Skip to content

AOT compilation crashes with "illegal text-relocations" on Intel (x86_64) macOS #866

Description

@burinc

Environment

  • macOS 26.5.1 (Build 25F80), Intel x86_64 (i7-9750H)
  • jank main @ fea82dbeef712b6c4ee46e9c28fdabfc4956f9bd
  • LLVM/Clang: Homebrew llvm 22.1.8 (keg-only, /usr/local/opt/llvm)
  • Built per compiler+runtime/doc/build.md "Release" recipe, with
    SDKROOT, PATH, LDFLAGS, CPPFLAGS pointed at the Homebrew LLVM
    install (Intel Homebrew prefix is /usr/local, not /opt/homebrew)

Summary

On Intel macOS, jank's AOT compilation path fails at link time with
ld: Found illegal text-relocations, referencing symbols from
__GLOBAL__sub_I_incr_module_* (the incrementally JIT-compiled core
module init code). Forcing a non-PIE link (-Wl,-no_pie) avoids the
link error but the resulting binary crashes on startup (SIGBUS, before
any output) with no further diagnostics.

Regular JIT execution (jank run, interactive eval) works correctly.
Only the AOT path (jank compile, and check-health's internal AOT
self-test) is affected.

Steps to reproduce

  1. Fresh clone + git submodule update --init --recursive --jobs 8.
  2. brew install entr double-conversion boost llvm (curl/git/etc.
    already present via Xcode CLT).
  3. export SDKROOT=$(xcrun --sdk macosx --show-sdk-path)
    export PATH="/usr/local/opt/llvm/bin:${PATH}"
    export LDFLAGS="-L/usr/local/opt/llvm/lib"
    export CPPFLAGS="-I/usr/local/opt/llvm/include"
    export CC=clang CXX=clang++
    cd compiler+runtime
    ./bin/configure -GNinja -DCMAKE_BUILD_TYPE=Release
    ./bin/compile
  4. export JANK_EXTRA_FLAGS="-L/usr/local/lib"   # see note below
    ./build/jank check-health

Actual result

  text-relocation in '__GLOBAL__sub_I_incr_module_4'+0x5A (.../health.o) to '___cxx_global_var_init.7'
  ... (several more, same pattern)
ld: Found illegal text-relocations
error: Clang failed with errors.error:  linker command failed with exit code 1
─ ❌ jank cannot aot compile working binaries

Forcing JANK_EXTRA_FLAGS="-L/usr/local/lib -Wl,-no_pie" makes the
link succeed, but running the produced binary directly (also
reproduced with a minimal standalone -main program compiled via
jank compile) crashes immediately:

$ ./target/a.out
[no output]
$ echo $?
138   # SIGBUS

What was ruled out

  • Not the Homebrew prefix mismatch (separate, smaller bug — see
    below): reproduces identically even after supplying the correct
    -L for Intel Homebrew.
  • Not a missing -fPIC on a third-party static lib: reconfigured
    with -DCMAKE_POSITION_INDEPENDENT_CODE=ON globally and did a full
    rebuild. Identical failure, same symbol pattern
    (__GLOBAL__sub_I_incr_module_*). This points at the incremental
    JIT/CppInterOp compilation pipeline itself emitting non-PIC-relocatable
    object code (fine for in-process JIT execution, since it doesn't need
    ASLR-safe relocations there) that then gets reused/relinked into the
    final AOT executable, which macOS's linker rejects for a PIE target.

Secondary bug found along the way

src/cpp/jank/aot/processor.cpp unconditionally hardcodes

if constexpr (jtl::current_platform == jtl::platform::macos_like)
{
  compiler_args.push_back(strdup("-L/opt/homebrew/lib"));
}

This assumes the Apple Silicon Homebrew prefix. On Intel macOS,
Homebrew lives at /usr/local, so this never resolves -lzstd
(and would presumably miss any other Homebrew-provided AOT link
dependency) unless the user manually passes
JANK_EXTRA_FLAGS="-L/usr/local/lib". Should probably resolve the
Homebrew prefix dynamically (e.g. via brew --prefix at configure
time, or checking both /opt/homebrew/lib and /usr/local/lib).

Related issues

Searched open + closed issues for "text-relocation", "illegal
text-relocation", "SIGBUS", "relocation model", "incr_module",
"non-PIC", "no_pie", "PIE macOS", "AOT macOS/Intel/x86_64" before
filing. No existing issue reports this exact failure. Two issues are
relevant context, not duplicates:

  • Homebrew package is only for aarch64, not x86 #645 "Homebrew package is only for aarch64, not x86" (open,
    help wanted). Different symptom (the published Homebrew bottle is
    arm64-only, so jank won't even run — bad CPU type in executable), but the maintainer's reply confirms the underlying
    gap: "we only have aarch64 binaries right now... I'm not familiar
    with how to get both added... but we definitely want to do that."

    Independent confirmation that Intel macOS isn't part of jank's
    tested/shipped matrix today.
  • Fix AOT builds on Nix #515 "Fix AOT builds on Nix" (closed, apparently without landing
    a fix on main). Different root cause (the clang::Driver CLI-arg
    translation and JANK_DEPS_LIBRARY_DIRS misbehave under Nix's
    compiler wrapper), but the same shape of problem: AOT compilation
    breaking on a platform/toolchain combination outside the primary
    macOS-arm64 / Linux-x86_64 CI matrix. Read together with Homebrew package is only for aarch64, not x86 #645, this
    suggests AOT-on-non-primary-platform is a recurring soft spot.

Also checked and ruled out as unrelated: #504 (Bad CppInterOp
codegen — a cpp/raw template/JIT-eval crash, not AOT/linking), #582
(ODR violation for duplicate cpp/raw definitions during AOT), #632
(AOT not passing user -l flags to clang, fixed by PR #631), #379
(dylib rpath resolution for external libs, closed as not-a-jank-bug).

Question

Is x86_64 macOS an actively tested/supported target for AOT
compilation? If so, any pointers on where in the incremental
compilation pipeline (CppInterOp / Cling-derived) the relocation
model would need to be forced to PIC for AOT-reused object code?
Happy to test patches — this reproduces reliably on a real Intel Mac.

Context

Found this while trying to build jank-engine, a small jank+OpenGL
game engine (private repo), which is itself produced via this exact
AOT pipeline. It currently cannot be built on Intel macOS with a
locally-built jank; JIT-only usage (jank run, jank repl) is
unaffected.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions