Skip to content

add support for the l4-bender linker on the x86_64-unknown-l4re-uclibc tier 3 target #85967

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

Merged
merged 3 commits into from
Jan 22, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions compiler/rustc_codegen_ssa/src/back/link.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1159,6 +1159,7 @@ pub fn linker_and_flavor(sess: &Session) -> (PathBuf, LinkerFlavor) {
LinkerFlavor::Lld(_) => "lld",
LinkerFlavor::PtxLinker => "rust-ptx-linker",
LinkerFlavor::BpfLinker => "bpf-linker",
LinkerFlavor::L4Bender => "l4-bender",
}),
flavor,
)),
Expand Down
154 changes: 153 additions & 1 deletion compiler/rustc_codegen_ssa/src/back/linker.rs
Original file line number Diff line number Diff line change
Expand Up @@ -126,7 +126,6 @@ pub fn get_linker<'a>(
// FIXME: Move `/LIBPATH` addition for uwp targets from the linker construction
// to the linker args construction.
assert!(cmd.get_args().is_empty() || sess.target.vendor == "uwp");

match flavor {
LinkerFlavor::Lld(LldFlavor::Link) | LinkerFlavor::Msvc => {
Box::new(MsvcLinker { cmd, sess }) as Box<dyn Linker>
Expand All @@ -149,6 +148,8 @@ pub fn get_linker<'a>(
LinkerFlavor::PtxLinker => Box::new(PtxLinker { cmd, sess }) as Box<dyn Linker>,

LinkerFlavor::BpfLinker => Box::new(BpfLinker { cmd, sess }) as Box<dyn Linker>,

LinkerFlavor::L4Bender => Box::new(L4Bender::new(cmd, sess)) as Box<dyn Linker>,
}
}

Expand Down Expand Up @@ -1355,6 +1356,157 @@ impl<'a> Linker for WasmLd<'a> {
}
}

/// 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: Symbol, _verbatim: bool, _as_needed: bool) {
bug!("dylibs are not supported on L4Re");
}
fn link_staticlib(&mut self, lib: Symbol, _verbatim: bool) {
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);
}

fn full_relro(&mut self) {
self.cmd.arg("-zrelro");
self.cmd.arg("-znow");
}

fn partial_relro(&mut self) {
self.cmd.arg("-zrelro");
}

fn no_relro(&mut self) {
self.cmd.arg("-znorelro");
}

fn cmd(&mut self) -> &mut Command {
&mut self.cmd
}

fn set_output_kind(&mut self, _output_kind: LinkOutputKind, _out_filename: &Path) {}

fn link_rust_dylib(&mut self, _: Symbol, _: &Path) {
panic!("Rust dylibs not supported");
}

fn link_framework(&mut self, _framework: Symbol, _as_needed: bool) {
bug!("frameworks not supported on L4Re");
}

