From 99f48131fa856c4bed9871030a85c34cf41e5101 Mon Sep 17 00:00:00 2001 From: Sebastian Humenda Date: Tue, 3 Apr 2018 14:53:13 +0200 Subject: [PATCH 1/7] Add L4Bender as linker variant --- src/librustc_codegen_llvm/back/linker.rs | 128 ++++++++++++++++++ src/librustc_target/spec/l4re_base.rs | 13 +- .../spec/x86_64_unknown_l4re_uclibc.rs | 2 +- 3 files changed, 130 insertions(+), 13 deletions(-) diff --git a/src/librustc_codegen_llvm/back/linker.rs b/src/librustc_codegen_llvm/back/linker.rs index c03180c02fe63..6d7ffbbc683e8 100644 --- a/src/librustc_codegen_llvm/back/linker.rs +++ b/src/librustc_codegen_llvm/back/linker.rs @@ -85,6 +85,13 @@ impl LinkerInfo { }) as Box } + LinkerFlavor::L4Bender => { + Box::new(L4Bender { + cmd, + sess, + hinted_static: false, + }) as Box + }, LinkerFlavor::Lld(LldFlavor::Wasm) => { Box::new(WasmLd { cmd, @@ -1088,3 +1095,124 @@ impl<'a> Linker for WasmLd<'a> { // Do nothing for now } } + +/// Linker shepherd script for L4Re (Fiasco) +pub struct L4Bender<'a> { + cmd: Command, + sess: &'a Session, + hinted_static: bool, +} + +impl<'a> Linker for L4Bender<'a> { + fn link_dylib(&mut self, lib: &str) { + self.link_staticlib(lib); // do not support dynamic linking for now + } + fn link_staticlib(&mut self, lib: &str) { + self.hint_static(); + self.cmd.arg(format!("-PC{}", lib)); + } + fn link_rlib(&mut self, lib: &Path) { + self.hint_static(); + self.cmd.arg(lib); + } + fn include_path(&mut self, path: &Path) { + self.cmd.arg("-L").arg(path); + } + fn framework_path(&mut self, _: &Path) { + bug!("Frameworks are not supported on L4Re!"); + } + fn output_filename(&mut self, path: &Path) { self.cmd.arg("-o").arg(path); } + fn add_object(&mut self, path: &Path) { self.cmd.arg(path); } + // not sure about pie on L4Re + fn position_independent_executable(&mut self) { } + fn no_position_independent_executable(&mut self) { } + fn full_relro(&mut self) { self.cmd.arg("-z,relro,-z,now"); } + fn partial_relro(&mut self) { self.cmd.arg("-z,relro"); } + fn no_relro(&mut self) { self.cmd.arg("-z,norelro"); } + fn build_static_executable(&mut self) { self.cmd.arg("-static"); } + fn args(&mut self, args: &[String]) { self.cmd.args(args); } + + fn link_rust_dylib(&mut self, lib: &str, _path: &Path) { self.link_dylib(lib); } + + fn link_framework(&mut self, _: &str) { + bug!("Frameworks not supported on L4Re."); + } + + // Here we explicitly ask that the entire archive is included into the + // result artifact. For more details see #15460, but the gist is that + // the linker will strip away any unused objects in the archive if we + // don't otherwise explicitly reference them. This can occur for + // libraries which are just providing bindings, libraries with generic + // functions, etc. + fn link_whole_staticlib(&mut self, lib: &str, _: &[PathBuf]) { + self.hint_static(); + self.cmd.arg("--whole-archive"); + self.cmd.arg("-l").arg(lib); + self.cmd.arg("--no-whole-archive"); + } + + fn link_whole_rlib(&mut self, lib: &Path) { + self.hint_static(); + self.cmd.arg("--whole-archive").arg(lib).arg("--no-whole-archive"); + } + + fn gc_sections(&mut self, keep_metadata: bool) { + if !keep_metadata { + self.cmd.arg("--gc-sections"); + } + } + + fn optimize(&mut self) { + self.cmd.arg("-O2"); + } + + fn pgo_gen(&mut self) { } + + fn debuginfo(&mut self) { + // for documentation, see GccLinker.debuginfo() + match self.sess.opts.debuginfo { + DebugInfoLevel::NoDebugInfo => { + match self.sess.opts.debugging_opts.strip_debuginfo_if_disabled { + Some(true) => { self.cmd.arg("-S"); }, + _ => {}, + } + }, + _ => {}, + }; + } + + fn no_default_libraries(&mut self) { + self.cmd.arg("-nostdlib"); + } + + fn build_dylib(&mut self, _: &Path) { + bug!("not implemented"); + } + + fn export_symbols(&mut self, _: &Path, _: CrateType) { + bug!("Not implemented"); + } + + fn subsystem(&mut self, subsystem: &str) { + self.cmd.arg(&format!("--subsystem,{}", subsystem)); + } + + fn finalize(&mut self) -> Command { + self.hint_static(); // Reset to default before returning the composed command line. + let mut cmd = Command::new(""); + ::std::mem::swap(&mut cmd, &mut self.cmd); + cmd + } + + fn group_start(&mut self) { self.cmd.arg("--start-group"); } + fn group_end(&mut self) { self.cmd.arg("--end-group"); } +} + +impl<'a> L4Bender<'a> { + fn hint_static(&mut self) { + if !self.hinted_static { + self.cmd.arg("-static"); + self.hinted_static = true; + } + } +} diff --git a/src/librustc_target/spec/l4re_base.rs b/src/librustc_target/spec/l4re_base.rs index 4ebc930d48b6f..539ae943f6b1f 100644 --- a/src/librustc_target/spec/l4re_base.rs +++ b/src/librustc_target/spec/l4re_base.rs @@ -12,17 +12,6 @@ use spec::{LinkArgs, LinkerFlavor, PanicStrategy, TargetOptions}; use std::default::Default; //use std::process::Command; -// Use GCC to locate code for crt* libraries from the host, not from L4Re. Note -// that a few files also come from L4Re, for these, the function shouldn't be -// used. This uses GCC for the location of the file, but GCC is required for L4Re anyway. -//fn get_path_or(filename: &str) -> String { -// let child = Command::new("gcc") -// .arg(format!("-print-file-name={}", filename)).output() -// .expect("Failed to execute GCC"); -// String::from_utf8(child.stdout) -// .expect("Couldn't read path from GCC").trim().into() -//} - pub fn opts() -> TargetOptions { let mut args = LinkArgs::new(); args.insert(LinkerFlavor::Gcc, vec![]); @@ -32,7 +21,7 @@ pub fn opts() -> TargetOptions { has_elf_tls: false, exe_allocation_crate: None, panic_strategy: PanicStrategy::Abort, - linker: Some("ld".to_string()), + linker: Some("l4-bender".to_string()), pre_link_args: args, target_family: Some("unix".to_string()), .. Default::default() diff --git a/src/librustc_target/spec/x86_64_unknown_l4re_uclibc.rs b/src/librustc_target/spec/x86_64_unknown_l4re_uclibc.rs index f1179c18294d3..fd6ab65bb513f 100644 --- a/src/librustc_target/spec/x86_64_unknown_l4re_uclibc.rs +++ b/src/librustc_target/spec/x86_64_unknown_l4re_uclibc.rs @@ -25,7 +25,7 @@ pub fn target() -> TargetResult { target_os: "l4re".to_string(), target_env: "uclibc".to_string(), target_vendor: "unknown".to_string(), - linker_flavor: LinkerFlavor::Ld, + linker_flavor: LinkerFlavor::L4Bender, options: base, }) } From af7a7bc51f93d55025074841adb8d54d7a247151 Mon Sep 17 00:00:00 2001 From: Sebastian Humenda Date: Tue, 17 Jul 2018 14:04:24 +0200 Subject: [PATCH 2/7] add L4Bender linker in all relevant scenarios --- src/librustc_codegen_llvm/back/linker.rs | 5 ++++- src/librustc_target/spec/mod.rs | 2 ++ 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/src/librustc_codegen_llvm/back/linker.rs b/src/librustc_codegen_llvm/back/linker.rs index 6d7ffbbc683e8..48f139646715b 100644 --- a/src/librustc_codegen_llvm/back/linker.rs +++ b/src/librustc_codegen_llvm/back/linker.rs @@ -90,7 +90,7 @@ impl LinkerInfo { cmd, sess, hinted_static: false, - }) as Box + }) as Box }, LinkerFlavor::Lld(LldFlavor::Wasm) => { Box::new(WasmLd { @@ -1206,6 +1206,9 @@ impl<'a> Linker for L4Bender<'a> { fn group_start(&mut self) { self.cmd.arg("--start-group"); } fn group_end(&mut self) { self.cmd.arg("--end-group"); } + fn cross_lang_lto(&mut self) { + // do nothing + } } impl<'a> L4Bender<'a> { diff --git a/src/librustc_target/spec/mod.rs b/src/librustc_target/spec/mod.rs index 3c68b5a7ab116..a3add7150a4ce 100644 --- a/src/librustc_target/spec/mod.rs +++ b/src/librustc_target/spec/mod.rs @@ -81,6 +81,7 @@ mod riscv_base; pub enum LinkerFlavor { Em, Gcc, + L4Bender, Ld, Msvc, Lld(LldFlavor), @@ -150,6 +151,7 @@ macro_rules! flavor_mappings { flavor_mappings! { ((LinkerFlavor::Em), "em"), ((LinkerFlavor::Gcc), "gcc"), + ((LinkerFlavor::L4Bender), "l4-bender"), ((LinkerFlavor::Ld), "ld"), ((LinkerFlavor::Msvc), "msvc"), ((LinkerFlavor::Lld(LldFlavor::Wasm)), "wasm-ld"), From 341392155cf8517f9d132274f41cecaca8304e84 Mon Sep 17 00:00:00 2001 From: Sebastian Humenda Date: Tue, 11 Sep 2018 15:05:59 +0200 Subject: [PATCH 3/7] enable linker optimisations --- src/librustc_codegen_llvm/back/link.rs | 1 + src/librustc_codegen_llvm/back/linker.rs | 54 +++++++++++++++++++++--- 2 files changed, 48 insertions(+), 7 deletions(-) diff --git a/src/librustc_codegen_llvm/back/link.rs b/src/librustc_codegen_llvm/back/link.rs index 8248385c12764..1c872fddd20ad 100644 --- a/src/librustc_codegen_llvm/back/link.rs +++ b/src/librustc_codegen_llvm/back/link.rs @@ -604,6 +604,7 @@ pub fn linker_and_flavor(sess: &Session) -> (PathBuf, LinkerFlavor) { (None, Some(flavor)) => Some((PathBuf::from(match flavor { LinkerFlavor::Em => if cfg!(windows) { "emcc.bat" } else { "emcc" }, LinkerFlavor::Gcc => "cc", + LinkerFlavor::L4Bender => "l4-bender", LinkerFlavor::Ld => "ld", LinkerFlavor::Msvc => "link.exe", LinkerFlavor::Lld(_) => "lld", diff --git a/src/librustc_codegen_llvm/back/linker.rs b/src/librustc_codegen_llvm/back/linker.rs index 48f139646715b..476bda6042afc 100644 --- a/src/librustc_codegen_llvm/back/linker.rs +++ b/src/librustc_codegen_llvm/back/linker.rs @@ -9,6 +9,7 @@ // except according to those terms. use rustc_data_structures::fx::FxHashMap; +use std::env; use std::ffi::{OsStr, OsString}; use std::fs::{self, File}; use std::io::prelude::*; @@ -86,11 +87,7 @@ impl LinkerInfo { } LinkerFlavor::L4Bender => { - Box::new(L4Bender { - cmd, - sess, - hinted_static: false, - }) as Box + Box::new(L4Bender::new(cmd, sess)) as Box }, LinkerFlavor::Lld(LldFlavor::Wasm) => { Box::new(WasmLd { @@ -1169,9 +1166,11 @@ impl<'a> Linker for L4Bender<'a> { fn pgo_gen(&mut self) { } fn debuginfo(&mut self) { - // for documentation, see GccLinker.debuginfo() match self.sess.opts.debuginfo { - DebugInfoLevel::NoDebugInfo => { + DebugInfo::None => { + // If we are building without debuginfo enabled and we were called with + // `-Zstrip-debuginfo-if-disabled=yes`, tell the linker to strip any debuginfo + // found when linking to get rid of symbols from libstd. match self.sess.opts.debugging_opts.strip_debuginfo_if_disabled { Some(true) => { self.cmd.arg("-S"); }, _ => {}, @@ -1212,6 +1211,47 @@ impl<'a> Linker for L4Bender<'a> { } impl<'a> L4Bender<'a> { + pub fn new(mut cmd: Command, sess: &'a Session) -> L4Bender<'a> { + if let Ok(l4bender_args) = env::var("L4_BENDER_ARGS") { + L4Bender::split_cmd_args(&mut cmd, &l4bender_args); + } + + cmd.arg("--"); // separate direct l4-bender args from linker args + + if let Ok(l4_ld_opts) = env::var("L4_LD_OPTIONS") { + L4Bender::split_cmd_args(&mut cmd, &l4_ld_opts); + } + + L4Bender { cmd: cmd, + sess: sess, + hinted_static: false, + } + } + + /// This parses a shell-escaped string and unquotes the arguments. It doesn't attempt to + /// completely understand shell, but should instead allow passing arguments like + /// `-Dlinker="ld -m x86_64"`, and a copy without quotes, but spaces preserved, is added as an + /// argument to the given Command. This means that constructs as \" are not understood, so + /// quote wisely. + fn split_cmd_args(cmd: &mut Command, shell_args: &str) { + let mut arg = String::new(); + let mut quoted = false; + for character in shell_args.chars() { + match character { + ' ' if !quoted => { + cmd.arg(&arg); + arg.clear(); + }, + '"' | '\'' => quoted = !quoted, + _ => arg.push(character), + }; + if arg.len() > 0 { + cmd.arg(&arg); + arg.clear(); + } + } + } + fn hint_static(&mut self) { if !self.hinted_static { self.cmd.arg("-static"); From 84ca73b1c86049177197807d72adf400e9954c81 Mon Sep 17 00:00:00 2001 From: Sebastian Humenda Date: Fri, 21 Sep 2018 14:58:11 +0200 Subject: [PATCH 4/7] correctly parse environment variables for l4-bender (linker) --- src/librustc_codegen_llvm/back/linker.rs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/librustc_codegen_llvm/back/linker.rs b/src/librustc_codegen_llvm/back/linker.rs index 476bda6042afc..f888433c64e13 100644 --- a/src/librustc_codegen_llvm/back/linker.rs +++ b/src/librustc_codegen_llvm/back/linker.rs @@ -1245,10 +1245,10 @@ impl<'a> L4Bender<'a> { '"' | '\'' => quoted = !quoted, _ => arg.push(character), }; - if arg.len() > 0 { - cmd.arg(&arg); - arg.clear(); - } + } + if arg.len() > 0 { + cmd.arg(&arg); + arg.clear(); } } From d7315066ab2395a21531dd9d4df0a78ee91edfc2 Mon Sep 17 00:00:00 2001 From: Sebastian Humenda Date: Fri, 21 Sep 2018 16:25:57 +0200 Subject: [PATCH 5/7] fix tidy errors --- src/librustc_codegen_llvm/back/linker.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/librustc_codegen_llvm/back/linker.rs b/src/librustc_codegen_llvm/back/linker.rs index f888433c64e13..405cfc24ee4f3 100644 --- a/src/librustc_codegen_llvm/back/linker.rs +++ b/src/librustc_codegen_llvm/back/linker.rs @@ -1215,7 +1215,7 @@ impl<'a> L4Bender<'a> { if let Ok(l4bender_args) = env::var("L4_BENDER_ARGS") { L4Bender::split_cmd_args(&mut cmd, &l4bender_args); } - + cmd.arg("--"); // separate direct l4-bender args from linker args if let Ok(l4_ld_opts) = env::var("L4_LD_OPTIONS") { @@ -1229,7 +1229,7 @@ impl<'a> L4Bender<'a> { } /// This parses a shell-escaped string and unquotes the arguments. It doesn't attempt to - /// completely understand shell, but should instead allow passing arguments like + /// completely understand shell, but should instead allow passing arguments like /// `-Dlinker="ld -m x86_64"`, and a copy without quotes, but spaces preserved, is added as an /// argument to the given Command. This means that constructs as \" are not understood, so /// quote wisely. From b30da94d75958dd75302ce11ec7efbe4a6a98d6d Mon Sep 17 00:00:00 2001 From: Sebastian Humenda Date: Fri, 21 Sep 2018 22:47:32 +0200 Subject: [PATCH 6/7] fix minor indentation issue + remove unused import --- src/librustc_codegen_llvm/back/linker.rs | 7 ++++--- src/librustc_target/spec/l4re_base.rs | 1 - 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/librustc_codegen_llvm/back/linker.rs b/src/librustc_codegen_llvm/back/linker.rs index 405cfc24ee4f3..16511e39bc445 100644 --- a/src/librustc_codegen_llvm/back/linker.rs +++ b/src/librustc_codegen_llvm/back/linker.rs @@ -1222,9 +1222,10 @@ impl<'a> L4Bender<'a> { L4Bender::split_cmd_args(&mut cmd, &l4_ld_opts); } - L4Bender { cmd: cmd, - sess: sess, - hinted_static: false, + L4Bender { + cmd: cmd, + sess: sess, + hinted_static: false, } } diff --git a/src/librustc_target/spec/l4re_base.rs b/src/librustc_target/spec/l4re_base.rs index 539ae943f6b1f..85c0e4037bfa1 100644 --- a/src/librustc_target/spec/l4re_base.rs +++ b/src/librustc_target/spec/l4re_base.rs @@ -10,7 +10,6 @@ use spec::{LinkArgs, LinkerFlavor, PanicStrategy, TargetOptions}; use std::default::Default; -//use std::process::Command; pub fn opts() -> TargetOptions { let mut args = LinkArgs::new(); From a924cd117c03679aa9a89293e4655ed317f16649 Mon Sep 17 00:00:00 2001 From: Sebastian Humenda Date: Tue, 25 Sep 2018 15:08:54 +0200 Subject: [PATCH 7/7] get rid of L4_LD_OPTIONS variable These options can be passed using `-C link-arg`. --- src/librustc_codegen_llvm/back/linker.rs | 4 ---- 1 file changed, 4 deletions(-) diff --git a/src/librustc_codegen_llvm/back/linker.rs b/src/librustc_codegen_llvm/back/linker.rs index 16511e39bc445..31af08f33dd30 100644 --- a/src/librustc_codegen_llvm/back/linker.rs +++ b/src/librustc_codegen_llvm/back/linker.rs @@ -1218,10 +1218,6 @@ impl<'a> L4Bender<'a> { cmd.arg("--"); // separate direct l4-bender args from linker args - if let Ok(l4_ld_opts) = env::var("L4_LD_OPTIONS") { - L4Bender::split_cmd_args(&mut cmd, &l4_ld_opts); - } - L4Bender { cmd: cmd, sess: sess,