about summary refs log tree commit diff
diff options
context:
space:
mode:
authorbors <bors@rust-lang.org>2022-05-13 08:48:31 +0000
committerbors <bors@rust-lang.org>2022-05-13 08:48:31 +0000
commit1c80ac003b59a2e708f127a721904e92ea51d0b9 (patch)
tree0f4b5d1b2571a2033d632344436cc6e5272a0a00
parent97d48bec2d2ac7e1aac807e1fe3e8341189db7da (diff)
parent3d5b1eeb7592da43442866d26af5e503c3169b6c (diff)
downloadrust-1c80ac003b59a2e708f127a721904e92ea51d0b9.tar.gz
rust-1c80ac003b59a2e708f127a721904e92ea51d0b9.zip
Auto merge of #96930 - ayrtonm:mips32-tmp-file, r=petrochenkov
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 is invalid for 32-bit MIPS targets. Even though symbols.o doesn't contain code, linking these targets with [lld fails](https://github.com/llvm/llvm-project/blob/main/lld/ELF/Arch/MipsArchTree.cpp#L76-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 [mipsel-sony-psx target](https://github.com/ayrtonm/psx-sdk-rs/issues/9), the builtin mipsel-sony-psp target (cc `@overdrivenpotato)` and probably 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 to avoid similar issues with the object file arch and PIC. 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.
-rw-r--r--Cargo.lock8
-rw-r--r--compiler/rustc_codegen_ssa/Cargo.toml2
-rw-r--r--compiler/rustc_codegen_ssa/src/back/metadata.rs28
3 files changed, 23 insertions, 15 deletions
diff --git a/Cargo.lock b/Cargo.lock
index f5aacba20cd..afe1814de67 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -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",
 ]
 
diff --git a/compiler/rustc_codegen_ssa/Cargo.toml b/compiler/rustc_codegen_ssa/Cargo.toml
index 87d0680bf6f..93b10a07e44 100644
--- a/compiler/rustc_codegen_ssa/Cargo.toml
+++ b/compiler/rustc_codegen_ssa/Cargo.toml
@@ -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"]
diff --git a/compiler/rustc_codegen_ssa/src/back/metadata.rs b/compiler/rustc_codegen_ssa/src/back/metadata.rs
index 2e422728056..6aa96f9f403 100644
--- a/compiler/rustc_codegen_ssa/src/back/metadata.rs
+++ b/compiler/rustc_codegen_ssa/src/back/metadata.rs
@@ -20,7 +20,7 @@ use rustc_metadata::EncodedMetadata;
 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 => {