Skip to content

Stripping debuginfo on macOS produces misaligned dylibs #157750

Description

@goranmoomin

Bug

When building a dylib / cdylib / proc-macro crate with -C strip=debuginfo and a deployment target that enables chained fixups (i.e. MACOSX_DEPLOYMENT_TARGET >= 12.0, e.g. 27.0), rustc produces a dylib whose LC_SYMTAB.stroff (the LINKEDIT string pool) is not 8-byte aligned. dyld on macOS 27 rejects such images, so the resulting dylib fails to load with the mis-aligned LINKEDIT string pool error.

(Edit: see below for a more minimal reproduction that does not require chained fixups nor MACOSX_DEPLOYMENT_TARGET.)

This can be reproduced by the following cdylib crate:

src/lib.rs:

#[unsafe(no_mangle)]
pub extern "C" fn answer() -> usize {
    "hello from a static string".len()
}

Cargo.toml:

[package]
name = "cargo_cdylib_linkedit_repro"
version = "0.1.0"
edition = "2024"

[lib]
crate-type = ["cdylib"]

[profile.dev]
strip = "debuginfo"
$ MACOSX_DEPLOYMENT_TARGET=12.0 cargo build
    Finished `dev` profile [unoptimized + debuginfo] target(s) in 0.04s
$ cat main.c
#include <dlfcn.h>
#include <stdio.h>
#include <stdlib.h>

typedef size_t (*answer_fn)(void);

int main(int argc, char **argv) {
    const char *path = argc > 1 ? argv[1] : "target/debug/libcargo_cdylib_linkedit_repro.dylib";
    void *handle = dlopen(path, RTLD_NOW);
    if (!handle) {
        fprintf(stderr, "dlopen failed: %s\n", dlerror());
        return 1;
    }

    dlerror();
    answer_fn answer = (answer_fn)dlsym(handle, "answer");
    const char *err = dlerror();
    if (err) {
        fprintf(stderr, "dlsym failed: %s\n", err);
        return 2;
    }

    printf("answer() = %zu\n", answer());
    dlclose(handle);
    return 0;
}
$ cc -o dlopen-test main.c
$ ./dlopen-test
dlopen failed: dlopen(target/debug/libcargo_cdylib_linkedit_repro.dylib, 0x0002): tried: 'target/debug/libcargo_cdylib_linkedit_repro.dylib' (mis-aligned LINKEDIT string pool, fileOffset=0x0004B90C), '/System/Volumes/Preboot/Cryptexes/OStarget/debug/libcargo_cdylib_linkedit_repro.dylib' (no such file), '/usr/lib/target/debug/libcargo_cdylib_linkedit_repro.dylib' (no such file, not in dyld cache), 'target/debug/libcargo_cdylib_linkedit_repro.dylib' (mis-aligned LINKEDIT string pool, fileOffset=0x0004B90C), '/Users/sungbin/Developer/Personal/cargo-cdylib-linkedit-repro/target/debug/libcargo_cdylib_linkedit_repro.dylib' (mis-aligned LINKEDIT string pool, fileOffset=0x0004B90C), '/System/Volumes/Preboot/Cryptexes/OS/Users/sungbin/Developer/Personal/cargo-cdylib-linkedit-repro/target/debug/libcargo_cdylib_linkedit_repro.dylib' (no such file), '/Users/sungbin/Developer/Personal/cargo-cdylib-linkedit-repro/target/debug/libcargo_cdylib_linkedit_repro.dylib' (mis-aligned LINKEDIT string pool, fileOffset=0x0004B90C)
$ cargo clean
     Removed 21 files, 809.3KiB total
$ MACOSX_DEPLOYMENT_TARGET=11.0 cargo build
   Compiling cargo_cdylib_linkedit_repro v0.1.0 (/Users/sungbin/Developer/Personal/cargo-cdylib-linkedit-repro)
    Finished `dev` profile [unoptimized + debuginfo] target(s) in 0.15s
$ ./dlopen-test
answer() = 26
$ cargo clean
     Removed 21 files, 809.9KiB total
$ vi Cargo.toml
$ cat Cargo.toml
[package]
name = "cargo_cdylib_linkedit_repro"
version = "0.1.0"
edition = "2024"

[lib]
crate-type = ["cdylib"]

