Skip to content

Use more accurate ELF flags on MIPS #140634

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 2 commits into from
May 6, 2025
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
66 changes: 41 additions & 25 deletions compiler/rustc_codegen_ssa/src/back/metadata.rs
Original file line number Diff line number Diff line change
Expand Up @@ -270,45 +270,61 @@ pub(super) fn elf_os_abi(sess: &Session) -> u8 {

pub(super) fn elf_e_flags(architecture: Architecture, sess: &Session) -> u32 {
match architecture {
Architecture::Mips => {
let arch = match sess.target.options.cpu.as_ref() {
"mips1" => elf::EF_MIPS_ARCH_1,
"mips2" => elf::EF_MIPS_ARCH_2,
Architecture::Mips | Architecture::Mips64 | Architecture::Mips64_N32 => {
// "N32" indicates an "ILP32" data model on a 64-bit MIPS CPU
// like SPARC's "v8+", x86_64's "x32", or the watchOS "arm64_32".
let is_32bit = architecture == Architecture::Mips;
let mut e_flags = match sess.target.options.cpu.as_ref() {
"mips1" if is_32bit => elf::EF_MIPS_ARCH_1,
"mips2" if is_32bit => elf::EF_MIPS_ARCH_2,
"mips3" => elf::EF_MIPS_ARCH_3,
"mips4" => elf::EF_MIPS_ARCH_4,
"mips5" => elf::EF_MIPS_ARCH_5,
s if s.contains("r6") => elf::EF_MIPS_ARCH_32R6,
_ => elf::EF_MIPS_ARCH_32R2,
"mips32r2" if is_32bit => elf::EF_MIPS_ARCH_32R2,
"mips32r6" if is_32bit => elf::EF_MIPS_ARCH_32R6,
"mips64r2" if !is_32bit => elf::EF_MIPS_ARCH_64R2,
"mips64r6" if !is_32bit => elf::EF_MIPS_ARCH_64R6,
s if s.starts_with("mips32") && !is_32bit => {
sess.dcx().fatal(format!("invalid CPU `{}` for 64-bit MIPS target", s))
}
s if s.starts_with("mips64") && is_32bit => {
sess.dcx().fatal(format!("invalid CPU `{}` for 32-bit MIPS target", s))
}
_ if is_32bit => elf::EF_MIPS_ARCH_32R2,
_ => elf::EF_MIPS_ARCH_64R2,
};

let mut e_flags = elf::EF_MIPS_CPIC | arch;

// If the ABI is explicitly given, use it or default to O32.
match sess.target.options.llvm_abiname.to_lowercase().as_str() {
"n32" => e_flags |= elf::EF_MIPS_ABI2,
"o32" => e_flags |= elf::EF_MIPS_ABI_O32,
_ => e_flags |= elf::EF_MIPS_ABI_O32,
// If the ABI is explicitly given, use it, or default to O32 on 32-bit MIPS,
// which is the only "true" 32-bit option that LLVM supports.
match sess.target.options.llvm_abiname.as_ref() {
"o32" if is_32bit => e_flags |= elf::EF_MIPS_ABI_O32,
"n32" if !is_32bit => e_flags |= elf::EF_MIPS_ABI2,
"n64" if !is_32bit => {}
"" if is_32bit => e_flags |= elf::EF_MIPS_ABI_O32,
"" => sess.dcx().fatal("LLVM ABI must be specifed for 64-bit MIPS targets"),
s if is_32bit => {
sess.dcx().fatal(format!("invalid LLVM ABI `{}` for 32-bit MIPS target", s))
}
s => sess.dcx().fatal(format!("invalid LLVM ABI `{}` for 64-bit MIPS target", s)),
};

if sess.target.options.relocation_model != RelocModel::Static {
e_flags |= elf::EF_MIPS_PIC;
// PIC means position-independent code. CPIC means "calls PIC".
// CPIC was mutually exclusive with PIC according to
// the SVR4 MIPS ABI https://refspecs.linuxfoundation.org/elf/mipsabi.pdf
// and should have only appeared on static objects with dynamically calls.
// At some point someone (GCC?) decided to set CPIC even for PIC.
// Nowadays various things expect both set on the same object file
// and may even error if you mix CPIC and non-CPIC object files,
// despite that being the entire point of the CPIC ABI extension!
// As we are in Rome, we do as the Romans do.
e_flags |= elf::EF_MIPS_PIC | elf::EF_MIPS_CPIC;
}
if sess.target.options.cpu.contains("r6") {
e_flags |= elf::EF_MIPS_NAN2008;
}
e_flags
}
Architecture::Mips64 => {
// copied from `mips64el-linux-gnuabi64-gcc foo.c -c`
let e_flags = elf::EF_MIPS_CPIC
| elf::EF_MIPS_PIC
| if sess.target.options.cpu.contains("r6") {
elf::EF_MIPS_ARCH_64R6 | elf::EF_MIPS_NAN2008
} else {
elf::EF_MIPS_ARCH_64R2
};
e_flags
}
Architecture::Riscv32 | Architecture::Riscv64 => {
// Source: https://github.com/riscv-non-isa/riscv-elf-psabi-doc/blob/079772828bd10933d34121117a222b4cc0ee2200/riscv-elf.adoc
let mut e_flags: u32 = 0x0;
Expand Down
14 changes: 13 additions & 1 deletion compiler/rustc_target/src/spec/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3567,7 +3567,19 @@ impl Target {
"x86" => (Architecture::I386, None),
"s390x" => (Architecture::S390x, None),
"mips" | "mips32r6" => (Architecture::Mips, None),
"mips64" | "mips64r6" => (Architecture::Mips64, None),
"mips64" | "mips64r6" => (
// While there are currently no builtin targets
// using the N32 ABI, it is possible to specify
// it using a custom target specification. N32
// is an ILP32 ABI like the Aarch64_Ilp32
// and X86_64_X32 cases above and below this one.
if self.options.llvm_abiname.as_ref() == "n32" {
Architecture::Mips64_N32
} else {
Architecture::Mips64
},
None,
),
"x86_64" => (
if self.pointer_width == 32 {
Architecture::X86_64_X32
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ pub(crate) fn target() -> Target {
abi: "abi64".into(),
endian: Endian::Big,
mcount: "_mcount".into(),
llvm_abiname: "n64".into(),
..base
},
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ pub(crate) fn target() -> Target {
features: "+mips64r2,+xgot".into(),
max_atomic_width: Some(64),
mcount: "_mcount".into(),
llvm_abiname: "n64".into(),

..base::linux_gnu::opts()
},
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ pub(crate) fn target() -> Target {
mcount: "_mcount".into(),
// FIXME(compiler-team#422): musl targets should be dynamically linked by default.
crt_static_default: true,
llvm_abiname: "n64".into(),
..base
},
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ pub(crate) fn target() -> Target {
features: "+mips64r2,+xgot".into(),
max_atomic_width: Some(64),
mcount: "_mcount".into(),
llvm_abiname: "n64".into(),

..base::linux_gnu::opts()
},
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,11 @@ pub(crate) fn target() -> Target {
pointer_width: 64,
data_layout: "e-m:e-i8:8:32-i16:16:32-i64:64-i128:128-n32:64-S128".into(),
arch: "mips64".into(),
options: TargetOptions { abi: "abi64".into(), mcount: "_mcount".into(), ..base },
options: TargetOptions {
abi: "abi64".into(),
mcount: "_mcount".into(),
llvm_abiname: "n64".into(),
..base
},
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ pub(crate) fn target() -> Target {
features: "+mips64r6".into(),
max_atomic_width: Some(64),
mcount: "_mcount".into(),
llvm_abiname: "n64".into(),

..base::linux_gnu::opts()
},
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ pub(crate) fn target() -> Target {
features: "+mips64r6".into(),
max_atomic_width: Some(64),
mcount: "_mcount".into(),
llvm_abiname: "n64".into(),

..base::linux_gnu::opts()
},
Expand Down
Loading