mirror of
https://github.com/rust-lang/rust.git
synced 2024-11-26 08:44:35 +00:00
linker: More systematic handling of CRT objects
This commit is contained in:
parent
23ffeea307
commit
49eb35c05e
@ -125,15 +125,16 @@ fn copy_third_party_objects(
|
||||
target_deps.push(target);
|
||||
};
|
||||
|
||||
// Copies the crt(1,i,n).o startup objects
|
||||
// Copies the CRT objects.
|
||||
//
|
||||
// Since musl supports fully static linking, we can cross link for it even
|
||||
// with a glibc-targeting toolchain, given we have the appropriate startup
|
||||
// files. As those shipped with glibc won't work, copy the ones provided by
|
||||
// musl so we have them on linux-gnu hosts.
|
||||
// rustc historically provides a more self-contained installation for musl targets
|
||||
// not requiring the presence of a native musl toolchain. For example, it can fall back
|
||||
// to using gcc from a glibc-targeting toolchain for linking.
|
||||
// To do that we have to distribute musl startup objects as a part of Rust toolchain
|
||||
// and link with them manually in the self-contained mode.
|
||||
if target.contains("musl") {
|
||||
let srcdir = builder.musl_root(target).unwrap().join("lib");
|
||||
for &obj in &["crt1.o", "crti.o", "crtn.o"] {
|
||||
for &obj in &["crt1.o", "Scrt1.o", "rcrt1.o", "crti.o", "crtn.o"] {
|
||||
copy_and_stamp(&srcdir, obj);
|
||||
}
|
||||
} else if target.ends_with("-wasi") {
|
||||
|
@ -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));
|
||||
}
|
||||
|
||||
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));
|
||||
}
|
||||
// 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,
|
||||
}
|
||||
}
|
||||
|
||||
/// 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 {
|
||||
/// 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 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")
|
||||
{
|
||||
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) {
|
||||
@ -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);
|
||||
|
@ -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) {
|
||||
|
145
src/librustc_target/spec/crt_objects.rs
Normal file
145
src/librustc_target/spec/crt_objects.rs
Normal file
@ -0,0 +1,145 @@
|
||||
//! Object files providing support for basic runtime facilities and added to the produced binaries
|
||||
//! at the start and at the end of linking.
|
||||
//!
|
||||
//! Table of CRT objects for popular toolchains.
|
||||
//! The `crtx` ones are generally distributed with libc and the `begin/end` ones with gcc.
|
||||
//! See https://dev.gentoo.org/~vapier/crt.txt for some more details.
|
||||
//!
|
||||
//! | Pre-link CRT objects | glibc | musl | bionic | mingw | wasi |
|
||||
//! |----------------------|------------------------|------------------------|------------------|-------------------|------|
|
||||
//! | dynamic-nopic-exe | crt1, crti, crtbegin | crt1, crti, crtbegin | crtbegin_dynamic | crt2, crtbegin | crt1 |
|
||||
//! | dynamic-pic-exe | Scrt1, crti, crtbeginS | Scrt1, crti, crtbeginS | crtbegin_dynamic | crt2, crtbegin | crt1 |
|
||||
//! | static-nopic-exe | crt1, crti, crtbeginT | crt1, crti, crtbegin | crtbegin_static | crt2, crtbegin | crt1 |
|
||||
//! | static-pic-exe | rcrt1, crti, crtbeginS | rcrt1, crti, crtbeginS | crtbegin_dynamic | crt2, crtbegin | crt1 |
|
||||
//! | dynamic-dylib | crti, crtbeginS | crti, crtbeginS | crtbegin_so | dllcrt2, crtbegin | - |
|
||||
//! | static-dylib (gcc) | crti, crtbeginT | crti, crtbeginS | crtbegin_so | dllcrt2, crtbegin | - |
|
||||
//! | static-dylib (clang) | crti, crtbeginT | N/A | crtbegin_static | dllcrt2, crtbegin | - |
|
||||
//!
|
||||
//! | Post-link CRT objects | glibc | musl | bionic | mingw | wasi |
|
||||
//! |-----------------------|---------------|---------------|----------------|--------|------|
|
||||
//! | dynamic-nopic-exe | crtend, crtn | crtend, crtn | crtend_android | crtend | - |
|
||||
//! | dynamic-pic-exe | crtendS, crtn | crtendS, crtn | crtend_android | crtend | - |
|
||||
//! | static-nopic-exe | crtend, crtn | crtend, crtn | crtend_android | crtend | - |
|
||||
//! | static-pic-exe | crtendS, crtn | crtendS, crtn | crtend_android | crtend | - |
|
||||
//! | dynamic-dylib | crtendS, crtn | crtendS, crtn | crtend_so | crtend | - |
|
||||
//! | static-dylib (gcc) | crtend, crtn | crtendS, crtn | crtend_so | crtend | - |
|
||||
//! | static-dylib (clang) | crtendS, crtn | N/A | crtend_so | crtend | - |
|
||||
//!
|
||||
//! Use cases for rustc linking the CRT objects explicitly:
|
||||
//! - rustc needs to add its own Rust-specific objects (mingw is the example)
|
||||
//! - gcc wrapper cannot be used for some reason and linker like ld or lld is used directly.
|
||||
//! - gcc wrapper pulls wrong CRT objects (e.g. from glibc when we are targeting musl).
|
||||
//!
|
||||
//! In general it is preferable to rely on the target's native toolchain to pull the objects.
|
||||
//! However, for some targets (musl, mingw) rustc historically provides a more self-contained
|
||||
//! installation not requiring users to install the native target's toolchain.
|
||||
//! In that case rustc distributes the objects as a part of the target's Rust toolchain
|
||||
//! and falls back to linking with them manually.
|
||||
//! Unlike native toolchains, rustc only currently adds the libc's objects during linking,
|
||||
//! but not gcc's. As a result rustc cannot link with C++ static libraries (#36710)
|
||||
//! when linking in self-contained mode.
|
||||
|
||||
use crate::spec::LinkOutputKind;
|
||||
use rustc_serialize::json::{Json, ToJson};
|
||||
use std::collections::BTreeMap;
|
||||
use std::str::FromStr;
|
||||
|
||||
pub type CrtObjects = BTreeMap<LinkOutputKind, Vec<String>>;
|
||||
|
||||
pub(super) fn new(obj_table: &[(LinkOutputKind, &[&str])]) -> CrtObjects {
|
||||
obj_table.iter().map(|(z, k)| (*z, k.iter().map(|b| b.to_string()).collect())).collect()
|
||||
}
|
||||
|
||||
pub(super) fn all(obj: &str) -> CrtObjects {
|
||||
new(&[
|
||||
(LinkOutputKind::DynamicNoPicExe, &[obj]),
|
||||
(LinkOutputKind::DynamicPicExe, &[obj]),
|
||||
(LinkOutputKind::StaticNoPicExe, &[obj]),
|
||||
(LinkOutputKind::StaticPicExe, &[obj]),
|
||||
(LinkOutputKind::DynamicDylib, &[obj]),
|
||||
(LinkOutputKind::StaticDylib, &[obj]),
|
||||
])
|
||||
}
|
||||
|
||||
pub(super) fn pre_musl_fallback() -> CrtObjects {
|
||||
new(&[
|
||||
(LinkOutputKind::DynamicNoPicExe, &["crt1.o", "crti.o"]),
|
||||
(LinkOutputKind::DynamicPicExe, &["Scrt1.o", "crti.o"]),
|
||||
(LinkOutputKind::StaticNoPicExe, &["crt1.o", "crti.o"]),
|
||||
(LinkOutputKind::StaticPicExe, &["rcrt1.o", "crti.o"]),
|
||||
(LinkOutputKind::DynamicDylib, &["crti.o"]),
|
||||
(LinkOutputKind::StaticDylib, &["crti.o"]),
|
||||
])
|
||||
}
|
||||
|
||||
pub(super) fn post_musl_fallback() -> CrtObjects {
|
||||
all("crtn.o")
|
||||
}
|
||||
|
||||
pub(super) fn pre_mingw_fallback() -> CrtObjects {
|
||||
new(&[
|
||||
(LinkOutputKind::DynamicNoPicExe, &["crt2.o", "rsbegin.o"]),
|
||||
(LinkOutputKind::DynamicPicExe, &["crt2.o", "rsbegin.o"]),
|
||||
(LinkOutputKind::StaticNoPicExe, &["crt2.o", "rsbegin.o"]),
|
||||
(LinkOutputKind::StaticPicExe, &["crt2.o", "rsbegin.o"]),
|
||||
(LinkOutputKind::DynamicDylib, &["dllcrt2.o", "rsbegin.o"]),
|
||||
(LinkOutputKind::StaticDylib, &["dllcrt2.o", "rsbegin.o"]),
|
||||
])
|
||||
}
|
||||
|
||||
pub(super) fn post_mingw_fallback() -> CrtObjects {
|
||||
all("rsend.o")
|
||||
}
|
||||
|
||||
pub(super) fn pre_mingw() -> CrtObjects {
|
||||
all("rsbegin.o")
|
||||
}
|
||||
|
||||
pub(super) fn post_mingw() -> CrtObjects {
|
||||
all("rsend.o")
|
||||
}
|
||||
|
||||
pub(super) fn pre_wasi_fallback() -> CrtObjects {
|
||||
new(&[
|
||||
(LinkOutputKind::DynamicNoPicExe, &["crt1.o"]),
|
||||
(LinkOutputKind::DynamicPicExe, &["crt1.o"]),
|
||||
(LinkOutputKind::StaticNoPicExe, &["crt1.o"]),
|
||||
(LinkOutputKind::StaticPicExe, &["crt1.o"]),
|
||||
])
|
||||
}
|
||||
|
||||
pub(super) fn post_wasi_fallback() -> CrtObjects {
|
||||
new(&[])
|
||||
}
|
||||
|
||||
/// Which logic to use to determine whether to fall back to the "self-contained" mode or not.
|
||||
#[derive(Clone, Copy, PartialEq, Hash, Debug)]
|
||||
pub enum CrtObjectsFallback {
|
||||
Musl,
|
||||
Mingw,
|
||||
Wasm,
|
||||
}
|
||||
|
||||
impl FromStr for CrtObjectsFallback {
|
||||
type Err = ();
|
||||
|
||||
fn from_str(s: &str) -> Result<CrtObjectsFallback, ()> {
|
||||
Ok(match s {
|
||||
"musl" => CrtObjectsFallback::Musl,
|
||||
"mingw" => CrtObjectsFallback::Mingw,
|
||||
"wasm" => CrtObjectsFallback::Wasm,
|
||||
_ => return Err(()),
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
impl ToJson for CrtObjectsFallback {
|
||||
fn to_json(&self) -> Json {
|
||||
match *self {
|
||||
CrtObjectsFallback::Musl => "musl",
|
||||
CrtObjectsFallback::Mingw => "mingw",
|
||||
CrtObjectsFallback::Wasm => "wasm",
|
||||
}
|
||||
.to_json()
|
||||
}
|
||||
}
|
@ -1,4 +1,4 @@
|
||||
use crate::spec::{LinkArgs, LinkerFlavor, LldFlavor, TargetOptions};
|
||||
use crate::spec::{crt_objects, LinkArgs, LinkOutputKind, LinkerFlavor, LldFlavor, TargetOptions};
|
||||
|
||||
pub fn opts() -> TargetOptions {
|
||||
let mut pre_link_args = LinkArgs::new();
|
||||
@ -23,7 +23,12 @@ pub fn opts() -> TargetOptions {
|
||||
linker_is_gnu: true,
|
||||
has_rpath: false,
|
||||
pre_link_args,
|
||||
pre_link_objects_exe: vec!["Scrt1.o".to_string()],
|
||||
pre_link_objects: crt_objects::new(&[
|
||||
(LinkOutputKind::DynamicNoPicExe, &["Scrt1.o"]),
|
||||
(LinkOutputKind::DynamicPicExe, &["Scrt1.o"]),
|
||||
(LinkOutputKind::StaticNoPicExe, &["Scrt1.o"]),
|
||||
(LinkOutputKind::StaticPicExe, &["Scrt1.o"]),
|
||||
]),
|
||||
position_independent_executables: true,
|
||||
has_elf_tls: true,
|
||||
..Default::default()
|
||||
|
@ -1,29 +1,18 @@
|
||||
use crate::spec::crt_objects::{self, CrtObjectsFallback};
|
||||
use crate::spec::{LinkerFlavor, TargetOptions};
|
||||
|
||||
pub fn opts() -> TargetOptions {
|
||||
let mut base = super::linux_base::opts();
|
||||
|
||||
// Make sure that the linker/gcc really don't pull in anything, including
|
||||
// default objects, libs, etc.
|
||||
base.pre_link_args_crt.insert(LinkerFlavor::Gcc, Vec::new());
|
||||
base.pre_link_args_crt.get_mut(&LinkerFlavor::Gcc).unwrap().push("-nostdlib".to_string());
|
||||
|
||||
// At least when this was tested, the linker would not add the
|
||||
// `GNU_EH_FRAME` program header to executables generated, which is required
|
||||
// when unwinding to locate the unwinding information. I'm not sure why this
|
||||
// argument is *not* necessary for normal builds, but it can't hurt!
|
||||
base.pre_link_args.get_mut(&LinkerFlavor::Gcc).unwrap().push("-Wl,--eh-frame-hdr".to_string());
|
||||
|
||||
// When generating a statically linked executable there's generally some
|
||||
// small setup needed which is listed in these files. These are provided by
|
||||
// a musl toolchain and are linked by default by the `musl-gcc` script. Note
|
||||
// that `gcc` also does this by default, it just uses some different files.
|
||||
//
|
||||
// Each target directory for musl has these object files included in it so
|
||||
// they'll be included from there.
|
||||
base.pre_link_objects_exe_crt.push("crt1.o".to_string());
|
||||
base.pre_link_objects_exe_crt.push("crti.o".to_string());
|
||||
base.post_link_objects_crt.push("crtn.o".to_string());
|
||||
base.pre_link_objects_fallback = crt_objects::pre_musl_fallback();
|
||||
base.post_link_objects_fallback = crt_objects::post_musl_fallback();
|
||||
base.crt_objects_fallback = Some(CrtObjectsFallback::Musl);
|
||||
|
||||
// These targets statically link libc by default
|
||||
base.crt_static_default = true;
|
||||
|
@ -35,6 +35,7 @@
|
||||
//! to the list specified by the target, rather than replace.
|
||||
|
||||
use crate::spec::abi::{lookup as lookup_abi, Abi};
|
||||
use crate::spec::crt_objects::{CrtObjects, CrtObjectsFallback};
|
||||
use rustc_serialize::json::{Json, ToJson};
|
||||
use std::collections::BTreeMap;
|
||||
use std::path::{Path, PathBuf};
|
||||
@ -44,6 +45,8 @@ use std::{fmt, io};
|
||||
use rustc_macros::HashStable_Generic;
|
||||
|
||||
pub mod abi;
|
||||
pub mod crt_objects;
|
||||
|
||||
mod android_base;
|
||||
mod apple_base;
|
||||
mod apple_sdk_base;
|
||||
@ -341,6 +344,54 @@ impl ToJson for TlsModel {
|
||||
}
|
||||
}
|
||||
|
||||
/// Everything is flattened to a single enum to make the json encoding/decoding less annoying.
|
||||
#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Debug)]
|
||||
pub enum LinkOutputKind {
|
||||
/// Dynamically linked non position-independent executable.
|
||||
DynamicNoPicExe,
|
||||
/// Dynamically linked position-independent executable.
|
||||
DynamicPicExe,
|
||||
/// Statically linked non position-independent executable.
|
||||
StaticNoPicExe,
|
||||
/// Statically linked position-independent executable.
|
||||
StaticPicExe,
|
||||
/// Regular dynamic library ("dynamically linked").
|
||||
DynamicDylib,
|
||||
/// Dynamic library with bundled libc ("statically linked").
|
||||
StaticDylib,
|
||||
}
|
||||
|
||||
impl LinkOutputKind {
|
||||
fn as_str(&self) -> &'static str {
|
||||
match self {
|
||||
LinkOutputKind::DynamicNoPicExe => "dynamic-nopic-exe",
|
||||
LinkOutputKind::DynamicPicExe => "dynamic-pic-exe",
|
||||
LinkOutputKind::StaticNoPicExe => "static-nopic-exe",
|
||||
LinkOutputKind::StaticPicExe => "static-pic-exe",
|
||||
LinkOutputKind::DynamicDylib => "dynamic-dylib",
|
||||
LinkOutputKind::StaticDylib => "static-dylib",
|
||||
}
|
||||
}
|
||||
|
||||
pub(super) fn from_str(s: &str) -> Option<LinkOutputKind> {
|
||||
Some(match s {
|
||||
"dynamic-nopic-exe" => LinkOutputKind::DynamicNoPicExe,
|
||||
"dynamic-pic-exe" => LinkOutputKind::DynamicPicExe,
|
||||
"static-nopic-exe" => LinkOutputKind::StaticNoPicExe,
|
||||
"static-pic-exe" => LinkOutputKind::StaticPicExe,
|
||||
"dynamic-dylib" => LinkOutputKind::DynamicDylib,
|
||||
"static-dylib" => LinkOutputKind::StaticDylib,
|
||||
_ => return None,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
impl fmt::Display for LinkOutputKind {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
f.write_str(self.as_str())
|
||||
}
|
||||
}
|
||||
|
||||
pub enum LoadTargetError {
|
||||
BuiltinTargetNotFound(String),
|
||||
Other(String),
|
||||
@ -644,13 +695,19 @@ pub struct TargetOptions {
|
||||
/// Linker arguments that are passed *before* any user-defined libraries.
|
||||
pub pre_link_args: LinkArgs, // ... unconditionally
|
||||
pub pre_link_args_crt: LinkArgs, // ... when linking with a bundled crt
|
||||
/// Objects to link before all others, always found within the
|
||||
/// sysroot folder.
|
||||
pub pre_link_objects_exe: Vec<String>, // ... when linking an executable, unconditionally
|
||||
pub pre_link_objects_exe_crt: Vec<String>, // ... when linking an executable with a bundled crt
|
||||
pub pre_link_objects_dll: Vec<String>, // ... when linking a dylib
|
||||
/// Objects to link before and after all other object code.
|
||||
pub pre_link_objects: CrtObjects,
|
||||
pub post_link_objects: CrtObjects,
|
||||
/// Same as `(pre|post)_link_objects`, but when we fail to pull the objects with help of the
|
||||
/// target's native gcc and fall back to the "self-contained" mode and pull them manually.
|
||||
/// See `crt_objects.rs` for some more detailed documentation.
|
||||
pub pre_link_objects_fallback: CrtObjects,
|
||||
pub post_link_objects_fallback: CrtObjects,
|
||||
/// Which logic to use to determine whether to fall back to the "self-contained" mode or not.
|
||||
pub crt_objects_fallback: Option<CrtObjectsFallback>,
|
||||
|
||||
/// Linker arguments that are unconditionally passed after any
|
||||
/// user-defined but before post_link_objects. Standard platform
|
||||
/// user-defined but before post-link objects. Standard platform
|
||||
/// libraries that should be always be linked to, usually go here.
|
||||
pub late_link_args: LinkArgs,
|
||||
/// Linker arguments used in addition to `late_link_args` if at least one
|
||||
@ -659,10 +716,6 @@ pub struct TargetOptions {
|
||||
/// Linker arguments used in addition to `late_link_args` if aall Rust
|
||||
/// dependencies are statically linked.
|
||||
pub late_link_args_static: LinkArgs,
|
||||
/// Objects to link after all others, always found within the
|
||||
/// sysroot folder.
|
||||
pub post_link_objects: Vec<String>, // ... unconditionally
|
||||
pub post_link_objects_crt: Vec<String>, // ... when linking with a bundled crt
|
||||
/// Linker arguments that are unconditionally passed *after* any
|
||||
/// user-defined libraries.
|
||||
pub post_link_args: LinkArgs,
|
||||
@ -932,11 +985,11 @@ impl Default for TargetOptions {
|
||||
position_independent_executables: false,
|
||||
needs_plt: false,
|
||||
relro_level: RelroLevel::None,
|
||||
pre_link_objects_exe: Vec::new(),
|
||||
pre_link_objects_exe_crt: Vec::new(),
|
||||
pre_link_objects_dll: Vec::new(),
|
||||
post_link_objects: Vec::new(),
|
||||
post_link_objects_crt: Vec::new(),
|
||||
pre_link_objects: Default::default(),
|
||||
post_link_objects: Default::default(),
|
||||
pre_link_objects_fallback: Default::default(),
|
||||
post_link_objects_fallback: Default::default(),
|
||||
crt_objects_fallback: None,
|
||||
late_link_args: LinkArgs::new(),
|
||||
late_link_args_dynamic: LinkArgs::new(),
|
||||
late_link_args_static: LinkArgs::new(),
|
||||
@ -1191,6 +1244,45 @@ impl Target {
|
||||
})
|
||||
})).unwrap_or(Ok(()))
|
||||
} );
|
||||
($key_name:ident, crt_objects_fallback) => ( {
|
||||
let name = (stringify!($key_name)).replace("_", "-");
|
||||
obj.find(&name[..]).and_then(|o| o.as_string().and_then(|s| {
|
||||
match s.parse::<CrtObjectsFallback>() {
|
||||
Ok(fallback) => base.options.$key_name = Some(fallback),
|
||||
_ => return Some(Err(format!("'{}' is not a valid CRT objects fallback. \
|
||||
Use 'musl', 'mingw' or 'wasm'", s))),
|
||||
}
|
||||
Some(Ok(()))
|
||||
})).unwrap_or(Ok(()))
|
||||
} );
|
||||
($key_name:ident, link_objects) => ( {
|
||||
let name = (stringify!($key_name)).replace("_", "-");
|
||||
if let Some(val) = obj.find(&name[..]) {
|
||||
let obj = val.as_object().ok_or_else(|| format!("{}: expected a \
|
||||
JSON object with fields per CRT object kind.", name))?;
|
||||
let mut args = CrtObjects::new();
|
||||
for (k, v) in obj {
|
||||
let kind = LinkOutputKind::from_str(&k).ok_or_else(|| {
|
||||
format!("{}: '{}' is not a valid value for CRT object kind. \
|
||||
Use '(dynamic,static)-(nopic,pic)-exe' or \
|
||||
'(dynamic,static)-dylib'", name, k)
|
||||
})?;
|
||||
|
||||
let v = v.as_array().ok_or_else(||
|
||||
format!("{}.{}: expected a JSON array", name, k)
|
||||
)?.iter().enumerate()
|
||||
.map(|(i,s)| {
|
||||
let s = s.as_string().ok_or_else(||
|
||||
format!("{}.{}[{}]: expected a JSON string", name, k, i))?;
|
||||
Ok(s.to_owned())
|
||||
})
|
||||
.collect::<Result<Vec<_>, String>>()?;
|
||||
|
||||
args.insert(kind, v);
|
||||
}
|
||||
base.options.$key_name = args;
|
||||
}
|
||||
} );
|
||||
($key_name:ident, link_args) => ( {
|
||||
let name = (stringify!($key_name)).replace("_", "-");
|
||||
if let Some(val) = obj.find(&name[..]) {
|
||||
@ -1238,16 +1330,16 @@ impl Target {
|
||||
key!(is_builtin, bool);
|
||||
key!(linker, optional);
|
||||
key!(lld_flavor, LldFlavor)?;
|
||||
key!(pre_link_objects, link_objects);
|
||||
key!(post_link_objects, link_objects);
|
||||
key!(pre_link_objects_fallback, link_objects);
|
||||
key!(post_link_objects_fallback, link_objects);
|
||||
key!(crt_objects_fallback, crt_objects_fallback)?;
|
||||
key!(pre_link_args, link_args);
|
||||
key!(pre_link_args_crt, link_args);
|
||||
key!(pre_link_objects_exe, list);
|
||||
key!(pre_link_objects_exe_crt, list);
|
||||
key!(pre_link_objects_dll, list);
|
||||
key!(late_link_args, link_args);
|
||||
key!(late_link_args_dynamic, link_args);
|
||||
key!(late_link_args_static, link_args);
|
||||
key!(post_link_objects, list);
|
||||
key!(post_link_objects_crt, list);
|
||||
key!(post_link_args, link_args);
|
||||
key!(link_env, env);
|
||||
key!(link_env_remove, list);
|
||||
@ -1468,16 +1560,16 @@ impl ToJson for Target {
|
||||
target_option_val!(is_builtin);
|
||||
target_option_val!(linker);
|
||||
target_option_val!(lld_flavor);
|
||||
target_option_val!(pre_link_objects);
|
||||
target_option_val!(post_link_objects);
|
||||
target_option_val!(pre_link_objects_fallback);
|
||||
target_option_val!(post_link_objects_fallback);
|
||||
target_option_val!(crt_objects_fallback);
|
||||
target_option_val!(link_args - pre_link_args);
|
||||
target_option_val!(link_args - pre_link_args_crt);
|
||||
target_option_val!(pre_link_objects_exe);
|
||||
target_option_val!(pre_link_objects_exe_crt);
|
||||
target_option_val!(pre_link_objects_dll);
|
||||
target_option_val!(link_args - late_link_args);
|
||||
target_option_val!(link_args - late_link_args_dynamic);
|
||||
target_option_val!(link_args - late_link_args_static);
|
||||
target_option_val!(post_link_objects);
|
||||
target_option_val!(post_link_objects_crt);
|
||||
target_option_val!(link_args - post_link_args);
|
||||
target_option_val!(env - link_env);
|
||||
target_option_val!(link_env_remove);
|
||||
|
@ -1,3 +1,4 @@
|
||||
use super::crt_objects::CrtObjectsFallback;
|
||||
use super::{LinkerFlavor, LldFlavor, PanicStrategy, RelocModel, TargetOptions, TlsModel};
|
||||
use std::collections::BTreeMap;
|
||||
|
||||
@ -123,6 +124,8 @@ pub fn options() -> TargetOptions {
|
||||
|
||||
pre_link_args,
|
||||
|
||||
crt_objects_fallback: Some(CrtObjectsFallback::Wasm),
|
||||
|
||||
// This has no effect in LLVM 8 or prior, but in LLVM 9 and later when
|
||||
// PIC code is implemented this has quite a drastric effect if it stays
|
||||
// at the default, `pic`. In an effort to keep wasm binaries as minimal
|
||||
|
@ -21,10 +21,6 @@ pub fn target() -> Result<Target, String> {
|
||||
// otherwise
|
||||
clang_args.push("--target=wasm32-unknown-unknown".to_string());
|
||||
|
||||
// Disable attempting to link crt1.o since it typically isn't present and
|
||||
// isn't needed currently.
|
||||
clang_args.push("-nostdlib".to_string());
|
||||
|
||||
// For now this target just never has an entry symbol no matter the output
|
||||
// type, so unconditionally pass this.
|
||||
clang_args.push("-Wl,--no-entry".to_string());
|
||||
|
@ -73,7 +73,7 @@
|
||||
//! you know what you're getting in to!
|
||||
|
||||
use super::wasm32_base;
|
||||
use super::{LinkerFlavor, LldFlavor, Target};
|
||||
use super::{crt_objects, LinkerFlavor, LldFlavor, Target};
|
||||
|
||||
pub fn target() -> Result<Target, String> {
|
||||
let mut options = wasm32_base::options();
|
||||
@ -84,9 +84,8 @@ pub fn target() -> Result<Target, String> {
|
||||
.or_insert(Vec::new())
|
||||
.push("--target=wasm32-wasi".to_string());
|
||||
|
||||
// When generating an executable be sure to put the startup object at the
|
||||
// front so the main function is correctly hooked up.
|
||||
options.pre_link_objects_exe_crt.push("crt1.o".to_string());
|
||||
options.pre_link_objects_fallback = crt_objects::pre_wasi_fallback();
|
||||
options.post_link_objects_fallback = crt_objects::post_wasi_fallback();
|
||||
|
||||
// Right now this is a bit of a workaround but we're currently saying that
|
||||
// the target by default has a static crt which we're taking as a signal
|
||||
|
@ -1,3 +1,4 @@
|
||||
use crate::spec::crt_objects::{self, CrtObjectsFallback};
|
||||
use crate::spec::{LinkArgs, LinkerFlavor, TargetOptions};
|
||||
|
||||
pub fn opts() -> TargetOptions {
|
||||
@ -10,8 +11,6 @@ pub fn opts() -> TargetOptions {
|
||||
"-fno-use-linker-plugin".to_string(),
|
||||
// Always enable DEP (NX bit) when it is available
|
||||
"-Wl,--nxcompat".to_string(),
|
||||
// Do not use the standard system startup files or libraries when linking
|
||||
"-nostdlib".to_string(),
|
||||
],
|
||||
);
|
||||
|
||||
@ -80,18 +79,14 @@ pub fn opts() -> TargetOptions {
|
||||
is_like_windows: true,
|
||||
allows_weak_linkage: false,
|
||||
pre_link_args,
|
||||
pre_link_objects_exe: vec![
|
||||
"crt2.o".to_string(), // mingw C runtime initialization for executables
|
||||
"rsbegin.o".to_string(), // Rust compiler runtime initialization, see rsbegin.rs
|
||||
],
|
||||
pre_link_objects_dll: vec![
|
||||
"dllcrt2.o".to_string(), // mingw C runtime initialization for dlls
|
||||
"rsbegin.o".to_string(),
|
||||
],
|
||||
pre_link_objects: crt_objects::pre_mingw(),
|
||||
post_link_objects: crt_objects::post_mingw(),
|
||||
pre_link_objects_fallback: crt_objects::pre_mingw_fallback(),
|
||||
post_link_objects_fallback: crt_objects::post_mingw_fallback(),
|
||||
crt_objects_fallback: Some(CrtObjectsFallback::Mingw),
|
||||
late_link_args,
|
||||
late_link_args_dynamic,
|
||||
late_link_args_static,
|
||||
post_link_objects: vec!["rsend.o".to_string()],
|
||||
abi_return_struct_as_int: true,
|
||||
emit_debug_gdb_scripts: false,
|
||||
requires_uwtable: true,
|
||||
|
@ -3,20 +3,8 @@ use crate::spec::{LinkArgs, LinkerFlavor, TargetOptions};
|
||||
pub fn opts() -> TargetOptions {
|
||||
let base = super::windows_gnu_base::opts();
|
||||
|
||||
// FIXME: Consider adding `-nostdlib` and inheriting from `windows_gnu_base`.
|
||||
let mut pre_link_args = LinkArgs::new();
|
||||
pre_link_args.insert(
|
||||
LinkerFlavor::Gcc,
|
||||
vec![
|
||||
// Tell GCC to avoid linker plugins, because we are not bundling
|
||||
// them with Windows installer, and Rust does its own LTO anyways.
|
||||
"-fno-use-linker-plugin".to_string(),
|
||||
// Always enable DEP (NX bit) when it is available
|
||||
"-Wl,--nxcompat".to_string(),
|
||||
],
|
||||
);
|
||||
|
||||
// FIXME: This should be updated for the exception machinery changes from #67502.
|
||||
// FIXME: This should be updated for the exception machinery changes from #67502
|
||||
// and inherit from `windows_gnu_base`, at least partially.
|
||||
let mut late_link_args = LinkArgs::new();
|
||||
let late_link_args_dynamic = LinkArgs::new();
|
||||
let late_link_args_static = LinkArgs::new();
|
||||
@ -40,11 +28,6 @@ pub fn opts() -> TargetOptions {
|
||||
TargetOptions {
|
||||
executables: false,
|
||||
limit_rdylib_exports: false,
|
||||
pre_link_args,
|
||||
// FIXME: Consider adding `-nostdlib` and inheriting from `windows_gnu_base`.
|
||||
pre_link_objects_exe: vec!["rsbegin.o".to_string()],
|
||||
// FIXME: Consider adding `-nostdlib` and inheriting from `windows_gnu_base`.
|
||||
pre_link_objects_dll: vec!["rsbegin.o".to_string()],
|
||||
late_link_args,
|
||||
late_link_args_dynamic,
|
||||
late_link_args_static,
|
||||
|
@ -1,6 +1,6 @@
|
||||
use std::iter;
|
||||
|
||||
use super::{LinkerFlavor, LldFlavor, PanicStrategy, Target, TargetOptions};
|
||||
use super::{crt_objects, LinkerFlavor, LldFlavor, PanicStrategy, Target, TargetOptions};
|
||||
|
||||
pub fn target() -> Result<Target, String> {
|
||||
const PRE_LINK_ARGS: &[&str] = &[
|
||||
@ -68,7 +68,8 @@ pub fn target() -> Result<Target, String> {
|
||||
PRE_LINK_ARGS.iter().cloned().map(String::from).collect(),
|
||||
))
|
||||
.collect(),
|
||||
post_link_objects: vec!["libunwind.a".into()],
|
||||
// FIXME: libunwind is certainly not a CRT object, use some other option instead.
|
||||
post_link_objects: crt_objects::all("libunwind.a"),
|
||||
override_export_symbols: Some(EXPORT_SYMBOLS.iter().cloned().map(String::from).collect()),
|
||||
relax_elf_relocations: true,
|
||||
..Default::default()
|
||||
|
@ -2684,11 +2684,11 @@ impl<A: ToJson> ToJson for Vec<A> {
|
||||
}
|
||||
}
|
||||
|
||||
impl<A: ToJson> ToJson for BTreeMap<string::String, A> {
|
||||
impl<T: ToString, A: ToJson> ToJson for BTreeMap<T, A> {
|
||||
fn to_json(&self) -> Json {
|
||||
let mut d = BTreeMap::new();
|
||||
for (key, value) in self {
|
||||
d.insert((*key).clone(), value.to_json());
|
||||
d.insert(key.to_string(), value.to_json());
|
||||
}
|
||||
Json::Object(d)
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user