about summary refs log tree commit diff
diff options
context:
space:
mode:
authorMatthew Maurer <matthew.r.maurer@gmail.com>2020-04-16 19:40:11 -0700
committerMatthew Maurer <matthew.r.maurer@gmail.com>2020-04-29 13:38:59 -0700
commit0e7d5be4b808bd7ccb1d45aa8f7e5026a15aee93 (patch)
treef96a66037263baa82b0267d9f450eb09c1799a4f
parent825cf51ad7d2578fcd60a0b7b107d7b0ab3017ff (diff)
downloadrust-0e7d5be4b808bd7ccb1d45aa8f7e5026a15aee93.tar.gz
rust-0e7d5be4b808bd7ccb1d45aa8f7e5026a15aee93.zip
Use .init_array rather than .ctors
LLVM TargetMachines default to using the (now-legacy) .ctors
representation of init functions. Mixing .ctors and .init_array
representations can cause issues when linking with lld.

This happens in practice for:

* Our profiling runtime which is currently implicitly built with
  .init_array since it is built by clang, which sets this field.
* External C/C++ code that may be linked into the same process.

To support legacy systems which may use .ctors, targets may now specify
that they use .ctors via the use_ctors attribute which defaults to
false.

For debugging and manual control, -Z use-ctors-section=yes/no will allow
manual override.

