@@ -2063,8 +2063,8 @@ fn add_post_link_args(cmd: &mut dyn Linker, sess: &Session, flavor: LinkerFlavor
20632063/// linker, and since they never participate in the linking, using `KEEP` in the linker scripts 
20642064/// can't keep them either. This causes #47384. 
20652065/// 
2066- /// To keep them around, we could use `--whole-archive`  and equivalents to force rlib to  
2067- /// participate in linking like object files, but this proves to be expensive (#93791). Therefore 
2066+ /// To keep them around, we could use `--whole-archive`, `-force_load`  and equivalents to force rlib 
2067+ /// to  participate in linking like object files, but this proves to be expensive (#93791). Therefore 
20682068/// we instead just introduce an undefined reference to them. This could be done by `-u` command 
20692069/// line option to the linker or `EXTERN(...)` in linker scripts, however they does not only 
20702070/// introduce an undefined reference, but also make them the GC roots, preventing `--gc-sections` 
@@ -2106,8 +2106,20 @@ fn add_linked_symbol_object(
21062106        file. set_mangling ( object:: write:: Mangling :: None ) ; 
21072107    } 
21082108
2109+     // ld64 requires a relocation to load undefined symbols, see below. 
2110+     // Not strictly needed if linking with lld, but might as well do it there too. 
2111+     let  ld64_section_helper = if  file. format ( )  == object:: BinaryFormat :: MachO  { 
2112+         Some ( file. add_section ( 
2113+             file. segment_name ( object:: write:: StandardSegment :: Data ) . to_vec ( ) , 
2114+             "__data" . into ( ) , 
2115+             object:: SectionKind :: Data , 
2116+         ) ) 
2117+     }  else  { 
2118+         None 
2119+     } ; 
2120+ 
21092121    for  ( sym,  kind)  in  symbols. iter ( )  { 
2110-         file. add_symbol ( object:: write:: Symbol  { 
2122+         let  symbol =  file. add_symbol ( object:: write:: Symbol  { 
21112123            name :  sym. clone ( ) . into ( ) , 
21122124            value :  0 , 
21132125            size :  0 , 
@@ -2121,6 +2133,47 @@ fn add_linked_symbol_object(
21212133            section :  object:: write:: SymbolSection :: Undefined , 
21222134            flags :  object:: SymbolFlags :: None , 
21232135        } ) ; 
2136+ 
2137+         // The linker shipped with Apple's Xcode, ld64, works a bit differently from other linkers. 
2138+         // 
2139+         // Code-wise, the relevant parts of ld64 are roughly: 
2140+         // 1. Find the `ArchiveLoadMode` based on commandline options, default to `parseObjects`. 
2141+         //    https://github.com/apple-oss-distributions/ld64/blob/ld64-954.16/src/ld/Options.cpp#L924-L932 
2142+         //    https://github.com/apple-oss-distributions/ld64/blob/ld64-954.16/src/ld/Options.h#L55 
2143+         // 
2144+         // 2. Read the archive table of contents (__.SYMDEF file). 
2145+         //    https://github.com/apple-oss-distributions/ld64/blob/ld64-954.16/src/ld/parsers/archive_file.cpp#L294-L325 
2146+         // 
2147+         // 3. Begin linking by loading "atoms" from input files. 
2148+         //    https://github.com/apple-oss-distributions/ld64/blob/ld64-954.16/doc/design/linker.html 
2149+         //    https://github.com/apple-oss-distributions/ld64/blob/ld64-954.16/src/ld/InputFiles.cpp#L1349 
2150+         // 
2151+         //   a. Directly specified object files (`.o`) are parsed immediately. 
2152+         //      https://github.com/apple-oss-distributions/ld64/blob/ld64-954.16/src/ld/parsers/macho_relocatable_file.cpp#L4611-L4627 
2153+         // 
2154+         //     - Undefined symbols are not atoms (`n_value > 0` denotes a common symbol). 
2155+         //       https://github.com/apple-oss-distributions/ld64/blob/ld64-954.16/src/ld/parsers/macho_relocatable_file.cpp#L2455-L2468 
2156+         //       https://maskray.me/blog/2022-02-06-all-about-common-symbols 
2157+         // 
2158+         //     - Relocations/fixups are atoms. 
2159+         //       https://github.com/apple-oss-distributions/ld64/blob/ce6341ae966b3451aa54eeb049f2be865afbd578/src/ld/parsers/macho_relocatable_file.cpp#L2088-L2114 
2160+         // 
2161+         //   b. Archives are not parsed yet. 
2162+         //      https://github.com/apple-oss-distributions/ld64/blob/ld64-954.16/src/ld/parsers/archive_file.cpp#L467-L577 
2163+         // 
2164+         // 4. When a symbol is needed by an atom, parse the object file that contains the symbol. 
2165+         //    https://github.com/apple-oss-distributions/ld64/blob/ld64-954.16/src/ld/InputFiles.cpp#L1417-L1491 
2166+         //    https://github.com/apple-oss-distributions/ld64/blob/ld64-954.16/src/ld/parsers/archive_file.cpp#L579-L597 
2167+         // 
2168+         // All of the steps above are fairly similar to other linkers, except that **it completely 
2169+         // ignores undefined symbols**. 
2170+         // 
2171+         // So to make this trick work on ld64, we need to do something else to load the relevant 
2172+         // object files. We do this by inserting a relocation (fixup) for each symbol. 
2173+         if  let  Some ( section)  = ld64_section_helper { 
2174+             apple:: add_data_and_relocation ( & mut  file,  section,  symbol,  & sess. target ,  * kind) 
2175+                 . expect ( "failed adding relocation" ) ; 
2176+         } 
21242177    } 
21252178
21262179    let  path = tmpdir. join ( "symbols.o" ) ; 
0 commit comments