[profile.dev]
# strip = "debuginfo"
$ MACOSX_DEPLOYMENT_TARGET=12.0 cargo build
   Compiling cargo_cdylib_linkedit_repro v0.1.0 (/Users/sungbin/Developer/Personal/cargo-cdylib-linkedit-repro)
    Finished [`dev` profile [unoptimized + debuginfo]](https://doc.rust-lang.org/cargo/reference/profiles.html#default-profiles) target(s) in 0.52s
$ ./dlopen-test
answer() = 26

More details on how the dylib is not aligned can be seen in the reproduction script and the results.

Context

The context for this bug report here is that I installed macOS 27 Beta on my machine, and building rust via MacPorts started to fail. It surfaced as failing to import proc macros (i.e. can't find crate for clap_derive) when building the bootstrap.

Apparently, cargo builds proc macros as dylibs with -C strip=debuginfo set and triggers the above bug. MacPorts sets MACOSX_DEPLOYMENT_TARGET to the current version of macOS (so 27.0), and it seems that macOS 27 started to validate dylibs more strictly, hence the new error.

I've done some research on whether this is a llvm-objcopy bug or a macOS bug, and while I am not sure macOS will keep the new strict behavior, it seems that both ld64 and lld-macho does align the section to pointer size, while llvm-objcopy does not. Seems like it would be beneficial if this issue be fixed regardless of whether macOS relaxes this behavior not.

Below is a patch that I applied to rustc-1.96.0-src in order to succeed building a rustc that does not suffer from this bug. I will be reporting this bug to llvm/llvm-project as well.

--- src/llvm-project/llvm/lib/ObjCopy/MachO/MachOLayoutBuilder.cpp.orig
+++ src/llvm-project/llvm/lib/ObjCopy/MachO/MachOLayoutBuilder.cpp
@@ -280,6 +280,7 @@ Error MachOLayoutBuilder::layoutTail(uint64_t Offset) {
   uint64_t StartOfSymbols = updateOffset(NListSize * O.SymTable.Symbols.size());
   uint64_t StartOfIndirectSymbols =
       updateOffset(sizeof(uint32_t) * O.IndirectSymTable.Symbols.size());
+  Offset = alignTo(Offset, Is64Bit ? 8 : 4);
   uint64_t StartOfSymbolStrings = updateOffset(StrTableBuilder.getSize());
   uint64_t StartOfDylibCodeSignDRs = updateOffset(O.DylibCodeSignDRs.Data.size());

Meta

rustc --version --verbose:

rustc 1.96.0 (ac68faa20 2026-05-25)
binary: rustc
commit-hash: ac68faa20c58cbccd01ee7208bf3b6e93a7d7f96
commit-date: 2026-05-25
host: aarch64-apple-darwin
release: 1.96.0
LLVM version: 22.1.2

The bug seems to affect all recent rustc versions, I checked both 1.93.0 and 1.96.0.

Reproduction script and run results

For reproducing, I created the following script rust-linkedit-repro.sh:

#!/usr/bin/env bash
set -euo pipefail

MDT="${1:-${MACOSX_DEPLOYMENT_TARGET:-$(sw_vers -productVersion | cut -d. -f1).0}}"
RUSTC="${RUSTC:-$(rustup which rustc)}"
ROOT="${ROOT:-$PWD/linkedit-repro-${MDT}}"
mkdir -p "$ROOT"
cd "$ROOT"

cat > pm.rs <<'RS'
extern crate proc_macro;
use proc_macro::TokenStream;
#[proc_macro_derive(Foo)]
pub fn foo(_input: TokenStream) -> TokenStream { TokenStream::new() }
RS

cat > cdylib_simple.rs <<'RS'
#[no_mangle]
pub extern "C" fn answer() -> i32 { 42 }
RS

cat > cdylib_static_str.rs <<'RS'
#[no_mangle]
pub extern "C" fn answer() -> usize { "hello from a static string".len() }
RS

cat > cdylib_std_env.rs <<'RS'
#[no_mangle]
pub extern "C" fn answer() -> usize {
    std::env::var("PATH").unwrap_or_default().len()
}
RS

cat > main.rs <<'RS'
fn main() { println!("hello from executable"); }
RS

build() {
    local label="$1"; shift
    echo "--- building $label"
    MACOSX_DEPLOYMENT_TARGET="$MDT" "$RUSTC" "$@"
}

report_macho() {
    local label="$1" file="$2"
    echo
    echo "=== $label: $file"
    file "$file"
    /usr/bin/otool -l "$file" | awk '
        /cmd LC_DYLD/ { print "  " $0 }
        /cmd LC_BUILD_VERSION/ { b=1; next }
        b && /cmd / { b=0 }
        b && /(minos|sdk)/ { print "  " $0 }
        /cmd LC_SYMTAB/ { s=1; next }
        s && /cmd / { s=0 }
        s && /(symoff|nsyms|stroff|strsize)/ { print "  " $0 }
        /cmd LC_DYSYMTAB/ { d=1; next }
        d && /cmd / { d=0 }
        d && /(indirectsymoff|nindirectsyms)/ { print "  " $0 }
    '
    local stroff
    stroff=$(/usr/bin/otool -l "$file" | awk '/cmd LC_SYMTAB/{s=1;next} s&&/cmd /{s=0} s&&/stroff/{print $2}')
    if [ -n "$stroff" ]; then
        echo "  stroff % 8 = $((stroff % 8))"
        if [ $((stroff % 8)) -ne 0 ]; then
            echo "  LINKEDIT string pool is MISALIGNED for dyld's 8-byte check"
        else
            echo "  LINKEDIT string pool is aligned"
        fi
    fi
}

dlcheck() {
    local file="$1"
    python3 - "$file" <<'PY'
import ctypes, sys
p = sys.argv[1]
try:
    lib = ctypes.CDLL(p)
    msg = "  dlopen: OK"
    if hasattr(lib, "answer"):
        lib.answer.restype = ctypes.c_size_t
        msg += f" answer()={lib.answer()}"
    print(msg)
except OSError as e:
    print("  dlopen: FAIL")
    print("   ", e)
PY
}

# Build with Rust's problematic strip path.
build proc-macro --crate-name p --crate-type proc-macro pm.rs -C strip=debuginfo -o libpm.dylib
build cdylib-simple --crate-type cdylib cdylib_simple.rs -C strip=debuginfo -o libcdylib_simple.dylib
build cdylib-static-str --crate-type cdylib cdylib_static_str.rs -C strip=debuginfo -o libcdylib_static_str.dylib
build cdylib-std-env --crate-type cdylib cdylib_std_env.rs -C strip=debuginfo -o libcdylib_std_env.dylib
build executable main.rs -C strip=debuginfo -o app

report_macho proc-macro libpm.dylib
cat > use_pm.rs <<'RS'
extern crate p;
RS
if "$RUSTC" --crate-type lib use_pm.rs --extern p="$PWD/libpm.dylib" -o libuse_pm.rlib > proc_macro_load.log 2>&1; then
    echo "  rustc proc-macro load: OK"
else
    echo "  rustc proc-macro load: FAIL"
    sed -n '1,4p' proc_macro_load.log | sed 's/^/    /'
fi
dlcheck "$PWD/libpm.dylib"

report_macho cdylib-simple libcdylib_simple.dylib
dlcheck "$PWD/libcdylib_simple.dylib"

report_macho cdylib-static-str libcdylib_static_str.dylib
dlcheck "$PWD/libcdylib_static_str.dylib"

report_macho cdylib-std-env libcdylib_std_env.dylib
dlcheck "$PWD/libcdylib_std_env.dylib"

report_macho executable app
if ./app; then echo "  exec: OK"; else echo "  exec: FAIL"; fi

echo
echo "Repro dir: $PWD"
echo "Rustc: $($RUSTC -Vv | tr '\n' '; ')"
echo "MACOSX_DEPLOYMENT_TARGET=$MDT"

Running this script with MACOSX_DEPLOYMENT_TARGET set to 27.0, 11.0, 26.0, and 12.0 in respective order:

$ ./rust-linkedit-repro.sh 27.0
--- building proc-macro
--- building cdylib-simple
--- building cdylib-static-str
--- building cdylib-std-env
--- building executable

=== proc-macro: libpm.dylib
libpm.dylib: Mach-O 64-bit dynamically linked shared library arm64
        cmd LC_DYLD_CHAINED_FIXUPS
        cmd LC_DYLD_EXPORTS_TRIE
    symoff 330040
     nsyms 936
    stroff 345476
   strsize 86168
   indirectsymoff 345016
    nindirectsyms 115
      minos 27.0
        sdk 27.0
  stroff % 8 = 4
  LINKEDIT string pool is MISALIGNED for dyld's 8-byte check
  rustc proc-macro load: FAIL
    error: /Users/sungbin/linkedit-repro-27.0/libpm.dylib: dlopen(/Users/sungbin/linkedit-repro-27.0/libpm.dylib, 0x0005): tried: '/Users/sungbin/linkedit-repro-27.0/libpm.dylib' (mis-aligned LINKEDIT string pool, fileOffset=0x00054584), '/System/Volumes/Preboot/Cryptexes/OS/Users/sungbin/linkedit-repro-27.0/libpm.dylib' (no such file), '/Users/sungbin/linkedit-repro-27.0/libpm.dylib' (mis-aligned LINKEDIT string pool, fileOffset=0x00054584)
     --> use_pm.rs:1:1
      |
    1 | extern crate p;
  dlopen: FAIL
    dlopen(/Users/sungbin/linkedit-repro-27.0/libpm.dylib, 0x0006): tried: '/Users/sungbin/linkedit-repro-27.0/libpm.dylib' (mis-aligned LINKEDIT string pool, fileOffset=0x00054584), '/System/Volumes/Preboot/Cryptexes/OS/Users/sungbin/linkedit-repro-27.0/libpm.dylib' (no such file), '/Users/sungbin/linkedit-repro-27.0/libpm.dylib' (mis-aligned LINKEDIT string pool, fileOffset=0x00054584)

=== cdylib-simple: libcdylib_simple.dylib
libcdylib_simple.dylib: Mach-O 64-bit dynamically linked shared library arm64
        cmd LC_DYLD_CHAINED_FIXUPS
        cmd LC_DYLD_EXPORTS_TRIE
    symoff 16464
     nsyms 1
    stroff 16480
   strsize 16
   indirectsymoff 0
    nindirectsyms 0
      minos 27.0
        sdk 27.0
  stroff % 8 = 0
  LINKEDIT string pool is aligned
  dlopen: OK answer()=42

=== cdylib-static-str: libcdylib_static_str.dylib
libcdylib_static_str.dylib: Mach-O 64-bit dynamically linked shared library arm64
        cmd LC_DYLD_CHAINED_FIXUPS
        cmd LC_DYLD_EXPORTS_TRIE
    symoff 296976
     nsyms 756
    stroff 309516
   strsize 71176
   indirectsymoff 309072
    nindirectsyms 111
      minos 27.0
        sdk 27.0
  stroff % 8 = 4
  LINKEDIT string pool is MISALIGNED for dyld's 8-byte check
  dlopen: FAIL
    dlopen(/Users/sungbin/linkedit-repro-27.0/libcdylib_static_str.dylib, 0x0006): tried: '/Users/sungbin/linkedit-repro-27.0/libcdylib_static_str.dylib' (mis-aligned LINKEDIT string pool, fileOffset=0x0004B90C), '/System/Volumes/Preboot/Cryptexes/OS/Users/sungbin/linkedit-repro-27.0/libcdylib_static_str.dylib' (no such file), '/Users/sungbin/linkedit-repro-27.0/libcdylib_static_str.dylib' (mis-aligned LINKEDIT string pool, fileOffset=0x0004B90C)

=== cdylib-std-env: libcdylib_std_env.dylib
libcdylib_std_env.dylib: Mach-O 64-bit dynamically linked shared library arm64
        cmd LC_DYLD_CHAINED_FIXUPS
        cmd LC_DYLD_EXPORTS_TRIE
    symoff 297000
     nsyms 775
    stroff 309844
   strsize 72464
   indirectsymoff 309400
    nindirectsyms 111
      minos 27.0
        sdk 27.0
  stroff % 8 = 4
  LINKEDIT string pool is MISALIGNED for dyld's 8-byte check
  dlopen: FAIL
    dlopen(/Users/sungbin/linkedit-repro-27.0/libcdylib_std_env.dylib, 0x0006): tried: '/Users/sungbin/linkedit-repro-27.0/libcdylib_std_env.dylib' (mis-aligned LINKEDIT string pool, fileOffset=0x0004BA54), '/System/Volumes/Preboot/Cryptexes/OS/Users/sungbin/linkedit-repro-27.0/libcdylib_std_env.dylib' (no such file), '/Users/sungbin/linkedit-repro-27.0/libcdylib_std_env.dylib' (mis-aligned LINKEDIT string pool, fileOffset=0x0004BA54)

=== executable: app
app: Mach-O 64-bit executable arm64
        cmd LC_DYLD_CHAINED_FIXUPS
        cmd LC_DYLD_EXPORTS_TRIE
    symoff 335648
     nsyms 841
    stroff 349652
   strsize 78096
   indirectsymoff 349104
    nindirectsyms 137
      minos 27.0
        sdk 27.0
  stroff % 8 = 4
  LINKEDIT string pool is MISALIGNED for dyld's 8-byte check
hello from executable
  exec: OK

Repro dir: /Users/sungbin/linkedit-repro-27.0
Rustc: rustc 1.96.0 (ac68faa20 2026-05-25);binary: rustc;commit-hash: ac68faa20c58cbccd01ee7208bf3b6e93a7d7f96;commit-date: 2026-05-25;host: aarch64-apple-darwin;release: 1.96.0;LLVM version: 22.1.2;
MACOSX_DEPLOYMENT_TARGET=27.0
$ ./rust-linkedit-repro.sh 11.0
--- building proc-macro
--- building cdylib-simple
--- building cdylib-static-str
--- building cdylib-std-env
--- building executable

=== proc-macro: libpm.dylib
libpm.dylib: Mach-O 64-bit dynamically linked shared library arm64
              cmd LC_DYLD_INFO_ONLY
    symoff 330336
     nsyms 938
    stroff 345808
   strsize 86200
   indirectsymoff 345344
    nindirectsyms 116
      minos 11.0
        sdk 27.0
  stroff % 8 = 0
  LINKEDIT string pool is aligned
  rustc proc-macro load: OK
  dlopen: OK

=== cdylib-simple: libcdylib_simple.dylib
libcdylib_simple.dylib: Mach-O 64-bit dynamically linked shared library arm64
              cmd LC_DYLD_INFO_ONLY
    symoff 16416
     nsyms 1
    stroff 16432
   strsize 16
   indirectsymoff 0
    nindirectsyms 0
      minos 11.0
        sdk 27.0
  stroff % 8 = 0
  LINKEDIT string pool is aligned
  dlopen: OK answer()=42

=== cdylib-static-str: libcdylib_static_str.dylib
libcdylib_static_str.dylib: Mach-O 64-bit dynamically linked shared library arm64
              cmd LC_DYLD_INFO_ONLY
    symoff 297208
     nsyms 758
    stroff 309784
   strsize 71208
   indirectsymoff 309336
    nindirectsyms 112
      minos 11.0
        sdk 27.0
  stroff % 8 = 0
  LINKEDIT string pool is aligned
  dlopen: OK answer()=26

=== cdylib-std-env: libcdylib_std_env.dylib
libcdylib_std_env.dylib: Mach-O 64-bit dynamically linked shared library arm64
              cmd LC_DYLD_INFO_ONLY
    symoff 297232
     nsyms 777
    stroff 310112
   strsize 72496
   indirectsymoff 309664
    nindirectsyms 112
      minos 11.0
        sdk 27.0
  stroff % 8 = 0
  LINKEDIT string pool is aligned
  dlopen: OK answer()=572

=== executable: app
app: Mach-O 64-bit executable arm64
              cmd LC_DYLD_INFO_ONLY
    symoff 335936
     nsyms 843
    stroff 349976
   strsize 78128
   indirectsymoff 349424
    nindirectsyms 138
      minos 11.0
        sdk 27.0
  stroff % 8 = 0
  LINKEDIT string pool is aligned
hello from executable
  exec: OK

Repro dir: /Users/sungbin/linkedit-repro-11.0
Rustc: rustc 1.96.0 (ac68faa20 2026-05-25);binary: rustc;commit-hash: ac68faa20c58cbccd01ee7208bf3b6e93a7d7f96;commit-date: 2026-05-25;host: aarch64-apple-darwin;release: 1.96.0;LLVM version: 22.1.2;
MACOSX_DEPLOYMENT_TARGET=11.0
$ ./rust-linkedit-repro.sh 26.0
--- building proc-macro
--- building cdylib-simple
--- building cdylib-static-str
--- building cdylib-std-env
--- building executable

=== proc-macro: libpm.dylib
libpm.dylib: Mach-O 64-bit dynamically linked shared library arm64
        cmd LC_DYLD_CHAINED_FIXUPS
        cmd LC_DYLD_EXPORTS_TRIE
    symoff 330040
     nsyms 936
    stroff 345476
   strsize 86168
   indirectsymoff 345016
    nindirectsyms 115
      minos 26.0
        sdk 27.0
  stroff % 8 = 4
  LINKEDIT string pool is MISALIGNED for dyld's 8-byte check
  rustc proc-macro load: FAIL
    error: /Users/sungbin/linkedit-repro-26.0/libpm.dylib: dlopen(/Users/sungbin/linkedit-repro-26.0/libpm.dylib, 0x0005): tried: '/Users/sungbin/linkedit-repro-26.0/libpm.dylib' (mis-aligned LINKEDIT string pool, fileOffset=0x00054584), '/System/Volumes/Preboot/Cryptexes/OS/Users/sungbin/linkedit-repro-26.0/libpm.dylib' (no such file), '/Users/sungbin/linkedit-repro-26.0/libpm.dylib' (mis-aligned LINKEDIT string pool, fileOffset=0x00054584)
     --> use_pm.rs:1:1
      |
    1 | extern crate p;
  dlopen: FAIL
    dlopen(/Users/sungbin/linkedit-repro-26.0/libpm.dylib, 0x0006): tried: '/Users/sungbin/linkedit-repro-26.0/libpm.dylib' (mis-aligned LINKEDIT string pool, fileOffset=0x00054584), '/System/Volumes/Preboot/Cryptexes/OS/Users/sungbin/linkedit-repro-26.0/libpm.dylib' (no such file), '/Users/sungbin/linkedit-repro-26.0/libpm.dylib' (mis-aligned LINKEDIT string pool, fileOffset=0x00054584)

=== cdylib-simple: libcdylib_simple.dylib
libcdylib_simple.dylib: Mach-O 64-bit dynamically linked shared library arm64
        cmd LC_DYLD_CHAINED_FIXUPS
        cmd LC_DYLD_EXPORTS_TRIE
    symoff 16464
     nsyms 1
    stroff 16480
   strsize 16
   indirectsymoff 0
    nindirectsyms 0
      minos 26.0
        sdk 27.0
  stroff % 8 = 0
  LINKEDIT string pool is aligned
  dlopen: OK answer()=42

=== cdylib-static-str: libcdylib_static_str.dylib
libcdylib_static_str.dylib: Mach-O 64-bit dynamically linked shared library arm64
        cmd LC_DYLD_CHAINED_FIXUPS
        cmd LC_DYLD_EXPORTS_TRIE
    symoff 296976
     nsyms 756
    stroff 309516
   strsize 71176
   indirectsymoff 309072
    nindirectsyms 111
      minos 26.0
        sdk 27.0
  stroff % 8 = 4
  LINKEDIT string pool is MISALIGNED for dyld's 8-byte check
  dlopen: FAIL
    dlopen(/Users/sungbin/linkedit-repro-26.0/libcdylib_static_str.dylib, 0x0006): tried: '/Users/sungbin/linkedit-repro-26.0/libcdylib_static_str.dylib' (mis-aligned LINKEDIT string pool, fileOffset=0x0004B90C), '/System/Volumes/Preboot/Cryptexes/OS/Users/sungbin/linkedit-repro-26.0/libcdylib_static_str.dylib' (no such file), '/Users/sungbin/linkedit-repro-26.0/libcdylib_static_str.dylib' (mis-aligned LINKEDIT string pool, fileOffset=0x0004B90C)

=== cdylib-std-env: libcdylib_std_env.dylib
libcdylib_std_env.dylib: Mach-O 64-bit dynamically linked shared library arm64
        cmd LC_DYLD_CHAINED_FIXUPS
        cmd LC_DYLD_EXPORTS_TRIE
    symoff 297000
     nsyms 775
    stroff 309844
   strsize 72464
   indirectsymoff 309400
    nindirectsyms 111
      minos 26.0
        sdk 27.0
  stroff % 8 = 4
  LINKEDIT string pool is MISALIGNED for dyld's 8-byte check
  dlopen: FAIL
    dlopen(/Users/sungbin/linkedit-repro-26.0/libcdylib_std_env.dylib, 0x0006): tried: '/Users/sungbin/linkedit-repro-26.0/libcdylib_std_env.dylib' (mis-aligned LINKEDIT string pool, fileOffset=0x0004BA54), '/System/Volumes/Preboot/Cryptexes/OS/Users/sungbin/linkedit-repro-26.0/libcdylib_std_env.dylib' (no such file), '/Users/sungbin/linkedit-repro-26.0/libcdylib_std_env.dylib' (mis-aligned LINKEDIT string pool, fileOffset=0x0004BA54)

=== executable: app
app: Mach-O 64-bit executable arm64
        cmd LC_DYLD_CHAINED_FIXUPS
        cmd LC_DYLD_EXPORTS_TRIE
    symoff 335648
     nsyms 841
    stroff 349652
   strsize 78096
   indirectsymoff 349104
    nindirectsyms 137
      minos 26.0
        sdk 27.0
  stroff % 8 = 4
  LINKEDIT string pool is MISALIGNED for dyld's 8-byte check
hello from executable
  exec: OK

Repro dir: /Users/sungbin/linkedit-repro-26.0
Rustc: rustc 1.96.0 (ac68faa20 2026-05-25);binary: rustc;commit-hash: ac68faa20c58cbccd01ee7208bf3b6e93a7d7f96;commit-date: 2026-05-25;host: aarch64-apple-darwin;release: 1.96.0;LLVM version: 22.1.2;
MACOSX_DEPLOYMENT_TARGET=26.0
$ ./rust-linkedit-repro.sh 12.0
--- building proc-macro
--- building cdylib-simple
--- building cdylib-static-str
--- building cdylib-std-env
--- building executable

=== proc-macro: libpm.dylib
libpm.dylib: Mach-O 64-bit dynamically linked shared library arm64
        cmd LC_DYLD_CHAINED_FIXUPS
        cmd LC_DYLD_EXPORTS_TRIE
    symoff 330040
     nsyms 936
    stroff 345476
   strsize 86168
   indirectsymoff 345016
    nindirectsyms 115
      minos 12.0
        sdk 27.0
  stroff % 8 = 4
  LINKEDIT string pool is MISALIGNED for dyld's 8-byte check
  rustc proc-macro load: FAIL
    error: /Users/sungbin/linkedit-repro-12.0/libpm.dylib: dlopen(/Users/sungbin/linkedit-repro-12.0/libpm.dylib, 0x0005): tried: '/Users/sungbin/linkedit-repro-12.0/libpm.dylib' (mis-aligned LINKEDIT string pool, fileOffset=0x00054584), '/System/Volumes/Preboot/Cryptexes/OS/Users/sungbin/linkedit-repro-12.0/libpm.dylib' (no such file), '/Users/sungbin/linkedit-repro-12.0/libpm.dylib' (mis-aligned LINKEDIT string pool, fileOffset=0x00054584)
     --> use_pm.rs:1:1
      |
    1 | extern crate p;
  dlopen: FAIL
    dlopen(/Users/sungbin/linkedit-repro-12.0/libpm.dylib, 0x0006): tried: '/Users/sungbin/linkedit-repro-12.0/libpm.dylib' (mis-aligned LINKEDIT string pool, fileOffset=0x00054584), '/System/Volumes/Preboot/Cryptexes/OS/Users/sungbin/linkedit-repro-12.0/libpm.dylib' (no such file), '/Users/sungbin/linkedit-repro-12.0/libpm.dylib' (mis-aligned LINKEDIT string pool, fileOffset=0x00054584)

=== cdylib-simple: libcdylib_simple.dylib
libcdylib_simple.dylib: Mach-O 64-bit dynamically linked shared library arm64
        cmd LC_DYLD_CHAINED_FIXUPS
        cmd LC_DYLD_EXPORTS_TRIE
    symoff 16464
     nsyms 1
    stroff 16480
   strsize 16
   indirectsymoff 0
    nindirectsyms 0
      minos 12.0
        sdk 27.0
  stroff % 8 = 0
  LINKEDIT string pool is aligned
  dlopen: OK answer()=42

=== cdylib-static-str: libcdylib_static_str.dylib
libcdylib_static_str.dylib: Mach-O 64-bit dynamically linked shared library arm64
        cmd LC_DYLD_CHAINED_FIXUPS
        cmd LC_DYLD_EXPORTS_TRIE
    symoff 296976
     nsyms 756
    stroff 309516
   strsize 71176
   indirectsymoff 309072
    nindirectsyms 111
      minos 12.0
        sdk 27.0
  stroff % 8 = 4
  LINKEDIT string pool is MISALIGNED for dyld's 8-byte check
  dlopen: FAIL
    dlopen(/Users/sungbin/linkedit-repro-12.0/libcdylib_static_str.dylib, 0x0006): tried: '/Users/sungbin/linkedit-repro-12.0/libcdylib_static_str.dylib' (mis-aligned LINKEDIT string pool, fileOffset=0x0004B90C), '/System/Volumes/Preboot/Cryptexes/OS/Users/sungbin/linkedit-repro-12.0/libcdylib_static_str.dylib' (no such file), '/Users/sungbin/linkedit-repro-12.0/libcdylib_static_str.dylib' (mis-aligned LINKEDIT string pool, fileOffset=0x0004B90C)

=== cdylib-std-env: libcdylib_std_env.dylib
libcdylib_std_env.dylib: Mach-O 64-bit dynamically linked shared library arm64
        cmd LC_DYLD_CHAINED_FIXUPS
        cmd LC_DYLD_EXPORTS_TRIE
    symoff 297000
     nsyms 775
    stroff 309844
   strsize 72464
   indirectsymoff 309400
    nindirectsyms 111
      minos 12.0
        sdk 27.0
  stroff % 8 = 4
  LINKEDIT string pool is MISALIGNED for dyld's 8-byte check
  dlopen: FAIL
    dlopen(/Users/sungbin/linkedit-repro-12.0/libcdylib_std_env.dylib, 0x0006): tried: '/Users/sungbin/linkedit-repro-12.0/libcdylib_std_env.dylib' (mis-aligned LINKEDIT string pool, fileOffset=0x0004BA54), '/System/Volumes/Preboot/Cryptexes/OS/Users/sungbin/linkedit-repro-12.0/libcdylib_std_env.dylib' (no such file), '/Users/sungbin/linkedit-repro-12.0/libcdylib_std_env.dylib' (mis-aligned LINKEDIT string pool, fileOffset=0x0004BA54)

=== executable: app
app: Mach-O 64-bit executable arm64
        cmd LC_DYLD_CHAINED_FIXUPS
        cmd LC_DYLD_EXPORTS_TRIE
    symoff 335648
     nsyms 841
    stroff 349652
   strsize 78096
   indirectsymoff 349104
    nindirectsyms 137
      minos 12.0
        sdk 27.0
  stroff % 8 = 4
  LINKEDIT string pool is MISALIGNED for dyld's 8-byte check
hello from executable
  exec: OK

Repro dir: /Users/sungbin/linkedit-repro-12.0
Rustc: rustc 1.96.0 (ac68faa20 2026-05-25);binary: rustc;commit-hash: ac68faa20c58cbccd01ee7208bf3b6e93a7d7f96;commit-date: 2026-05-25;host: aarch64-apple-darwin;release: 1.96.0;LLVM version: 22.1.2;
MACOSX_DEPLOYMENT_TARGET=12.0

This is run on a macOS 27.0 machine.

I have also verified that running the same script with 26.0, 12.0, and 11.0 on a macOS 26.5 virtual machine succeeds.

Disclosure: I have used LLMs in first encountering and researching the bug. However I have personally verified the bug myself, checked that every single part of this bug report is true as far as my knoweldge goes, did the research on the ld64/lld behavior, and wrote every single part of the bug report myself.

Metadata

Metadata

Assignees

No one assigned

    Labels

    A-LLVMArea: Code generation parts specific to LLVM. Both correctness bugs and optimization-related issues.A-linkageArea: linking into static, shared libraries and binariesC-bugCategory: This is a bug.O-appleOperating system: Apple / Darwin (macOS, iOS, tvOS, visionOS, watchOS)O-macosOperating system: macOSS-has-mcveStatus: A Minimal Complete and Verifiable Example has been found for this issueT-compilerRelevant to the compiler team, which will review and decide on the PR/issue.

    Type

    No type

    Fields

    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions