diff --git a/compiler/rustc_codegen_ssa/src/back/metadata.rs b/compiler/rustc_codegen_ssa/src/back/metadata.rs index d70413b8a4741..236507ac0cd28 100644 --- a/compiler/rustc_codegen_ssa/src/back/metadata.rs +++ b/compiler/rustc_codegen_ssa/src/back/metadata.rs @@ -252,15 +252,7 @@ pub(crate) fn create_object_file(sess: &Session) -> Option return None, }; - let binary_format = if sess.target.is_like_osx { - BinaryFormat::MachO - } else if sess.target.is_like_windows { - BinaryFormat::Coff - } else if sess.target.is_like_aix { - BinaryFormat::Xcoff - } else { - BinaryFormat::Elf - }; + let binary_format = sess.target.binary_format.to_object(); let mut file = write::Object::new(binary_format, architecture, endianness); file.set_sub_architecture(sub_architecture); diff --git a/compiler/rustc_codegen_ssa/src/mir/naked_asm.rs b/compiler/rustc_codegen_ssa/src/mir/naked_asm.rs index eb0711dbb32ff..0593fb420c306 100644 --- a/compiler/rustc_codegen_ssa/src/mir/naked_asm.rs +++ b/compiler/rustc_codegen_ssa/src/mir/naked_asm.rs @@ -8,7 +8,7 @@ use rustc_middle::ty::{Instance, Ty, TyCtxt}; use rustc_middle::{bug, span_bug, ty}; use rustc_span::sym; use rustc_target::callconv::{ArgAbi, FnAbi, PassMode}; -use rustc_target::spec::WasmCAbi; +use rustc_target::spec::{BinaryFormat, WasmCAbi}; use crate::common; use crate::traits::{AsmCodegenMethods, BuilderMethods, GlobalAsmOperandRef, MiscCodegenMethods}; @@ -104,27 +104,6 @@ fn inline_to_global_operand<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>( } } -enum AsmBinaryFormat { - Elf, - Macho, - Coff, - Wasm, -} - -impl AsmBinaryFormat { - fn from_target(target: &rustc_target::spec::Target) -> Self { - if target.is_like_windows { - Self::Coff - } else if target.is_like_osx { - Self::Macho - } else if target.is_like_wasm { - Self::Wasm - } else { - Self::Elf - } - } -} - fn prefix_and_suffix<'tcx>( tcx: TyCtxt<'tcx>, instance: Instance<'tcx>, @@ -134,7 +113,7 @@ fn prefix_and_suffix<'tcx>( ) -> (String, String) { use std::fmt::Write; - let asm_binary_format = AsmBinaryFormat::from_target(&tcx.sess.target); + let asm_binary_format = &tcx.sess.target.binary_format; let is_arm = tcx.sess.target.arch == "arm"; let is_thumb = tcx.sess.unstable_target_features.contains(&sym::thumb_mode); @@ -178,10 +157,13 @@ fn prefix_and_suffix<'tcx>( } Linkage::LinkOnceAny | Linkage::LinkOnceODR | Linkage::WeakAny | Linkage::WeakODR => { match asm_binary_format { - AsmBinaryFormat::Elf | AsmBinaryFormat::Coff | AsmBinaryFormat::Wasm => { + BinaryFormat::Elf + | BinaryFormat::Coff + | BinaryFormat::Wasm + | BinaryFormat::Xcoff => { writeln!(w, ".weak {asm_name}")?; } - AsmBinaryFormat::Macho => { + BinaryFormat::MachO => { writeln!(w, ".globl {asm_name}")?; writeln!(w, ".weak_definition {asm_name}")?; } @@ -207,7 +189,7 @@ fn prefix_and_suffix<'tcx>( let mut begin = String::new(); let mut end = String::new(); match asm_binary_format { - AsmBinaryFormat::Elf => { + BinaryFormat::Elf | BinaryFormat::Xcoff => { let section = link_section.unwrap_or(format!(".text.{asm_name}")); let progbits = match is_arm { @@ -239,7 +221,7 @@ fn prefix_and_suffix<'tcx>( writeln!(end, "{}", arch_suffix).unwrap(); } } - AsmBinaryFormat::Macho => { + BinaryFormat::MachO => { let section = link_section.unwrap_or("__TEXT,__text".to_string()); writeln!(begin, ".pushsection {},regular,pure_instructions", section).unwrap(); writeln!(begin, ".balign {align}").unwrap(); @@ -255,7 +237,7 @@ fn prefix_and_suffix<'tcx>( writeln!(end, "{}", arch_suffix).unwrap(); } } - AsmBinaryFormat::Coff => { + BinaryFormat::Coff => { let section = link_section.unwrap_or(format!(".text.{asm_name}")); writeln!(begin, ".pushsection {},\"xr\"", section).unwrap(); writeln!(begin, ".balign {align}").unwrap(); @@ -272,7 +254,7 @@ fn prefix_and_suffix<'tcx>( writeln!(end, "{}", arch_suffix).unwrap(); } } - AsmBinaryFormat::Wasm => { + BinaryFormat::Wasm => { let section = link_section.unwrap_or(format!(".text.{asm_name}")); writeln!(begin, ".section {section},\"\",@").unwrap(); diff --git a/compiler/rustc_target/src/spec/base/aix.rs b/compiler/rustc_target/src/spec/base/aix.rs index a92d104f9108e..aa42b4d1c5027 100644 --- a/compiler/rustc_target/src/spec/base/aix.rs +++ b/compiler/rustc_target/src/spec/base/aix.rs @@ -1,6 +1,8 @@ use rustc_abi::Endian; -use crate::spec::{Cc, CodeModel, LinkOutputKind, LinkerFlavor, TargetOptions, crt_objects, cvs}; +use crate::spec::{ + BinaryFormat, Cc, CodeModel, LinkOutputKind, LinkerFlavor, TargetOptions, crt_objects, cvs, +}; pub(crate) fn opts() -> TargetOptions { TargetOptions { @@ -21,6 +23,7 @@ pub(crate) fn opts() -> TargetOptions { linker: Some("ld".into()), eh_frame_header: false, is_like_aix: true, + binary_format: BinaryFormat::Xcoff, default_dwarf_version: 3, function_sections: true, pre_link_objects: crt_objects::new(&[ diff --git a/compiler/rustc_target/src/spec/base/apple/mod.rs b/compiler/rustc_target/src/spec/base/apple/mod.rs index 1b56143545f61..66c85146c2944 100644 --- a/compiler/rustc_target/src/spec/base/apple/mod.rs +++ b/compiler/rustc_target/src/spec/base/apple/mod.rs @@ -2,8 +2,8 @@ use std::borrow::Cow; use std::env; use crate::spec::{ - Cc, DebuginfoKind, FloatAbi, FramePointer, LinkerFlavor, Lld, RustcAbi, SplitDebuginfo, - StackProbeType, StaticCow, TargetOptions, cvs, + BinaryFormat, Cc, DebuginfoKind, FloatAbi, FramePointer, LinkerFlavor, Lld, RustcAbi, + SplitDebuginfo, StackProbeType, StaticCow, TargetOptions, cvs, }; #[cfg(test)] @@ -116,6 +116,7 @@ pub(crate) fn base( dynamic_linking: true, families: cvs!["unix"], is_like_osx: true, + binary_format: BinaryFormat::MachO, // LLVM notes that macOS 10.11+ and iOS 9+ default // to v4, so we do the same. // https://github.com/llvm/llvm-project/blob/378778a0d10c2f8d5df8ceff81f95b6002984a4b/clang/lib/Driver/ToolChains/Darwin.cpp#L1203 diff --git a/compiler/rustc_target/src/spec/base/cygwin.rs b/compiler/rustc_target/src/spec/base/cygwin.rs index fe3efb3f46ba0..819d1d68a71d9 100644 --- a/compiler/rustc_target/src/spec/base/cygwin.rs +++ b/compiler/rustc_target/src/spec/base/cygwin.rs @@ -1,6 +1,8 @@ use std::borrow::Cow; -use crate::spec::{Cc, DebuginfoKind, LinkerFlavor, Lld, SplitDebuginfo, TargetOptions, cvs}; +use crate::spec::{ + BinaryFormat, Cc, DebuginfoKind, LinkerFlavor, Lld, SplitDebuginfo, TargetOptions, cvs, +}; pub(crate) fn opts() -> TargetOptions { let mut pre_link_args = TargetOptions::link_args( @@ -32,6 +34,7 @@ pub(crate) fn opts() -> TargetOptions { exe_suffix: ".exe".into(), families: cvs!["unix"], is_like_windows: true, + binary_format: BinaryFormat::Coff, allows_weak_linkage: false, pre_link_args, late_link_args, diff --git a/compiler/rustc_target/src/spec/base/msvc.rs b/compiler/rustc_target/src/spec/base/msvc.rs index b0fb2ef4b27f2..486d7158723f8 100644 --- a/compiler/rustc_target/src/spec/base/msvc.rs +++ b/compiler/rustc_target/src/spec/base/msvc.rs @@ -1,6 +1,6 @@ use std::borrow::Cow; -use crate::spec::{DebuginfoKind, LinkerFlavor, Lld, SplitDebuginfo, TargetOptions}; +use crate::spec::{BinaryFormat, DebuginfoKind, LinkerFlavor, Lld, SplitDebuginfo, TargetOptions}; pub(crate) fn opts() -> TargetOptions { // Suppress the verbose logo and authorship debugging output, which would needlessly @@ -12,6 +12,7 @@ pub(crate) fn opts() -> TargetOptions { dll_tls_export: false, is_like_windows: true, is_like_msvc: true, + binary_format: BinaryFormat::Coff, pre_link_args, abi_return_struct_as_int: true, emit_debug_gdb_scripts: false, diff --git a/compiler/rustc_target/src/spec/base/wasm.rs b/compiler/rustc_target/src/spec/base/wasm.rs index 81b96cd39ffac..88e7af5e66978 100644 --- a/compiler/rustc_target/src/spec/base/wasm.rs +++ b/compiler/rustc_target/src/spec/base/wasm.rs @@ -1,6 +1,6 @@ use crate::spec::{ - Cc, LinkSelfContainedDefault, LinkerFlavor, PanicStrategy, RelocModel, TargetOptions, TlsModel, - add_link_args, cvs, + BinaryFormat, Cc, LinkSelfContainedDefault, LinkerFlavor, PanicStrategy, RelocModel, + TargetOptions, TlsModel, add_link_args, cvs, }; pub(crate) fn options() -> TargetOptions { @@ -53,6 +53,7 @@ pub(crate) fn options() -> TargetOptions { TargetOptions { is_like_wasm: true, + binary_format: BinaryFormat::Wasm, families: cvs!["wasm"], // we allow dynamic linking, but only cdylibs. Basically we allow a diff --git a/compiler/rustc_target/src/spec/base/windows_gnu.rs b/compiler/rustc_target/src/spec/base/windows_gnu.rs index 024b10f2faad7..4ba1102198847 100644 --- a/compiler/rustc_target/src/spec/base/windows_gnu.rs +++ b/compiler/rustc_target/src/spec/base/windows_gnu.rs @@ -1,8 +1,8 @@ use std::borrow::Cow; use crate::spec::{ - Cc, DebuginfoKind, LinkSelfContainedDefault, LinkerFlavor, Lld, SplitDebuginfo, TargetOptions, - add_link_args, crt_objects, cvs, + BinaryFormat, Cc, DebuginfoKind, LinkSelfContainedDefault, LinkerFlavor, Lld, SplitDebuginfo, + TargetOptions, add_link_args, crt_objects, cvs, }; pub(crate) fn opts() -> TargetOptions { @@ -90,6 +90,7 @@ pub(crate) fn opts() -> TargetOptions { exe_suffix: ".exe".into(), families: cvs!["windows"], is_like_windows: true, + binary_format: BinaryFormat::Coff, allows_weak_linkage: false, pre_link_args, pre_link_objects: crt_objects::pre_mingw(), diff --git a/compiler/rustc_target/src/spec/base/windows_gnullvm.rs b/compiler/rustc_target/src/spec/base/windows_gnullvm.rs index 4a6e7c75200f6..f24ad781e2b81 100644 --- a/compiler/rustc_target/src/spec/base/windows_gnullvm.rs +++ b/compiler/rustc_target/src/spec/base/windows_gnullvm.rs @@ -1,6 +1,8 @@ use std::borrow::Cow; -use crate::spec::{Cc, DebuginfoKind, LinkerFlavor, Lld, SplitDebuginfo, TargetOptions, cvs}; +use crate::spec::{ + BinaryFormat, Cc, DebuginfoKind, LinkerFlavor, Lld, SplitDebuginfo, TargetOptions, cvs, +}; pub(crate) fn opts() -> TargetOptions { // We cannot use `-nodefaultlibs` because compiler-rt has to be passed @@ -30,6 +32,7 @@ pub(crate) fn opts() -> TargetOptions { exe_suffix: ".exe".into(), families: cvs!["windows"], is_like_windows: true, + binary_format: BinaryFormat::Coff, allows_weak_linkage: false, pre_link_args, late_link_args, diff --git a/compiler/rustc_target/src/spec/json.rs b/compiler/rustc_target/src/spec/json.rs index f703132e51f0a..134405f3630e7 100644 --- a/compiler/rustc_target/src/spec/json.rs +++ b/compiler/rustc_target/src/spec/json.rs @@ -103,6 +103,19 @@ impl Target { base.$key_name = Some(s); } } ); + ($key_name:ident, BinaryFormat) => ( { + let name = (stringify!($key_name)).replace("_", "-"); + obj.remove(&name).and_then(|f| f.as_str().and_then(|s| { + match s.parse::() { + Ok(binary_format) => base.$key_name = binary_format, + _ => return Some(Err(format!( + "'{s}' is not a valid value for binary_format. \ + Use 'coff', 'elf', 'mach-o', 'wasm' or 'xcoff' " + ))), + } + Some(Ok(())) + })).unwrap_or(Ok(())) + } ); ($key_name:ident, MergeFunctions) => ( { let name = (stringify!($key_name)).replace("_", "-"); obj.remove(&name).and_then(|o| o.as_str().and_then(|s| { @@ -585,6 +598,7 @@ impl Target { key!(is_like_msvc, bool); key!(is_like_wasm, bool); key!(is_like_android, bool); + key!(binary_format, BinaryFormat)?; key!(default_dwarf_version, u32); key!(allows_weak_linkage, bool); key!(has_rpath, bool); @@ -762,6 +776,7 @@ impl ToJson for Target { target_option_val!(is_like_msvc); target_option_val!(is_like_wasm); target_option_val!(is_like_android); + target_option_val!(binary_format); target_option_val!(default_dwarf_version); target_option_val!(allows_weak_linkage); target_option_val!(has_rpath); diff --git a/compiler/rustc_target/src/spec/mod.rs b/compiler/rustc_target/src/spec/mod.rs index 794d6457cb78b..f40af2dce266d 100644 --- a/compiler/rustc_target/src/spec/mod.rs +++ b/compiler/rustc_target/src/spec/mod.rs @@ -1640,6 +1640,55 @@ impl fmt::Display for StackProtector { } } +#[derive(PartialEq, Clone, Debug)] +pub enum BinaryFormat { + Coff, + Elf, + MachO, + Wasm, + Xcoff, +} + +impl BinaryFormat { + /// Returns [`object::BinaryFormat`] for given `BinaryFormat` + pub fn to_object(&self) -> object::BinaryFormat { + match self { + Self::Coff => object::BinaryFormat::Coff, + Self::Elf => object::BinaryFormat::Elf, + Self::MachO => object::BinaryFormat::MachO, + Self::Wasm => object::BinaryFormat::Wasm, + Self::Xcoff => object::BinaryFormat::Xcoff, + } + } +} + +impl FromStr for BinaryFormat { + type Err = (); + fn from_str(s: &str) -> Result { + match s { + "coff" => Ok(Self::Coff), + "elf" => Ok(Self::Elf), + "mach-o" => Ok(Self::MachO), + "wasm" => Ok(Self::Wasm), + "xcoff" => Ok(Self::Xcoff), + _ => Err(()), + } + } +} + +impl ToJson for BinaryFormat { + fn to_json(&self) -> Json { + match self { + Self::Coff => "coff", + Self::Elf => "elf", + Self::MachO => "mach-o", + Self::Wasm => "wasm", + Self::Xcoff => "xcoff", + } + .to_json() + } +} + macro_rules! supported_targets { ( $(($tuple:literal, $module:ident),)+ ) => { mod targets { @@ -2369,6 +2418,8 @@ pub struct TargetOptions { pub is_like_wasm: bool, /// Whether a target toolchain is like Android, implying a Linux kernel and a Bionic libc pub is_like_android: bool, + /// Target's binary file format. Defaults to BinaryFormat::Elf + pub binary_format: BinaryFormat, /// Default supported version of DWARF on this platform. /// Useful because some platforms (osx, bsd) only want up to DWARF2. pub default_dwarf_version: u32, @@ -2744,6 +2795,7 @@ impl Default for TargetOptions { is_like_msvc: false, is_like_wasm: false, is_like_android: false, + binary_format: BinaryFormat::Elf, default_dwarf_version: 4, allows_weak_linkage: true, has_rpath: false,