Linker nondeterminism (ld_new) involving branch islands

Hi, I'm investigating what looks like possibly nondeterministic behavior when linking large iOS app binaries. I do not have a concise reproduction of the issue yet, but am trying to hunt down possible leads. In particular, the problem appears to surface when invoking clang to link a binary and the resulting order of the 'branch island' instructions appears to be random each time the binary is linked (as shown by the link map output). I was wondering if anyone with insight into the linker's current implementation could shed light on whether that is expected, and if there is anything that can be done to prevent it. FWIW, it seems like it might be size-dependent as smaller app binaries don't appear to exhibit the same behavior. I'd be glad to share more specifics and hopefully a reproduction if I can ever find one eventually. Some environment info (Xcode 16.4 toolchain):

clang -v:

Apple clang version 17.0.0 (clang-1700.0.13.5)
Target: arm64-apple-darwin24.6.0
Thread model: posix
InstalledDir: /Applications/Xcode-16.4.0.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin

ld -v:

@(#)PROGRAM:ld PROJECT:ld-1167.5
BUILD 01:45:05 Apr 30 2025
configured to support archs: armv6 armv7 armv7s arm64 arm64e arm64_32 i386 x86_64 x86_64h armv6m armv7k armv7m armv7em
will use ld-classic for: armv6 armv7 armv7s i386 armv6m armv7k armv7m armv7em
LTO support using: LLVM version 17.0.0 (static support for 29, runtime is 29)
TAPI support using: Apple TAPI version 17.0.0 (tapi-1700.0.3.5)

Hello. On arm64 architecture branch islands are needed only if the total size of the executable code in a binary exceeds 128mb. How many islands will be effectively inserted depends on the exact code layout, and that'll also be a contributing factor to the potentially non-deterministic output. It is supposed to be deterministic, but it sounds like you might be hitting some edge cases.

It'd be great if you could file a feedback report with your sample, so that we could try to reproduce it. You can add a -debug_snapshot option (-Wl,-debug_snapshot in Xcode's other linker flags build setting) to create a minimal linker reproducer that'll be saved in a /tmp/*.ld-snapshot directory.

One note, in Xcode 26, we've made significant underlying changes to how linker snapshots are generated. There were cases where snapshots created by older ld versions weren't quite complete. So upgrading your toolchain might be helpful, but we can also try first with a snapshot from Xcode 16.4.

Unfortunately, I've been unable to figure out what is going wrong with the -debug_snapshot option, and also cannot submit the 'real' code that was hitting the issue. However, I have filed a feedback (FB20884404), and additionally put together a repo containing a synthetic reproduction of the issue which was consistently able to demonstrate the behavior in my dev environment: https://github.com/jamieQ/ld-branch-island-nondeterminism

Linker nondeterminism (ld_new) involving branch islands
 
 
Q