@@ -2063,8 +2063,8 @@ fn add_post_link_args(cmd: &mut dyn Linker, sess: &Session, flavor: LinkerFlavor
2063
2063
/// linker, and since they never participate in the linking, using `KEEP` in the linker scripts
2064
2064
/// can't keep them either. This causes #47384.
2065
2065
///
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
2068
2068
/// we instead just introduce an undefined reference to them. This could be done by `-u` command
2069
2069
/// line option to the linker or `EXTERN(...)` in linker scripts, however they does not only
2070
2070
/// introduce an undefined reference, but also make them the GC roots, preventing `--gc-sections`
@@ -2106,8 +2106,20 @@ fn add_linked_symbol_object(
2106
2106
file. set_mangling ( object:: write:: Mangling :: None ) ;
2107
2107
}
2108
2108
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
+
2109
2121
for ( sym, kind) in symbols. iter ( ) {
2110
- file. add_symbol ( object:: write:: Symbol {
2122
+ let symbol = file. add_symbol ( object:: write:: Symbol {
2111
2123
name : sym. clone ( ) . into ( ) ,
2112
2124
value : 0 ,
2113
2125
size : 0 ,
@@ -2121,6 +2133,47 @@ fn add_linked_symbol_object(
2121
2133
section : object:: write:: SymbolSection :: Undefined ,
2122
2134
flags : object:: SymbolFlags :: None ,
2123
2135
} ) ;
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
+ }
2124
2177
}
2125
2178
2126
2179
let path = tmpdir. join ( "symbols.o" ) ;
0 commit comments