Fixes: #71233
-rw-r--r--src/librustc_codegen_llvm/back/write.rs8
-rw-r--r--src/librustc_codegen_llvm/llvm/ffi.rs1
-rw-r--r--src/librustc_interface/tests.rs1
-rw-r--r--src/librustc_session/options.rs2
-rw-r--r--src/librustc_target/spec/mod.rs7
-rw-r--r--src/librustc_target/spec/netbsd_base.rs1
-rw-r--r--src/rustllvm/PassWrapper.cpp4
7 files changed, 23 insertions, 1 deletions
diff --git a/src/librustc_codegen_llvm/back/write.rs b/src/librustc_codegen_llvm/back/write.rs
index 3ec7ef831b5..6196993310e 100644
--- a/src/librustc_codegen_llvm/back/write.rs
+++ b/src/librustc_codegen_llvm/back/write.rs
@@ -166,6 +166,13 @@ pub fn target_machine_factory(
 
     let asm_comments = sess.asm_comments();
     let relax_elf_relocations = sess.target.target.options.relax_elf_relocations;
+
+    let use_init_array = !sess
+        .opts
+        .debugging_opts
+        .use_ctors_section
+        .unwrap_or(sess.target.target.options.use_ctors_section);
+
     Arc::new(move || {
         let tm = unsafe {
             llvm::LLVMRustCreateTargetMachine(
@@ -185,6 +192,7 @@ pub fn target_machine_factory(
                 asm_comments,
                 emit_stack_size_section,
                 relax_elf_relocations,
+                use_init_array,
             )
         };
 
diff --git a/src/librustc_codegen_llvm/llvm/ffi.rs b/src/librustc_codegen_llvm/llvm/ffi.rs
index fd03812cccd..53a7f718197 100644
--- a/src/librustc_codegen_llvm/llvm/ffi.rs
+++ b/src/librustc_codegen_llvm/llvm/ffi.rs
@@ -1956,6 +1956,7 @@ extern "C" {
         AsmComments: bool,
         EmitStackSizeSection: bool,
         RelaxELFRelocations: bool,
+        UseInitArray: bool,
     ) -> Option<&'static mut TargetMachine>;
     pub fn LLVMRustDisposeTargetMachine(T: &'static mut TargetMachine);
     pub fn LLVMRustAddBuilderLibraryInfo(
diff --git a/src/librustc_interface/tests.rs b/src/librustc_interface/tests.rs
index cee2e5b5bec..d041a05e25f 100644
--- a/src/librustc_interface/tests.rs
+++ b/src/librustc_interface/tests.rs
@@ -571,6 +571,7 @@ fn test_debugging_options_tracking_hash() {
     tracked!(tls_model, Some(TlsModel::GeneralDynamic));
     tracked!(treat_err_as_bug, Some(1));
     tracked!(unleash_the_miri_inside_of_you, true);
+    tracked!(use_ctors_section, Some(true));
     tracked!(verify_llvm_ir, true);
 }
 
diff --git a/src/librustc_session/options.rs b/src/librustc_session/options.rs
index 5b983d1105d..943f0cde010 100644
--- a/src/librustc_session/options.rs
+++ b/src/librustc_session/options.rs
@@ -1010,6 +1010,8 @@ options! {DebuggingOptions, DebuggingSetter, basic_debugging_options,
         `mir` (the MIR), or `mir-cfg` (graphviz formatted MIR)"),
     unstable_options: bool = (false, parse_bool, [UNTRACKED],
         "adds unstable command line options to rustc interface (default: no)"),
+    use_ctors_section: Option<bool> = (None, parse_opt_bool, [TRACKED],
+        "use legacy .ctors section for initializers rather than .init_array"),
     verbose: bool = (false, parse_bool, [UNTRACKED],
         "in general, enable more debug printouts (default: no)"),
     verify_llvm_ir: bool = (false, parse_bool, [TRACKED],
diff --git a/src/librustc_target/spec/mod.rs b/src/librustc_target/spec/mod.rs
index e853c07632f..579453cd7f8 100644
--- a/src/librustc_target/spec/mod.rs
+++ b/src/librustc_target/spec/mod.rs
@@ -878,6 +878,10 @@ pub struct TargetOptions {
 
     /// Additional arguments to pass to LLVM, similar to the `-C llvm-args` codegen option.
     pub llvm_args: Vec<String>,
+
+    /// Whether to use legacy .ctors initialization hooks rather than .init_array. Defaults
+    /// to false (uses .init_array).
+    pub use_ctors_section: bool,
 }
 
 impl Default for TargetOptions {
@@ -966,6 +970,7 @@ impl Default for TargetOptions {
             llvm_abiname: "".to_string(),
             relax_elf_relocations: false,
             llvm_args: vec![],
+            use_ctors_section: false,
         }
     }
 }
@@ -1304,6 +1309,7 @@ impl Target {
         key!(llvm_abiname);
         key!(relax_elf_relocations, bool);
         key!(llvm_args, list);
+        key!(use_ctors_section, bool);
 
         if let Some(array) = obj.find("abi-blacklist").and_then(Json::as_array) {
             for name in array.iter().filter_map(|abi| abi.as_string()) {
@@ -1531,6 +1537,7 @@ impl ToJson for Target {
         target_option_val!(llvm_abiname);
         target_option_val!(relax_elf_relocations);
         target_option_val!(llvm_args);
+        target_option_val!(use_ctors_section);
 
         if default.abi_blacklist != self.options.abi_blacklist {
             d.insert(
diff --git a/src/librustc_target/spec/netbsd_base.rs b/src/librustc_target/spec/netbsd_base.rs
index 95c4749f9c7..988346af2d7 100644
--- a/src/librustc_target/spec/netbsd_base.rs
+++ b/src/librustc_target/spec/netbsd_base.rs
@@ -23,6 +23,7 @@ pub fn opts() -> TargetOptions {
         pre_link_args: args,
         position_independent_executables: true,
         relro_level: RelroLevel::Full,
+        use_ctors_section: true,
         ..Default::default()
     }
 }
diff --git a/src/rustllvm/PassWrapper.cpp b/src/rustllvm/PassWrapper.cpp
index e31dd77d8af..0acedc25db8 100644
--- a/src/rustllvm/PassWrapper.cpp
+++ b/src/rustllvm/PassWrapper.cpp
@@ -445,7 +445,8 @@ extern "C" LLVMTargetMachineRef LLVMRustCreateTargetMachine(
     bool Singlethread,
     bool AsmComments,
     bool EmitStackSizeSection,
-    bool RelaxELFRelocations) {
+    bool RelaxELFRelocations,
+    bool UseInitArray) {
 
   auto OptLevel = fromRust(RustOptLevel);
   auto RM = fromRust(RustReloc);
@@ -471,6 +472,7 @@ extern "C" LLVMTargetMachineRef LLVMRustCreateTargetMachine(
   Options.MCOptions.PreserveAsmComments = AsmComments;
   Options.MCOptions.ABIName = ABIStr;
   Options.RelaxELFRelocations = RelaxELFRelocations;
+  Options.UseInitArray = UseInitArray;
 
   if (TrapUnreachable) {
     // Tell LLVM to codegen `unreachable` into an explicit trap instruction.