Skip to content

Commit

Permalink
Use .init_array rather than .ctors
Browse files Browse the repository at this point in the history
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
  • Loading branch information
maurer committed Apr 29, 2020
1 parent 825cf51 commit 0e7d5be
Show file tree
Hide file tree
Showing 7 changed files with 23 additions and 1 deletion.
8 changes: 8 additions & 0 deletions src/librustc_codegen_llvm/back/write.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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(
Expand All @@ -185,6 +192,7 @@ pub fn target_machine_factory(
asm_comments,
emit_stack_size_section,
relax_elf_relocations,
use_init_array,
)
};

Expand Down
1 change: 1 addition & 0 deletions src/librustc_codegen_llvm/llvm/ffi.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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(
Expand Down
1 change: 1 addition & 0 deletions src/librustc_interface/tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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);
}

Expand Down
2 changes: 2 additions & 0 deletions src/librustc_session/options.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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],
Expand Down
7 changes: 7 additions & 0 deletions src/librustc_target/spec/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand Down Expand Up @@ -966,6 +970,7 @@ impl Default for TargetOptions {
llvm_abiname: "".to_string(),
relax_elf_relocations: false,
llvm_args: vec![],
use_ctors_section: false,
}
}
}
Expand Down Expand Up @@ -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()) {
Expand Down Expand Up @@ -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(
Expand Down
1 change: 1 addition & 0 deletions src/librustc_target/spec/netbsd_base.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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()
}
}
4 changes: 3 additions & 1 deletion src/rustllvm/PassWrapper.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand All @@ -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.
Expand Down

0 comments on commit 0e7d5be

Please sign in to comment.