diff options
| author | bors <bors@rust-lang.org> | 2020-05-20 05:47:10 +0000 |
|---|---|---|
| committer | bors <bors@rust-lang.org> | 2020-05-20 05:47:10 +0000 |
| commit | 64ad709ad4d2863b7995d8b9e90a1bedb7d0ccf1 (patch) | |
| tree | 72dbfc627b26a19d36533a927c38fc6b094abe92 /src/librustc_codegen_ssa | |
| parent | 692a26e8d727a79340937565cf77c573d3a2294f (diff) | |
| parent | 49eb35c05e8bff6197ed0ea7437e0c0fb03c62c5 (diff) | |
| download | rust-64ad709ad4d2863b7995d8b9e90a1bedb7d0ccf1.tar.gz rust-64ad709ad4d2863b7995d8b9e90a1bedb7d0ccf1.zip | |
Auto merge of #71769 - petrochenkov:crto, r=cuviper
linker: More systematic handling of CRT objects Document which kinds of `crt0.o`-like objects we link and in which cases, discovering bugs in process. `src/librustc_target/spec/crt_objects.rs` is the place to start reading from. This PR also automatically contains half of the `-static-pie` support (https://github.com/rust-lang/rust/pull/70740), because that's one of the six cases that we need to consider when linking CRT objects. This is a breaking change for custom target specifications that specify CRT objects. Closes https://github.com/rust-lang/rust/issues/30868
Diffstat (limited to 'src/librustc_codegen_ssa')
| -rw-r--r-- | src/librustc_codegen_ssa/back/link.rs | 147 | ||||
| -rw-r--r-- | src/librustc_codegen_ssa/back/linker.rs | 21 |
2 files changed, 106 insertions, 62 deletions
diff --git a/src/librustc_codegen_ssa/back/link.rs b/src/librustc_codegen_ssa/back/link.rs index ce158fb07da..d87b84f880a 100644 --- a/src/librustc_codegen_ssa/back/link.rs +++ b/src/librustc_codegen_ssa/back/link.rs @@ -11,7 +11,9 @@ use rustc_session::search_paths::PathKind; /// need out of the shared crate context before we get rid of it. use rustc_session::{filesearch, Session}; use rustc_span::symbol::Symbol; -use rustc_target::spec::{LinkerFlavor, LldFlavor, PanicStrategy, RelocModel, RelroLevel}; +use rustc_target::spec::crt_objects::CrtObjectsFallback; +use rustc_target::spec::{LinkOutputKind, LinkerFlavor, LldFlavor}; +use rustc_target::spec::{PanicStrategy, RelocModel, RelroLevel}; use super::archive::ArchiveBuilder; use super::command::Command; @@ -1130,33 +1132,70 @@ fn exec_linker( } } -/// Add begin object files defined by the target spec. -fn add_pre_link_objects(cmd: &mut dyn Linker, sess: &Session, crate_type: CrateType) { - let pre_link_objects = if crate_type == CrateType::Executable { - &sess.target.target.options.pre_link_objects_exe - } else { - &sess.target.target.options.pre_link_objects_dll +fn link_output_kind(sess: &Session, crate_type: CrateType) -> LinkOutputKind { + let kind = match (crate_type, sess.crt_static(Some(crate_type)), sess.relocation_model()) { + (CrateType::Executable, false, RelocModel::Pic) => LinkOutputKind::DynamicPicExe, + (CrateType::Executable, false, _) => LinkOutputKind::DynamicNoPicExe, + (CrateType::Executable, true, RelocModel::Pic) => LinkOutputKind::StaticPicExe, + (CrateType::Executable, true, _) => LinkOutputKind::StaticNoPicExe, + (_, true, _) => LinkOutputKind::StaticDylib, + (_, false, _) => LinkOutputKind::DynamicDylib, }; - for obj in pre_link_objects { - cmd.add_object(&get_object_file_path(sess, obj)); + + // Adjust the output kind to target capabilities. + let pic_exe_supported = sess.target.target.options.position_independent_executables; + let static_pic_exe_supported = false; // FIXME: Add this option to target specs. + let static_dylib_supported = sess.target.target.options.crt_static_allows_dylibs; + match kind { + LinkOutputKind::DynamicPicExe if !pic_exe_supported => LinkOutputKind::DynamicNoPicExe, + LinkOutputKind::StaticPicExe if !static_pic_exe_supported => LinkOutputKind::StaticNoPicExe, + LinkOutputKind::StaticDylib if !static_dylib_supported => LinkOutputKind::DynamicDylib, + _ => kind, } +} - if crate_type == CrateType::Executable && sess.crt_static(Some(crate_type)) { - for obj in &sess.target.target.options.pre_link_objects_exe_crt { - cmd.add_object(&get_object_file_path(sess, obj)); - } +/// Whether we link to our own CRT objects instead of relying on gcc to pull them. +/// We only provide such support for a very limited number of targets. +fn crt_objects_fallback(sess: &Session, crate_type: CrateType) -> bool { + match sess.target.target.options.crt_objects_fallback { + // FIXME: Find a better heuristic for "native musl toolchain is available", + // based on host and linker path, for example. + // (https://github.com/rust-lang/rust/pull/71769#issuecomment-626330237). + Some(CrtObjectsFallback::Musl) => sess.crt_static(Some(crate_type)), + // FIXME: Find some heuristic for "native mingw toolchain is available", + // likely based on `get_crt_libs_path` (https://github.com/rust-lang/rust/pull/67429). + Some(CrtObjectsFallback::Mingw) => sess.target.target.target_vendor != "uwp", + // FIXME: Figure out cases in which WASM needs to link with a native toolchain. + Some(CrtObjectsFallback::Wasm) => true, + None => false, } } -/// Add end object files defined by the target spec. -fn add_post_link_objects(cmd: &mut dyn Linker, sess: &Session, crate_type: CrateType) { - for obj in &sess.target.target.options.post_link_objects { +/// Add pre-link object files defined by the target spec. +fn add_pre_link_objects( + cmd: &mut dyn Linker, + sess: &Session, + link_output_kind: LinkOutputKind, + fallback: bool, +) { + let opts = &sess.target.target.options; + let objects = if fallback { &opts.pre_link_objects_fallback } else { &opts.pre_link_objects }; + for obj in objects.get(&link_output_kind).iter().copied().flatten() { cmd.add_object(&get_object_file_path(sess, obj)); } - if sess.crt_static(Some(crate_type)) { - for obj in &sess.target.target.options.post_link_objects_crt { - cmd.add_object(&get_object_file_path(sess, obj)); - } +} + +/// Add post-link object files defined by the target spec. +fn add_post_link_objects( + cmd: &mut dyn Linker, + sess: &Session, + link_output_kind: LinkOutputKind, + fallback: bool, +) { + let opts = &sess.target.target.options; + let objects = if fallback { &opts.post_link_objects_fallback } else { &opts.post_link_objects }; + for obj in objects.get(&link_output_kind).iter().copied().flatten() { + cmd.add_object(&get_object_file_path(sess, obj)); } } @@ -1342,38 +1381,6 @@ fn add_library_search_dirs(cmd: &mut dyn Linker, sess: &Session) { cmd.include_path(&fix_windows_verbatim_for_gcc(&lib_path)); } -/// Add options requesting executables to be position-independent or not position-independent. -fn add_position_independent_executable_args( - cmd: &mut dyn Linker, - sess: &Session, - flavor: LinkerFlavor, - crate_type: CrateType, - codegen_results: &CodegenResults, -) { - if crate_type != CrateType::Executable { - return; - } - - if sess.target.target.options.position_independent_executables { - let attr_link_args = &*codegen_results.crate_info.link_args; - let mut user_defined_link_args = sess.opts.cg.link_args.iter().chain(attr_link_args); - if sess.relocation_model() == RelocModel::Pic - && !sess.crt_static(Some(crate_type)) - && !user_defined_link_args.any(|x| x == "-static") - { - cmd.position_independent_executable(); - return; - } - } - - // Recent versions of gcc can be configured to generate position - // independent executables by default. We have to pass -no-pie to - // explicitly turn that off. Not applicable to ld. - if sess.target.target.options.linker_is_gnu && flavor != LinkerFlavor::Ld { - cmd.no_position_independent_executable(); - } -} - /// Add options making relocation sections in the produced ELF files read-only /// and suppressing lazy binding. fn add_relro_args(cmd: &mut dyn Linker, sess: &Session) { @@ -1439,6 +1446,8 @@ fn linker_with_args<'a, B: ArchiveBuilder<'a>>( // to the linker args construction. assert!(base_cmd.get_args().is_empty() || sess.target.target.target_vendor == "uwp"); let cmd = &mut *codegen_results.linker_info.to_linker(base_cmd, &sess, flavor, target_cpu); + let link_output_kind = link_output_kind(sess, crate_type); + let crt_objects_fallback = crt_objects_fallback(sess, crate_type); // NO-OPT-OUT, OBJECT-FILES-MAYBE, CUSTOMIZATION-POINT add_pre_link_args(cmd, sess, flavor, crate_type); @@ -1455,8 +1464,13 @@ fn linker_with_args<'a, B: ArchiveBuilder<'a>>( cmd.arg(format!("--dynamic-linker={}ld.so.1", prefix)); } + // NO-OPT-OUT, OBJECT-FILES-NO + if crt_objects_fallback { + cmd.no_crt_objects(); + } + // NO-OPT-OUT, OBJECT-FILES-YES - add_pre_link_objects(cmd, sess, crate_type); + add_pre_link_objects(cmd, sess, link_output_kind, crt_objects_fallback); // NO-OPT-OUT, OBJECT-FILES-NO, AUDIT-ORDER if sess.target.target.options.is_like_emscripten { @@ -1515,7 +1529,16 @@ fn linker_with_args<'a, B: ArchiveBuilder<'a>>( } // NO-OPT-OUT, OBJECT-FILES-NO, AUDIT-ORDER - add_position_independent_executable_args(cmd, sess, flavor, crate_type, codegen_results); + // FIXME: Support `StaticPicExe` correctly. + match link_output_kind { + LinkOutputKind::DynamicPicExe | LinkOutputKind::StaticPicExe => { + cmd.position_independent_executable() + } + LinkOutputKind::DynamicNoPicExe | LinkOutputKind::StaticNoPicExe => { + cmd.no_position_independent_executable() + } + _ => {} + } // OBJECT-FILES-NO, AUDIT-ORDER add_relro_args(cmd, sess); @@ -1545,12 +1568,14 @@ fn linker_with_args<'a, B: ArchiveBuilder<'a>>( ); // NO-OPT-OUT, OBJECT-FILES-NO, AUDIT-ORDER - // Tell the linker what we're doing. - if crate_type != CrateType::Executable { - cmd.build_dylib(out_filename); - } - if crate_type == CrateType::Executable && sess.crt_static(Some(crate_type)) { - cmd.build_static_executable(); + // FIXME: Merge with the previous `link_output_kind` match, + // and support `StaticPicExe` and `StaticDylib` correctly. + match link_output_kind { + LinkOutputKind::StaticNoPicExe | LinkOutputKind::StaticPicExe => { + cmd.build_static_executable() + } + LinkOutputKind::DynamicDylib | LinkOutputKind::StaticDylib => cmd.build_dylib(out_filename), + _ => {} } // OBJECT-FILES-NO, AUDIT-ORDER @@ -1576,7 +1601,7 @@ fn linker_with_args<'a, B: ArchiveBuilder<'a>>( add_late_link_args(cmd, sess, flavor, crate_type, codegen_results); // NO-OPT-OUT, OBJECT-FILES-YES - add_post_link_objects(cmd, sess, crate_type); + add_post_link_objects(cmd, sess, link_output_kind, crt_objects_fallback); // NO-OPT-OUT, OBJECT-FILES-MAYBE, CUSTOMIZATION-POINT add_post_link_args(cmd, sess, flavor); diff --git a/src/librustc_codegen_ssa/back/linker.rs b/src/librustc_codegen_ssa/back/linker.rs index 535c4ff092f..ee5bcf4b9f5 100644 --- a/src/librustc_codegen_ssa/back/linker.rs +++ b/src/librustc_codegen_ssa/back/linker.rs @@ -123,6 +123,7 @@ pub trait Linker { fn pgo_gen(&mut self); fn control_flow_guard(&mut self); fn debuginfo(&mut self, strip: Strip); + fn no_crt_objects(&mut self); fn no_default_libraries(&mut self); fn build_dylib(&mut self, out_filename: &Path); fn build_static_executable(&mut self); @@ -266,7 +267,9 @@ impl<'a> Linker for GccLinker<'a> { self.cmd.arg("-pie"); } fn no_position_independent_executable(&mut self) { - self.cmd.arg("-no-pie"); + if !self.is_ld { + self.cmd.arg("-no-pie"); + } } fn full_relro(&mut self) { self.linker_arg("-zrelro"); @@ -404,6 +407,12 @@ impl<'a> Linker for GccLinker<'a> { } } + fn no_crt_objects(&mut self) { + if !self.is_ld { + self.cmd.arg("-nostartfiles"); + } + } + fn no_default_libraries(&mut self) { if !self.is_ld { self.cmd.arg("-nodefaultlibs"); @@ -644,6 +653,10 @@ impl<'a> Linker for MsvcLinker<'a> { // noop } + fn no_crt_objects(&mut self) { + // noop + } + fn no_default_libraries(&mut self) { self.cmd.arg("/NODEFAULTLIB"); } @@ -907,6 +920,8 @@ impl<'a> Linker for EmLinker<'a> { }); } + fn no_crt_objects(&mut self) {} + fn no_default_libraries(&mut self) { self.cmd.args(&["-s", "DEFAULT_LIBRARY_FUNCS_TO_INCLUDE=[]"]); } @@ -1106,6 +1121,8 @@ impl<'a> Linker for WasmLd<'a> { self.sess.warn("Windows Control Flow Guard is not supported by this linker."); } + fn no_crt_objects(&mut self) {} + fn no_default_libraries(&mut self) {} fn build_dylib(&mut self, _out_filename: &Path) { @@ -1271,6 +1288,8 @@ impl<'a> Linker for PtxLinker<'a> { fn pgo_gen(&mut self) {} + fn no_crt_objects(&mut self) {} + fn no_default_libraries(&mut self) {} fn control_flow_guard(&mut self) { |
