Stop emitting the dso_local LLVM attribute for external symbols under the static relocation model on macOS. by pcwalton · Pull Request #88200 · rust-lang/rust (original) (raw)

This matches Clang's behavior:

https://github.com/llvm/llvm-project/blob/973cb2c326be9f256da0897c4d2ef117dc22761d/clang/lib/CodeGen/CodeGenModule.cpp#L1038-L1040

Even if dso_local were properly supported in this way on macOS, it seems
incorrect to add this annotation as liberally as we did. The dso_local
annotation is for symbols that ultimately end up in the same linkage unit, but
we were adding this annotation even for static values inside extern blocks
marked with #[link(type="framework")], which should be considered dynamically
linked. Note that Clang likewise avoids emitting dso_local for dllimport
symbols:

https://github.com/llvm/llvm-project/blob/973cb2c326be9f256da0897c4d2ef117dc22761d/clang/lib/CodeGen/CodeGenModule.cpp#L1005-L1007

This issue caused breakage in the ring crate, which links to a symbol defined
in Security.framework that ultimately resolves to address 0x0:

https://github.com/briansmith/ring/blob/b94d61e044b42827fefd71d5f61e8c58a7659870/src/rand.rs#L390

For this symbol, the use of dso_local causes LLVM to emit a relocation of
type X86_64_RELOC_SIGNED, which is a 32-bit signed PC-relative offset. If the
binary is large enough, 0x0 might be out of range, and the link will fail.
Avoiding dso_local causes LLVM to use the GOT instead, emitting a relocation
of type X86_64_RELOC_GOT_LOAD, which will properly handle the large offset
and cause the link to succeed.

As a side note, the static relocation model is effectively deprecated for
security reasons on macOS, as it prohibits PIE. It's also completely
unsupported on Apple Silicon, so I don't think it's worth going to the effort
of properly supporting this model on that platform.