Skip to content

[iOS] .NET 9.0.13 broke NativeAOT builds with classic linker when AesGcm is used #124609

@filipnavara

Description

@filipnavara

There's a Swift shim in libSystem.Security.Cryptography.Native.Apple.a. The build tools were likely upgraded between .NET 9.0.12 an .NET 9.0.13 which resulted in additional dependencies inside the Swift shim:

                 U __swift_FORCE_LOAD_$_swiftXPC
00000000000022d0 S __swift_FORCE_LOAD_$_swiftXPC_$_pal_swiftbindings
                 U __swift_FORCE_LOAD_$_swift_Builtin_float
00000000000022a8 S __swift_FORCE_LOAD_$_swift_Builtin_float_$_pal_swiftbindings
                 U __swift_FORCE_LOAD_$_swift_errno
0000000000002270 S __swift_FORCE_LOAD_$_swift_errno_$_pal_swiftbindings
                 U __swift_FORCE_LOAD_$_swift_math
00000000000022a0 S __swift_FORCE_LOAD_$_swift_math_$_pal_swiftbindings
                 U __swift_FORCE_LOAD_$_swift_signal
0000000000002278 S __swift_FORCE_LOAD_$_swift_signal_$_pal_swiftbindings
                 U __swift_FORCE_LOAD_$_swift_stdio
0000000000002298 S __swift_FORCE_LOAD_$_swift_stdio_$_pal_swiftbindings
                 U __swift_FORCE_LOAD_$_swift_time
0000000000002288 S __swift_FORCE_LOAD_$_swift_time_$_pal_swiftbindings
                 U __swift_FORCE_LOAD_$_swiftsys_time
0000000000002280 S __swift_FORCE_LOAD_$_swiftsys_time_$_pal_swiftbindings
                 U __swift_FORCE_LOAD_$_swiftunistd
0000000000002290 S __swift_FORCE_LOAD_$_swiftunistd_$_pal_swiftbindings

The new Apple linker has some logic to handle some backwards compatibility but that doesn't work with classic linker. The classic linker fails to compile the project now:

 /usr/local/share/dotnet/packs/Microsoft.iOS.Sdk.net9.0_26.0/26.0.9785/targets/Xamarin.Shared.Sdk.targets(1835,3): error : 
      clang++ exited with code 1:
      0  0x100d81788  __assert_rtn + 160
      1  0x100d84570  ld::tool::SymbolTableAtom<x86_64>::classicOrdinalForProxy(ld::Atom const*) (.cold.3) + 0
      2  0x100cbbdb0  ld::tool::SymbolTableAtom<x86_64>::classicOrdinalForProxy(ld::Atom const*) + 172
      3  0x100cbcc24  ld::tool::SymbolTableAtom<arm64>::addImport(ld::Atom const*, ld::tool::StringPoolAtom*) + 140
      4  0x100cbe508  ld::tool::SymbolTableAtom<arm64>::encode() + 396
      5  0x100cb03b0  ___ZN2ld4tool10OutputFile20buildLINKEDITContentERNS_8InternalE_block_invoke.413 + 36
      6  0x18814ca28  _dispatch_call_block_and_release + 32
      7  0x1881664b0  _dispatch_client_callout + 16
      8  0x188183d9c  _dispatch_channel_invoke.cold.9 + 76
      9  0x18815eadc  _dispatch_root_queue_drain + 708
      10  0x18815f120  _dispatch_worker_thread2 + 184
      11  0x188303e84  _pthread_wqthread + 232
      A linker snapshot was created at:
      	/tmp/AesGcmAppleNAOT-2026-02-19-191403.ld-snapshot
      ld: Assertion failed: (it != _dylibToOrdinal.end()), function dylibToOrdinal, file OutputFile.cpp, line 5196.

We cannot use the new linker due to #119380.

Minimal repro:
AesGcmAppleNAOT.zip - Run dotnet publish

The repro simply uses the AesGcm class which depends on the Swift shim. For simplicity, any code like this is sufficient to reference the class and the related shims:

using (var aes = new AesGcm(new byte[32], 16))
    aes.Encrypt([], [], [], [], []);

The project includes global.json which pins the SDK version to 9.0.311. Downgrading to 9.0.310 (9.0.12 runtime) makes the error go away.

Minimal supported platform version is set with <SupportedOSPlatformVersion>15.0</SupportedOSPlatformVersion>. Raising it to 18.0 also makes the problem go away because the OS deployed Swift version is new enough.

Finally, <_UseClassicLinker>true</_UseClassicLinker> (dotnet/macios workload) switch is used to force the usage of the old linker.

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    Status

    No status

    Status

    No status

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions