-
Notifications
You must be signed in to change notification settings - Fork 12.8k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
linker: More systematic handling of CRT objects #71769
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -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)); | ||
} | ||
} | ||
|
||
|
@@ -1320,38 +1359,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") | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The only case of rustc interpreting user-provided raw linker arguments is removed here. |
||
{ | ||
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 { | ||
petrochenkov marked this conversation as resolved.
Show resolved
Hide resolved
|
||
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) { | ||
|
@@ -1417,6 +1424,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); | ||
|
@@ -1430,8 +1439,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 { | ||
|
@@ -1490,7 +1504,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); | ||
|
@@ -1520,12 +1543,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 | ||
|
@@ -1551,7 +1576,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); | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Am I missing something, or is this logic inverted from what it should be? If
crt_static()
returns true, aren't we only allowed to create aDynamicDylib
whencrt_static_allows_dylibs
is also true?There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This case is here for consistency, but we should never hit it right now because if
invalid_output_for_target
istrue
then we skip the crate type and never get to linking.But if we didn't skip it (like we don't skip PIC executables when
+crt-static
is enabled but not supported), then we would fall back fromStaticDylib
toDynamicDylib
.