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