Fix e_flags for 32-bit MIPS targets in generated object file

In #95604 the compiler started generating a temporary symbols.o which is added
to the linker invocation. This object file has an `e_flags` which may be invalid
for 32-bit MIPS targets. Even though symbols.o doesn't contain code, linking
    with [lld fails](https://github.com/llvm/llvm-project/blob/main/lld/ELF/Arch/MipsArchTree.cpp#L79) with
```
rust-lld: error: foo-cgu.0.rcgu.o: ABI 'o32' is incompatible with target ABI 'n64'
```
because it omits the ABI bits (EF_MIPS_ABI_O32) so lld assumes it's using the
N64 ABI. This breaks linking on nightly for the out-of-tree [psx
target](https://github.com/ayrtonm/psx-sdk-rs/issues/9), the builtin
mipsel-sony-psp target (cc @overdrivenpotato) and any other 32-bit MIPS
target using lld.

This PR sets the ABI in `e_flags` to O32 since that's the only ABI for 32-bit
MIPS that LLVM supports. It also sets other `e_flags` bits based on the target.
I had to bump the object crate version since some of these constants were [added
recently](https://github.com/gimli-rs/object/pull/433). I'm not sure if this
PR needs a test, but I can confirm that it fixes the linking issue on both
targets I mentioned.
This commit is contained in:
Ayrton 2022-05-01 21:45:50 -04:00
parent ecd44958e0
commit 3d5b1eeb75
3 changed files with 23 additions and 15 deletions

View File

@ -2509,9 +2509,9 @@ dependencies = [
[[package]]
name = "object"
version = "0.28.1"
version = "0.28.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7ce8b38d41f9f3618fc23f908faae61510f8d8ce2d99cbe910641e8f1971f084"
checksum = "e42c982f2d955fac81dd7e1d0e1426a7d702acd9c98d19ab01083a6a0328c424"
dependencies = [
"crc32fast",
"flate2",
@ -3617,7 +3617,7 @@ dependencies = [
"itertools",
"jobserver",
"libc",
"object 0.28.1",
"object 0.28.4",
"pathdiff",
"regex",
"rustc_apfloat",
@ -5207,7 +5207,7 @@ checksum = "dd95b4559c196987c8451b4e14d08a4c796c2844f9adf4d2a2dbc9b3142843be"
dependencies = [
"gimli 0.26.1",
"hashbrown 0.11.2",
"object 0.28.1",
"object 0.28.4",
"tracing",
]

View File

@ -41,6 +41,6 @@ rustc_target = { path = "../rustc_target" }
rustc_session = { path = "../rustc_session" }
[dependencies.object]
version = "0.28.0"
version = "0.28.4"
default-features = false
features = ["read_core", "elf", "macho", "pe", "unaligned", "archive", "write"]

View File

@ -20,7 +20,7 @@
use rustc_session::cstore::MetadataLoader;
use rustc_session::Session;
use rustc_target::abi::Endian;
use rustc_target::spec::Target;
use rustc_target::spec::{RelocModel, Target};
use crate::METADATA_FILENAME;
@ -132,15 +132,23 @@ pub(crate) fn create_object_file(sess: &Session) -> Option<write::Object<'static
let mut file = write::Object::new(binary_format, architecture, endianness);
match architecture {
Architecture::Mips => {
// copied from `mipsel-linux-gnu-gcc foo.c -c` and
// inspecting the resulting `e_flags` field.
let e_flags = elf::EF_MIPS_CPIC
| elf::EF_MIPS_PIC
| if sess.target.options.cpu.contains("r6") {
elf::EF_MIPS_ARCH_32R6 | elf::EF_MIPS_NAN2008
} else {
elf::EF_MIPS_ARCH_32R2
};
let arch = match sess.target.options.cpu.as_ref() {
"mips1" => elf::EF_MIPS_ARCH_1,
"mips2" => 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,
};
// The only ABI LLVM supports for 32-bit MIPS CPUs is o32.
let mut e_flags = elf::EF_MIPS_CPIC | elf::EF_MIPS_ABI_O32 | arch;
if sess.target.options.relocation_model != RelocModel::Static {
e_flags |= elf::EF_MIPS_PIC;
}
if sess.target.options.cpu.contains("r6") {
e_flags |= elf::EF_MIPS_NAN2008;
}
file.flags = FileFlags::Elf { e_flags };
}
Architecture::Mips64 => {