You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
ld64 crashing while Native AOT compiling Microsoft MCP for .NET 10 #119380
Yep. Already reported this one to Apple as FB18561897 on July 2 and there was no reply so far. The only known workaround is to use ld-classic (<_UseClassicLinker>true</_UseClassicLinker> for netX-macos projects or manually injecting the -ld_classic linker option). Affects all Xcode 16+ versions that I could test.
Unfortunately the source code is not available. The condition is hit only for bigger object files and I think it's specifically happening based on number of symbols (or rather the total size of symbol names). The old linker is open source and the handling of the same situation exists there. I don't remember the exact specifics but searching for hasLargeAddends/hasHugeAddends eventually leads to the code path.
Andy did mention FB18561897 and the Apple engineer looked at that object file.
The problem is that the object file has lots of relative relocations (pairs of ARM64_RELOC_SUBTRACTOR and ARM64_RELOC_UNSIGNED ) many of which are relative to the lsection2 symbol, ie., the start of the __DATA,.dotnet_eh_table section.
llvm-objdump --macho --reloc net10_azmcp.o > relocs.txt
Relocation information (__DATA,.dotnet_eh_table) 72890 entries
address pcrel length extern type scattered symbolnum/value
00886bd9 False long True SUB False lsection2
00886bd9 False long True UNSIGND False ___ehinfo_System_Linq_System_Linq_Enumerable__ToDictionary_6<System___Canon__System___Canon__System___Canon>
00886851 False long True SUB False lsection2
00886851 False long True UNSIGND False ___ehinfo_System_Security_Cryptography_System_Security_Cryptography_FixedMemoryKeyBox__UseKey<System___Canon__System___Canon>
008866c2 False long True SUB False lsection2
008866c2 False long True UNSIGND False ___ehinfo_System_Linq_System_Linq_Enumerable__ToDictionary_4<System___Canon__System___Canon>
00886596 False long True SUB False lsection2
00886596 False long True UNSIGND False ___ehinfo_System_Linq_System_Linq_Enumerable__Aggregate_0<System___Canon__System___Canon>
The contents stored at the address of these relocations (ie., the relocation addend) is quite large, combined with the overall size of the object file and the number of these large addends it ends up exceeding certain encoding limits. Is there a way you could avoid these large addends, maybe by referencing other base symbols? Or if not, can you elaborate on the use case behind it?
These are IMAGE_REL_BASED_RELPTR32 relocations pointing from LSDA data (associated data for code regions pointed from .eh_frame exception handling table) to EH info. They are created here. The objdump output tells only half of the story since it doesn't show the offset embedded in the code which is negative. In the example above, the offset in the code would be -0x00886bd9 for the first relocation (- address [+ addend] - section_start + symbol). While it does "overflow" in the calculation the result could only truly overflow if the distance between .dotnet_eh_table+00886bd9 and ___ehinfo_System_Linq_System_Linq_Enumerable__ToDictionary_6 is larger than (signed) 32-bit. I'm pretty sure that the resulting linked object from my example was not over 2GB big.
I will double check but I don't think there's any Mach-O format limitation that would limit any of those values to smaller size than 32-bit integer. Additionally, ld-classic links this just fine which would suggest that it either comes up with different layout, silently corrupts the output, or that it's not really a format issue. My suspicion is that they incorrectly flag the negative offset value in the code as a large positive value.
Yep, the questions were just a copy-paste from the Apple engineer. I think I'm going to ask if there is a better reloc kind in MachO we could use to achieve a 32bit relocation without running into the linker limits. The reloc to section start is just means to an end in the end.
I'd specifically ask if they correctly treat the offset as signed because the explanation has some holes. I'll check the input object files and linked output for my test case with the old linker, but it will have to wait until beginning of the next week.
I don't think it's related to JIT changes. This was happening for a long while, we had to switch to classic LD64 linker for our app ~10 months ago with .NET 9 at the time. On other projects I encountered this even earlier. The large offsets were either in the exception handling metadata or the ILC dehydrated data.
It is a bug in the new Apple linker and gradually switching to it only makes it show up more. I have a workaround for it - #124721. Unfortunately, Apple never really acknowledged the true nature of the issue, so it's hard to reason about the correctness of the workaround.
Any feedback would be appreciated on whether it helps with some scenario or not. I let Copilot try to binary search for the exact condition to hit the bug but I am not sure if it really worked well.
Any feedback would be appreciated on whether it helps with some scenario or not. I let Copilot try to binary search for the exact condition to hit the bug but I am not sure if it really worked well.
/Users/admin/.nuget/packages/linkerassert.machoaddendrewriter/1.0.4-beta-gd36cf9e2a0/buildTransitive/LinkerAssert.MachOAddendRewriter.targets(18,5): error LinkerAssert.MachOAddendRewriter could not find the packaged rewriter tool at '/Users/admin/.nuget/packages/linkerassert.machoaddendrewriter/1.0.4-beta-gd36cf9e2a0/tools/macho_addend_rewriter'.
I also submitted another Apple support request to request clarification on what has to be actually changed (as a workaround) or to reevaluate any fix on the Apple side.
This results in a large number of distant relocations that can't be encoded.
Unfortunately this statement lacks the explanation of why and where they can't be encoded. The information is never present in the output so this is either misunderstanding of the issue on Apple side or they refer to some of their internal encoding within the linker itself that is opaque to the caller.
You can avoid that issue by using .subsections_via_symbols directive and the relocation expressions .long bar - . has some labels like ltmp%d.
Using temporary labels is exactly what I use in my workaround (both in the PR #124721 and https://github.com/filipnavara/ld64addend). However, it is not clear when it is necessary to emit the labels. I based my guesses on heuristics and binary search to find the problematic boundaries. Emitting a label for every relocation is prohibitively expensive in terms of intermediate object file size. Essentially I use an upper boundary for the addend and every time it would cross this boundary I emit a label and base every successive relocation on this label (until it crosses another boundary). Without knowing the internals of the linker it's not clear whether this approach is sufficient and covers all the cases.
Ideally, the absolute value of the addend should fit within -/+ 1MB for the most efficient encoding. There’s no limit on the number of unique addend values, as long as they’re within this limit.
Given this information I think I can proceed with finalizing PR #124721 to implement the workaround. I'll be away for a long weekend but I will try to get back to it sometime next week.
Activity
dotnet-policy-service commentedon Sep 5, 2025
Tagging subscribers to this area: @agocke, @MichalStrehovsky, @jkotas
See info in area-owners.md if you want to be subscribed.
MichalStrehovsky commentedon Sep 5, 2025
@filipnavara you have seen lots of Apple linker crashes. Does this one look familiar to you?
filipnavara commentedon Sep 5, 2025
Yep. Already reported this one to Apple as FB18561897 on July 2 and there was no reply so far. The only known workaround is to use ld-classic (
<_UseClassicLinker>true</_UseClassicLinker>fornetX-macosprojects or manually injecting the-ld_classiclinker option). Affects all Xcode 16+ versions that I could test.MichalStrehovsky commentedon Sep 5, 2025
Thank you! Do you know if Apple makes the source code of this linker available? I had no luck finding the assertion message anywhere.
filipnavara commentedon Sep 5, 2025
Unfortunately the source code is not available. The condition is hit only for bigger object files and I think it's specifically happening based on number of symbols (or rather the total size of symbol names). The old linker is open source and the handling of the same situation exists there. I don't remember the exact specifics but searching for
hasLargeAddends/hasHugeAddendseventually leads to the code path.filipnavara commentedon Sep 5, 2025
Also, the assert message differs slighly based on an Xcode version:
ld: Assertion failed: (_addend < largeAddends.size()), function addend, file Fixup.cpp, line 1430.(Xcode 26 beta 2)ld: Assertion failed: (_addend == uniqueIndex && "too many large addends"), function setAddend, file Fixup.cpp, line 1445.(Xcode 26 beta 6)agocke commentedon Sep 5, 2025
Confirmed that
-ld_classicis a viable workaround. I think we should try to also open an issue with Apple on our side.filipnavara commentedon Sep 5, 2025
Please do mention FB18561897 if you do, I uploaded a full repro there. Unfortunately I cannot share it publicly.
MichalStrehovsky commentedon Sep 11, 2025
Andy did mention FB18561897 and the Apple engineer looked at that object file.
The problem is that the object file has lots of relative relocations (pairs of ARM64_RELOC_SUBTRACTOR and ARM64_RELOC_UNSIGNED ) many of which are relative to the lsection2 symbol, ie., the start of the __DATA,.dotnet_eh_table section.
The contents stored at the address of these relocations (ie., the relocation addend) is quite large, combined with the overall size of the object file and the number of these large addends it ends up exceeding certain encoding limits. Is there a way you could avoid these large addends, maybe by referencing other base symbols? Or if not, can you elaborate on the use case behind it?
filipnavara commentedon Sep 11, 2025
These are
IMAGE_REL_BASED_RELPTR32relocations pointing from LSDA data (associated data for code regions pointed from.eh_frameexception handling table) to EH info. They are created here. Theobjdumpoutput tells only half of the story since it doesn't show the offset embedded in the code which is negative. In the example above, the offset in the code would be-0x00886bd9for the first relocation (- address [+ addend] - section_start + symbol). While it does "overflow" in the calculation the result could only truly overflow if the distance between.dotnet_eh_table+00886bd9and___ehinfo_System_Linq_System_Linq_Enumerable__ToDictionary_6is larger than (signed) 32-bit. I'm pretty sure that the resulting linked object from my example was not over 2GB big.I will double check but I don't think there's any Mach-O format limitation that would limit any of those values to smaller size than 32-bit integer. Additionally, ld-classic links this just fine which would suggest that it either comes up with different layout, silently corrupts the output, or that it's not really a format issue. My suspicion is that they incorrectly flag the negative offset value in the code as a large positive value.
MichalStrehovsky commentedon Sep 11, 2025
Yep, the questions were just a copy-paste from the Apple engineer. I think I'm going to ask if there is a better reloc kind in MachO we could use to achieve a 32bit relocation without running into the linker limits. The reloc to section start is just means to an end in the end.
filipnavara commentedon Sep 11, 2025
I'd specifically ask if they correctly treat the offset as signed because the explanation has some holes. I'll check the input object files and linked output for my test case with the old linker, but it will have to wait until beginning of the next week.
9 remaining items
agocke commentedon Apr 13, 2026
@EgorBo Can you take a look at this? It seemed like this was downstream of the large addends used in the JIT-generated code.
filipnavara commentedon Apr 13, 2026
I don't think it's related to JIT changes. This was happening for a long while, we had to switch to classic LD64 linker for our app ~10 months ago with .NET 9 at the time. On other projects I encountered this even earlier. The large offsets were either in the exception handling metadata or the ILC dehydrated data.
It is a bug in the new Apple linker and gradually switching to it only makes it show up more. I have a workaround for it - #124721. Unfortunately, Apple never really acknowledged the true nature of the issue, so it's hard to reason about the correctness of the workaround.
filipnavara commentedon Apr 20, 2026
I am experimenting with a workaround that does the rewriting after
IlcCompileand before the files are handed over to the linker (https://github.com/filipnavara/ld64addend). You just need to get the NuGet, point your NuGet.config to a place where it can be found and reference it:Any feedback would be appreciated on whether it helps with some scenario or not. I let Copilot try to binary search for the exact condition to hit the bug but I am not sure if it really worked well.
DigitApps2 commentedon Apr 20, 2026
/Users/admin/.nuget/packages/linkerassert.machoaddendrewriter/1.0.4-beta-gd36cf9e2a0/buildTransitive/LinkerAssert.MachOAddendRewriter.targets(18,5): error LinkerAssert.MachOAddendRewriter could not find the packaged rewriter tool at '/Users/admin/.nuget/packages/linkerassert.machoaddendrewriter/1.0.4-beta-gd36cf9e2a0/tools/macho_addend_rewriter'.filipnavara commentedon Apr 20, 2026
That's weird. I am pretty sure the tool is in the package. There could be some signing issue though...
filipnavara commentedon Apr 21, 2026
@DigitApps2 I republished a fixed NuGet. There was an error in the packaging project that required
dotnet packto be run twice and obviously that was not happening on the GitHub Actions builder. Please report any further issues on the https://github.com/filipnavara/ld64addend repo to avoid spamming this issue.I also submitted another Apple support request to request clarification on what has to be actually changed (as a workaround) or to reevaluate any fix on the Apple side.
agocke commentedon Apr 21, 2026
Update from apple on the following
Apple:
filipnavara commentedon Apr 22, 2026
Unfortunately this statement lacks the explanation of why and where they can't be encoded. The information is never present in the output so this is either misunderstanding of the issue on Apple side or they refer to some of their internal encoding within the linker itself that is opaque to the caller.
Using temporary labels is exactly what I use in my workaround (both in the PR #124721 and https://github.com/filipnavara/ld64addend). However, it is not clear when it is necessary to emit the labels. I based my guesses on heuristics and binary search to find the problematic boundaries. Emitting a label for every relocation is prohibitively expensive in terms of intermediate object file size. Essentially I use an upper boundary for the addend and every time it would cross this boundary I emit a label and base every successive relocation on this label (until it crosses another boundary). Without knowing the internals of the linker it's not clear whether this approach is sufficient and covers all the cases.
filipnavara commentedon May 6, 2026
I got a response from Apple:
Given this information I think I can proceed with finalizing PR #124721 to implement the workaround. I'll be away for a long weekend but I will try to get back to it sometime next week.
Implement a workaround for ld-prime hitting an assert on large addends (
build: ship Native AOT on macOS by linking through LLVM lld
[release/10.0] Implement a workaround for ld-prime hitting an assert …