fn link_whole_staticlib(&mut self, lib: Symbol, _verbatim: bool, _search_path: &[PathBuf]) {
self.hint_static();
self.cmd.arg("--whole-archive").arg(format!("-l{}", 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 no_gc_sections(&mut self) {
self.cmd.arg("--no-gc-sections");
}

fn optimize(&mut self) {
// GNU-style linkers support optimization with -O. GNU ld doesn't
// need a numeric argument, but other linkers do.
if self.sess.opts.optimize == config::OptLevel::Default
|| self.sess.opts.optimize == config::OptLevel::Aggressive
{
self.cmd.arg("-O1");
}
}

fn pgo_gen(&mut self) {}

fn debuginfo(&mut self, strip: Strip) {
match strip {
Strip::None => {}
Strip::Debuginfo => {
self.cmd().arg("--strip-debug");
}
Strip::Symbols => {
self.cmd().arg("--strip-all");
}
}
}

fn no_default_libraries(&mut self) {
self.cmd.arg("-nostdlib");
}

fn export_symbols(&mut self, _: &Path, _: CrateType, _: &[String]) {
// ToDo, not implemented, copy from GCC
self.sess.warn("exporting symbols not implemented yet for L4Bender");
return;
}

fn subsystem(&mut self, subsystem: &str) {
self.cmd.arg(&format!("--subsystem {}", subsystem));
}

fn reset_per_library_state(&mut self) {
self.hint_static(); // Reset to default before returning the composed command line.
}

fn group_start(&mut self) {
self.cmd.arg("--start-group");
}

fn group_end(&mut self) {
self.cmd.arg("--end-group");
}

fn linker_plugin_lto(&mut self) {}

fn control_flow_guard(&mut self) {}

fn no_crt_objects(&mut self) {}
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The interface looks like more or less like an ld linker, I'd suggest to avoid adding a new linker flavor for a start and reuse GccLinker (especially given that the set of linker flavors accepted by -C linker-flavor is a stable public interface).


impl<'a> L4Bender<'a> {
pub fn new(cmd: Command, sess: &'a Session) -> L4Bender<'a> {
L4Bender { cmd: cmd, sess: sess, hinted_static: false }
}

fn hint_static(&mut self) {
if !self.hinted_static {
self.cmd.arg("-static");
self.hinted_static = true;
}
}
}

pub(crate) fn exported_symbols(tcx: TyCtxt<'_>, crate_type: CrateType) -> Vec<String> {
if let Some(ref exports) = tcx.sess.target.override_export_symbols {
return exports.clone();
Expand Down
12 changes: 11 additions & 1 deletion compiler/rustc_session/src/config.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ use rustc_data_structures::fx::FxHashSet;
use rustc_data_structures::impl_stable_hash_via_hash;

use rustc_target::abi::{Align, TargetDataLayout};
use rustc_target::spec::{SplitDebuginfo, Target, TargetTriple, TargetWarnings};
use rustc_target::spec::{LinkerFlavor, SplitDebuginfo, Target, TargetTriple, TargetWarnings};

use rustc_serialize::json;

Expand Down Expand Up @@ -2237,6 +2237,16 @@ pub fn build_session_options(matches: &getopts::Matches) -> Options {
}
}

if cg.linker_flavor == Some(LinkerFlavor::L4Bender)
&& !nightly_options::is_unstable_enabled(matches)
{
early_error(
error_format,
"`l4-bender` linker flavor is unstable, `-Z unstable-options` \
flag must also be passed to explicitly use it",
);
}

let prints = collect_print_requests(&mut cg, &mut debugging_opts, matches, error_format);

let cg = cg;
Expand Down
17 changes: 3 additions & 14 deletions compiler/rustc_target/src/spec/l4re_base.rs
Original file line number Diff line number Diff line change
@@ -1,25 +1,14 @@
use crate::spec::{LinkerFlavor, PanicStrategy, TargetOptions};
//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()
//}
use std::default::Default;

pub fn opts() -> TargetOptions {
TargetOptions {
os: "l4re".to_string(),
env: "uclibc".to_string(),
linker_flavor: LinkerFlavor::Ld,
linker_flavor: LinkerFlavor::L4Bender,
executables: true,
panic_strategy: PanicStrategy::Abort,
linker: Some("ld".to_string()),
linker: Some("l4-bender".to_string()),
linker_is_gnu: false,
families: vec!["unix".to_string()],
..Default::default()
Expand Down
2 changes: 2 additions & 0 deletions compiler/rustc_target/src/spec/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -90,6 +90,7 @@ mod windows_uwp_msvc_base;
pub enum LinkerFlavor {
Em,
Gcc,
L4Bender,
Ld,
Msvc,
Lld(LldFlavor),
Expand Down Expand Up @@ -160,6 +161,7 @@ macro_rules! flavor_mappings {
flavor_mappings! {
((LinkerFlavor::Em), "em"),
((LinkerFlavor::Gcc), "gcc"),
((LinkerFlavor::L4Bender), "l4-bender"),
((LinkerFlavor::Ld), "ld"),
((LinkerFlavor::Msvc), "msvc"),
((LinkerFlavor::PtxLinker), "ptx-linker"),
Expand Down
5 changes: 4 additions & 1 deletion compiler/rustc_target/src/spec/x86_64_unknown_l4re_uclibc.rs
Original file line number Diff line number Diff line change
@@ -1,9 +1,12 @@
use crate::spec::Target;
use crate::spec::{PanicStrategy, Target};

pub fn target() -> Target {
let mut base = super::l4re_base::opts();
base.cpu = "x86-64".to_string();
base.max_atomic_width = Some(64);
base.crt_static_allows_dylibs = false;
base.dynamic_linking = false;
base.panic_strategy = PanicStrategy::Abort;

Target {
llvm_target: "x86_64-unknown-l4re-uclibc".to_string(),
Expand Down
4 changes: 4 additions & 0 deletions library/panic_unwind/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,10 @@ cfg_if::cfg_if! {
} else if #[cfg(target_os = "hermit")] {
#[path = "hermit.rs"]
mod real_imp;
} else if #[cfg(target_os = "l4re")] {
// L4Re is unix family but does not yet support unwinding.
#[path = "dummy.rs"]
mod real_imp;
} else if #[cfg(target_env = "msvc")] {
#[path = "seh.rs"]
mod real_imp;
Expand Down