]> git.lizzy.rs Git - rust.git/commitdiff
Only compile #[used] as llvm.compiler.used for ELF targets
authorThom Chiovoloni <chiovolonit@gmail.com>
Sun, 6 Feb 2022 21:51:11 +0000 (13:51 -0800)
committerThom Chiovoloni <chiovolonit@gmail.com>
Wed, 11 May 2022 08:29:56 +0000 (01:29 -0700)
compiler/rustc_codegen_llvm/src/consts.rs
compiler/rustc_codegen_ssa/src/traits/statics.rs

index 4d3f3f318b80c7aa8d884ec9b93e1a686f9eb02e..98b412f9397e97fb6da31322c2ab6bfda4ff951b 100644 (file)
@@ -535,11 +535,41 @@ fn codegen_static(&self, def_id: DefId, is_mutable: bool) {
 
                 // The semantics of #[used] in Rust only require the symbol to make it into the
                 // object file. It is explicitly allowed for the linker to strip the symbol if it
-                // is dead. As such, use llvm.compiler.used instead of llvm.used.
+                // is dead, which means we are allowed use `llvm.compiler.used` instead of
+                // `llvm.used` here.
+                //
                 // Additionally, https://reviews.llvm.org/D97448 in LLVM 13 started emitting unique
                 // sections with SHF_GNU_RETAIN flag for llvm.used symbols, which may trigger bugs
-                // in some versions of the gold linker.
-                self.add_compiler_used_global(g);
+                // in the handling of `.init_array` (the static constructor list) in versions of
+                // the gold linker (prior to the one released with binutils 2.36).
+                //
+                // However, unconditional use of `llvm.compiler.used` caused a nontrivial amount of
+                // ecosystem breakage, especially on Mach-O targets. To resolve this, we compile it
+                // as llvm.used on ELF targets and llvm.compiler.used elsewhere, which and should be
+                // equivalent to how we compiled `#[used]` before LLVM 13, as `llvm.used` and
+                // `llvm.compiler.used` were treated the same on ELF targets prior in earlier LLVM
+                // versions (additionally, it seems to be how Clang handles `__attribute__((used))`,
+                // perhaps for similar compatibility-motivated reasons).
+                //
+                // See https://github.com/rust-lang/rust/issues/47384#issuecomment-1019080146 and
+                // following comments for some discussion of this.
+                //
+                // The final wrinkle is it's not really clear how to tell if we're going to output
+                // ELF, so it's been approximated as "not like wasm, osx, or windows", which is
+                // not exactly correct, but is pretty close and hopefully handles all the platforms
+                // platforms where old versions of `ld.gold` are likely to show up.
+                //
+                // All this is subject to change in the future. Which is a good thing, because this
+                // probably should be firmed up somehow!
+                let seems_like_elf = !(self.tcx.sess.target.is_like_osx
+                    || self.tcx.sess.target.is_like_windows
+                    || self.tcx.sess.target.is_like_wasm);
+
+                if seems_like_elf {
+                    self.add_compiler_used_global(g);
+                } else {
+                    self.add_used_global(g);
+                }
             }
             if attrs.flags.contains(CodegenFnAttrFlags::USED_LINKER) {
                 // `USED` and `USED_LINKER` can't be used together.
index a2a3cb56c78062f34196314999482f66e5f1a4b4..413d31bb94293db88ca40e7f84af41f3d7f56829 100644 (file)
@@ -13,7 +13,9 @@ pub trait StaticMethods: BackendTypes {
     /// Same as add_used_global(), but only prevent the compiler from potentially removing an
     /// otherwise unused symbol. The linker is still permitted to drop it.
     ///
-    /// This corresponds to the semantics of the `#[used]` attribute.
+    /// This corresponds to the documented semantics of the `#[used]` attribute, although
+    /// on some targets (non-ELF), we may use `add_used_global` for `#[used]` statics
+    /// instead.
     fn add_compiler_used_global(&self, global: Self::Value);
 }