Skip to content

ld64 crashing while Native AOT compiling Microsoft MCP for .NET 10 #119380

Closed

Description

@agocke

We now have a test blocked on this issue. Search for issue number in the repo.

Unfortunately the object file is too big to upload here.

Assertion failed: (_addend == uniqueIndex && "too many large addends"), function setAddend, file Fixup.cpp, line 1445.
0  0x1006f552c  __assert_rtn + 252
1  0x1005db65c  ld::Fixup::setAddend(long long, std::__1::function<unsigned int (long long)>) + 352
2  0x100640f9c  ld::DynamicAtom::addFixup(ld::file_format::FixupKind, unsigned int, ld::Atom const*, ld::Atom const*, long long) + 368
3  0x1005e9190  ld::FixupFromRelocs::diff(relocation_info const&, relocation_info const&, long long) const + 252
4  0x100601f98  ld::InputFiles::SliceParser::parseObjectFile(mach_o::Header const*) const + 5960
5  0x10060d940  ld::InputFiles::SliceParser::parse() const + 696
6  0x100610c48  ld::InputFiles::parseAllFiles(void (ld::AtomFile const*) block_pointer)::$_0::operator()(unsigned long, ld::FileInfo const&) const + 516
7  0x193da9874  _dispatch_client_callout2 + 16
8  0x193da4610  _dispatch_apply_invoke3 + 336
9  0x193da985c  _dispatch_client_callout + 16
10  0x193d92a28  _dispatch_once_callout + 32
11  0x193da3750  _dispatch_apply_invoke + 252
12  0x193da985c  _dispatch_client_callout + 16
13  0x193dc6490  _dispatch_channel_invoke.cold.5 + 32
14  0x193da1fa4  _dispatch_root_queue_drain + 736
15  0x193da25d4  _dispatch_worker_thread2 + 156
16  0x193f43de4  _pthread_wqthread + 232

Repro:

On a mac, clone https://github.com/agocke/azure-mcp/tree/net10 and run $ dotnet publish -r osx-arm64 -p:BuildNative=true inside the servers/Azure.Mcp.Server/src directory.

Activity

  1. dotnet-policy-service commented on Sep 5, 2025

    @dotnet-policy-service
    Contributor

    Tagging subscribers to this area: @agocke, @MichalStrehovsky, @jkotas
    See info in area-owners.md if you want to be subscribed.

  2. MichalStrehovsky commented on Sep 5, 2025

    @MichalStrehovsky
    Member

    @filipnavara you have seen lots of Apple linker crashes. Does this one look familiar to you?

  3. filipnavara commented on Sep 5, 2025

    @filipnavara
    Member

    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.

  4. MichalStrehovsky commented on Sep 5, 2025

    @MichalStrehovsky
    Member

    Yep. Already reported this one to Apple as FB18561897 on July 2 and there was no reply so far

    Thank you! Do you know if Apple makes the source code of this linker available? I had no luck finding the assertion message anywhere.

  5. filipnavara commented on Sep 5, 2025

    @filipnavara
    Member

    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.

  6. filipnavara commented on Sep 5, 2025

    @filipnavara
    Member

    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)

  7. agocke commented on Sep 5, 2025

    @agocke
    MemberAuthor

    Confirmed that -ld_classic is a viable workaround. I think we should try to also open an issue with Apple on our side.

  8. filipnavara commented on Sep 5, 2025

    @filipnavara
    Member

    Confirmed that -ld_classic is a viable workaround. I think we should try to also open an issue with Apple on our side.

    Please do mention FB18561897 if you do, I uploaded a full repro there. Unfortunately I cannot share it publicly.

  9. MichalStrehovsky commented on Sep 11, 2025

    @MichalStrehovsky
    Member

    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?

  10. filipnavara commented on Sep 11, 2025

    @filipnavara
    Member

    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.

  11. MichalStrehovsky commented on Sep 11, 2025

    @MichalStrehovsky
    Member

    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.

  12. filipnavara commented on Sep 11, 2025

    @filipnavara
    Member

    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.

  13. 9 remaining items

  14. agocke commented on Apr 13, 2026

    @agocke
    MemberAuthor

    @EgorBo Can you take a look at this? It seemed like this was downstream of the large addends used in the JIT-generated code.

  15. filipnavara commented on Apr 13, 2026

    @filipnavara
    Member

    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.

  16. filipnavara commented on Apr 20, 2026

    @filipnavara
    Member

    I am experimenting with a workaround that does the rewriting after IlcCompile and 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:

    <ItemGroup>
      <PackageReference Include="LinkerAssert.MachOAddendRewriter" Version="1.0.4-beta-gd36cf9e2a0" />
    </ItemGroup>

    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.

  17. DigitApps2 commented on Apr 20, 2026

    @DigitApps2

    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'.

  18. filipnavara commented on Apr 20, 2026

    @filipnavara
    Member

    That's weird. I am pretty sure the tool is in the package. There could be some signing issue though...

  19. filipnavara commented on Apr 21, 2026

    @filipnavara
    Member

    @DigitApps2 I republished a fixed NuGet. There was an error in the packaging project that required dotnet pack to 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.

  20. agocke commented on Apr 21, 2026

    @agocke
    MemberAuthor

    Update from apple on the following

    For posterity, this is the minimal example where the linker will fail (compile with clang test.S -o test):

    .text
    .align 2
    .globl _main
    _main:
    mov x0, 0
    ret

    .section __TEXT,__bar
    bar:
    .rept 0x140002
    .long 0
    .endr

    .section __TEXT,__foo
    foo:
    .rept 0x40001
    .long 0
    .endr
    // ltmp0:
    .rept 0x140002 - 0x40001
    .long bar - .
    .endr

    Apple:

    This results in a large number of distant relocations that can't be encoded.

    You can avoid that issue by using .subsections_via_symbols directive and the relocation expressions .long bar - . has some labels like ltmp%d.

    Another option could be breaking down contents of that section into multiple .o files.

  21. filipnavara commented on Apr 22, 2026

    @filipnavara
    Member

    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.

  22. filipnavara commented on May 6, 2026

    @filipnavara
    Member

    I got a response from Apple:

    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.

  23. added a commit that references this issue on Jul 27, 2026
    3aa40d2
  24. locked and limited conversation to collaborators on Aug 27, 2026
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

    Type

    No type

    Projects

    • Status
      No status

    Milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions