From cca6a75eac74ab9d73213b9f715d3b50388d489b Mon Sep 17 00:00:00 2001 From: c272 Date: Thu, 9 May 2024 12:48:34 +0100 Subject: [PATCH] codegen(feat): Allow forced use of platform linker. bench(feat): Allow forced use of platform linker in benchmarks. --- crates/bench/src/cli.rs | 6 ++++++ crates/bench/src/runner.rs | 8 +++++++- crates/compiler/src/cli.rs | 4 ++++ crates/compiler/src/config.rs | 4 ++++ crates/compiler/src/linker/mod.rs | 2 +- crates/compiler/src/linker/platform.rs | 23 +++++++++++++++-------- crates/compiler/src/tests/common/mod.rs | 1 + 7 files changed, 38 insertions(+), 10 deletions(-) diff --git a/crates/bench/src/cli.rs b/crates/bench/src/cli.rs index 1aa6425..e2d0edb 100644 --- a/crates/bench/src/cli.rs +++ b/crates/bench/src/cli.rs @@ -24,6 +24,11 @@ pub struct Cli { #[arg(short = 'C', long, default_value_t = 3)] pub cobc_opt_level: u8, + /// Whether to force usage of the platform linker over other available + /// linkers when compiling with Cobalt. + #[arg(long, short = 'f', action)] + pub force_platform_linker: bool, + /// Whether to disable generation of hardware security instructions by /// Cobalt when generating benchmarking binaries. #[arg(long, short = 'h', action)] @@ -215,6 +220,7 @@ impl TryInto for Cli { compiler: cobalt_bin, cobalt_opt_level: opt_level, cobc_opt_level: self.cobc_opt_level, + cobc_force_platform_linker: self.force_platform_linker, disable_hw_security: self.disable_hw_security, run_comparative: self.run_comparative, build_only: self.build_only, diff --git a/crates/bench/src/runner.rs b/crates/bench/src/runner.rs index 46e39e4..66851f9 100644 --- a/crates/bench/src/runner.rs +++ b/crates/bench/src/runner.rs @@ -27,6 +27,9 @@ pub(crate) struct Cfg { /// The optimisation level to run `cobc` at when compiling. pub cobc_opt_level: u8, + /// Whether to force use of the platform linker when using `cobc`. + pub cobc_force_platform_linker: bool, + /// Whether to disable generating hardware security instructions /// when compiling sources with Cobalt. pub disable_hw_security: bool, @@ -90,6 +93,9 @@ fn run_cobalt(cfg: &Cfg, benchmark: &Benchmark) -> Result { .args(["--opt-level", &cfg.cobalt_opt_level]) .args(["--output-dir", cfg.output_dir.to_str().unwrap()]) .args(["--output-name", BENCH_BIN_NAME]); + if cfg.cobc_force_platform_linker { + cobalt.arg("--prefer-platform-linker"); + } if cfg.disable_hw_security { cobalt.arg("--disable-security-features"); } @@ -167,7 +173,7 @@ fn run_cobc(cfg: &Cfg, benchmark: &Benchmark) -> Result { } else { (None, None) }; - + Ok(BenchmarkResult { compile_time_total: elapsed, compile_time_avg: elapsed / 100, diff --git a/crates/compiler/src/cli.rs b/crates/compiler/src/cli.rs index a309911..a405a1f 100644 --- a/crates/compiler/src/cli.rs +++ b/crates/compiler/src/cli.rs @@ -49,6 +49,10 @@ pub struct BuildCommand { #[arg(short = 'O', long, value_parser = clap::builder::PossibleValuesParser::new(&["none", "speed", "speed_and_size"]))] pub opt_level: Option, + /// Actively selects the platform linker over other available linkers. + #[arg(short = 'p', long, action)] + pub prefer_platform_linker: bool, + /// Disables the generation of instructions utilising hardware security /// features within output binaries (e.g. PAC/BTI on aarch64). #[arg(long, action)] diff --git a/crates/compiler/src/config.rs b/crates/compiler/src/config.rs index 3e97d2f..7600c45 100644 --- a/crates/compiler/src/config.rs +++ b/crates/compiler/src/config.rs @@ -20,6 +20,9 @@ pub(crate) struct BuildConfig { /// The output linked executable file for this build. pub out_file: PathBuf, + /// Whether to use the platform linker over all others. + pub use_platform_linker: bool, + /// Whether to generate code with security features enabled. pub gen_security_features: bool, @@ -82,6 +85,7 @@ impl TryFrom for BuildConfig { input_file: cli.input.clone(), out_dir, out_file, + use_platform_linker: cli.prefer_platform_linker, gen_security_features: !cli.disable_security_features, opt_level, #[cfg(debug_assertions)] diff --git a/crates/compiler/src/linker/mod.rs b/crates/compiler/src/linker/mod.rs index 079a9b5..cd35af7 100644 --- a/crates/compiler/src/linker/mod.rs +++ b/crates/compiler/src/linker/mod.rs @@ -30,7 +30,7 @@ impl<'cfg> Linker<'cfg> { Ok(Linker { cfg, user_objects: Vec::new(), - platform_config: PlatformConfig::new()?, + platform_config: PlatformConfig::new(cfg)?, }) } diff --git a/crates/compiler/src/linker/platform.rs b/crates/compiler/src/linker/platform.rs index 636da27..703088d 100644 --- a/crates/compiler/src/linker/platform.rs +++ b/crates/compiler/src/linker/platform.rs @@ -7,6 +7,8 @@ use std::process::Command; use miette::Result; +use crate::config::BuildConfig; + /// Platform-specific linker configuration options. /// Typically auto-detected from the host machine. pub(super) struct PlatformConfig { @@ -42,11 +44,11 @@ impl LinkerType { impl PlatformConfig { /// Auto-detects the platform linker configuration from the host machine's setup. - pub(super) fn new() -> Result { + pub(super) fn new(cfg: &BuildConfig) -> Result { if env::consts::ARCH == "x86_64" && env::consts::OS == "linux" { - Self::detect_linux_x64() + Self::detect_linux_x64(cfg) } else if env::consts::ARCH == "aarch64" && env::consts::OS == "linux" { - Self::detect_linux_aarch64() + Self::detect_linux_aarch64(cfg) } else { miette::bail!( "Unsupported platform/architecture ({}, {}) for linker.", @@ -73,7 +75,7 @@ impl PlatformConfig { } /// Detects the linker configuration for an x86_64 Linux host. - fn detect_linux_x64() -> Result { + fn detect_linux_x64(cfg: &BuildConfig) -> Result { // Sanity check that the crt, loader exist. let crt = PathBuf::from("/usr/lib/x86_64-linux-gnu/crt1.o"); let loader = PathBuf::from("/lib64/ld-linux-x86-64.so.2"); @@ -91,7 +93,7 @@ impl PlatformConfig { } Ok(PlatformConfig { - linker_type: Self::detect_best_linker(), + linker_type: Self::detect_best_linker(cfg), crt1_o: crt, dyn_linker: Some(loader), lib_paths: Vec::new(), @@ -99,7 +101,7 @@ impl PlatformConfig { } /// Detects the linker configuration for an aarch64 Linux host. - fn detect_linux_aarch64() -> Result { + fn detect_linux_aarch64(cfg: &BuildConfig) -> Result { // Sanity check that the crt, loader exist. let crt = PathBuf::from("/usr/lib64/crt1.o"); let loader = PathBuf::from("/usr/lib/ld-linux-aarch64.so.1"); @@ -117,7 +119,7 @@ impl PlatformConfig { } Ok(PlatformConfig { - linker_type: Self::detect_best_linker(), + linker_type: Self::detect_best_linker(cfg), crt1_o: crt, dyn_linker: Some(loader), lib_paths: Vec::new(), @@ -125,7 +127,12 @@ impl PlatformConfig { } /// Detects the best linker for use on the host system. - fn detect_best_linker() -> LinkerType { + fn detect_best_linker(cfg: &BuildConfig) -> LinkerType { + // If we need to always prefer the platform linker, we're done. + if cfg.use_platform_linker { + return LinkerType::GnuLd; + } + // If `mold` is present, use that instead for increased performance. if Command::new("mold").spawn().is_ok() { LinkerType::Mold diff --git a/crates/compiler/src/tests/common/mod.rs b/crates/compiler/src/tests/common/mod.rs index 870c517..fd0a43d 100644 --- a/crates/compiler/src/tests/common/mod.rs +++ b/crates/compiler/src/tests/common/mod.rs @@ -104,6 +104,7 @@ impl CommonTestRunner { input_file: PathBuf::from_str(&self.name).unwrap(), out_dir: out_dir.clone(), out_file, + use_platform_linker: false, gen_security_features: true, opt_level: "none".into(), output_ast: false,