about summary refs log tree commit diff
diff options
context:
space:
mode:
authorJubilee <workingjubilee@gmail.com>2025-06-17 00:28:20 -0700
committerGitHub <noreply@github.com>2025-06-17 00:28:20 -0700
commit38000833992f90ab20713a6ad0af48e898737b64 (patch)
treefe8485d2fff66d9c6be64d0baf092dc7091dacaa
parent99c8475e529bfbaf738b12276431fe14d2e98bc3 (diff)
parent9c1180b6238d163fc384d60d85647385d9210343 (diff)
downloadrust-38000833992f90ab20713a6ad0af48e898737b64.tar.gz
rust-38000833992f90ab20713a6ad0af48e898737b64.zip
Rollup merge of #142598 - ostylk:fix/ppc64_llvmabi, r=nikic,workingjubilee
Set elf e_flags on ppc64 targets according to abi

(This PR contains the non user-facing changes of https://github.com/rust-lang/rust/pull/142321)

Fixes https://github.com/rust-lang/rust/issues/85589 by making sure that ld.lld errors out instead of generating a broken binary.

Basically the problem is that ld.lld assumes that all ppc64 object files with e_flags=0 are object files which use the ELFv2 ABI (this here is the check https://github.com/llvm/llvm-project/blob/main/lld/ELF/Arch/PPC64.cpp#L639).
This pull request sets the correct e_flags to indicate the used ABI so ld.lld errors out when encountering ELFv1 ABI files instead of generating a broken binary.

For example compare code generation for this program (file name ``min.rs``):
```rust
#![feature(no_core, lang_items, repr_simd)]
#![crate_type = "bin"]
#![no_core]
#![no_main]

#[lang = "sized"]
trait Sized {}
#[lang = "copy"]
trait Copy {}
#[lang = "panic_cannot_unwind"]
pub fn panic() -> ! {
    loop {}
}

pub fn my_rad_unmangled_function() {
    loop {}
}

pub fn my_rad_function() {
    loop {}
}

#[no_mangle]
pub fn _start() {
    my_rad_unmangled_function();
    my_rad_function();
}
```
Compile with ``rustc --target=powerpc64-unknown-linux-gnu -C linker=ld.lld -C relocation-model=static min.rs``

Before change:
```
$ llvm-objdump -d min
Disassembly of section .text:
000000001001030c <.text>:
		...
10010334: 7c 08 02 a6  	mflr 0
10010338: f8 21 ff 91  	stdu 1, -112(1)
1001033c: f8 01 00 80  	std 0, 128(1)
10010340: 48 02 00 39  	bl 0x10030378 <_ZN3min25my_rad_unmangled_function17h7471c49af58039f5E>
10010344: 60 00 00 00  	nop
10010348: 48 02 00 49  	bl 0x10030390 <_ZN3min15my_rad_function17h37112b8fd1008c9bE>
1001034c: 60 00 00 00  	nop
		...
```
The branch instructions ``bl 0x10030378`` and ``bl 0x10030390`` are jumping into the ``.opd`` section which is data. That is a broken binary (because fixing those branches is the task of the linker).

After change:
```
error: linking with `ld.lld` failed: exit status: 1
  |
  = note:  "ld.lld" "/tmp/rustcNYKZCS/symbols.o" "<1 object files omitted>" "--as-needed" "-L" "/tmp/rustcNYKZCS/raw-dylibs" "-Bdynamic" "--eh-frame-hdr" "-z" "noexecstack" "-L" "<sysroot>/lib/rustlib/powerpc64-unknown-linux-gnu/lib" "-o" "min" "--gc-sections" "-z" "relro" "-z" "now"
  = note: some arguments are omitted. use `--verbose` to show all linker arguments
  = note: ld.lld: error: /tmp/rustcNYKZCS/symbols.o: ABI version 1 is not supported
```
Which is correct because ld.lld doesn't support ELFv1 ABI.
-rw-r--r--compiler/rustc_codegen_ssa/src/back/metadata.rs18
-rw-r--r--compiler/rustc_target/src/spec/targets/powerpc64_unknown_freebsd.rs1
-rw-r--r--compiler/rustc_target/src/spec/targets/powerpc64_unknown_linux_gnu.rs1
-rw-r--r--compiler/rustc_target/src/spec/targets/powerpc64_unknown_linux_musl.rs1
-rw-r--r--compiler/rustc_target/src/spec/targets/powerpc64_unknown_openbsd.rs1
-rw-r--r--compiler/rustc_target/src/spec/targets/powerpc64_wrs_vxworks.rs1
-rw-r--r--compiler/rustc_target/src/spec/targets/powerpc64le_unknown_freebsd.rs1
-rw-r--r--compiler/rustc_target/src/spec/targets/powerpc64le_unknown_linux_gnu.rs1
-rw-r--r--compiler/rustc_target/src/spec/targets/powerpc64le_unknown_linux_musl.rs1
9 files changed, 26 insertions, 0 deletions
diff --git a/compiler/rustc_codegen_ssa/src/back/metadata.rs b/compiler/rustc_codegen_ssa/src/back/metadata.rs
index a16862c41ee..d091c46d9c1 100644
--- a/compiler/rustc_codegen_ssa/src/back/metadata.rs
+++ b/compiler/rustc_codegen_ssa/src/back/metadata.rs
@@ -379,6 +379,24 @@ pub(super) fn elf_e_flags(architecture: Architecture, sess: &Session) -> u32 {
             };
             e_flags
         }
+        Architecture::PowerPc64 => {
+            const EF_PPC64_ABI_UNKNOWN: u32 = 0;
+            const EF_PPC64_ABI_ELF_V1: u32 = 1;
+            const EF_PPC64_ABI_ELF_V2: u32 = 2;
+
+            match sess.target.options.llvm_abiname.as_ref() {
+                // If the flags do not correctly indicate the ABI,
+                // linkers such as ld.lld assume that the ppc64 object files are always ELFv2
+                // which leads to broken binaries if ELFv1 is used for the object files.
+                "elfv1" => EF_PPC64_ABI_ELF_V1,
+                "elfv2" => EF_PPC64_ABI_ELF_V2,
+                "" if sess.target.options.binary_format.to_object() == BinaryFormat::Elf => {
+                    bug!("No ABI specified for this PPC64 ELF target");
+                }
+                // Fall back
+                _ => EF_PPC64_ABI_UNKNOWN,
+            }
+        }
         _ => 0,
     }
 }
diff --git a/compiler/rustc_target/src/spec/targets/powerpc64_unknown_freebsd.rs b/compiler/rustc_target/src/spec/targets/powerpc64_unknown_freebsd.rs
index dba45776c94..66733d5d4b8 100644
--- a/compiler/rustc_target/src/spec/targets/powerpc64_unknown_freebsd.rs
+++ b/compiler/rustc_target/src/spec/targets/powerpc64_unknown_freebsd.rs
@@ -10,6 +10,7 @@ pub(crate) fn target() -> Target {
     base.add_pre_link_args(LinkerFlavor::Gnu(Cc::Yes, Lld::No), &["-m64"]);
     base.max_atomic_width = Some(64);
     base.stack_probes = StackProbeType::Inline;
+    base.llvm_abiname = "elfv2".into();
 
     Target {
         llvm_target: "powerpc64-unknown-freebsd".into(),
diff --git a/compiler/rustc_target/src/spec/targets/powerpc64_unknown_linux_gnu.rs b/compiler/rustc_target/src/spec/targets/powerpc64_unknown_linux_gnu.rs
index 1f67bc7f3c2..ecf68ddff8c 100644
--- a/compiler/rustc_target/src/spec/targets/powerpc64_unknown_linux_gnu.rs
+++ b/compiler/rustc_target/src/spec/targets/powerpc64_unknown_linux_gnu.rs
@@ -10,6 +10,7 @@ pub(crate) fn target() -> Target {
     base.add_pre_link_args(LinkerFlavor::Gnu(Cc::Yes, Lld::No), &["-m64"]);
     base.max_atomic_width = Some(64);
     base.stack_probes = StackProbeType::Inline;
+    base.llvm_abiname = "elfv1".into();
 
     Target {
         llvm_target: "powerpc64-unknown-linux-gnu".into(),
diff --git a/compiler/rustc_target/src/spec/targets/powerpc64_unknown_linux_musl.rs b/compiler/rustc_target/src/spec/targets/powerpc64_unknown_linux_musl.rs
index 49413d27a45..e205aef8285 100644
--- a/compiler/rustc_target/src/spec/targets/powerpc64_unknown_linux_musl.rs
+++ b/compiler/rustc_target/src/spec/targets/powerpc64_unknown_linux_musl.rs
@@ -12,6 +12,7 @@ pub(crate) fn target() -> Target {
     base.stack_probes = StackProbeType::Inline;
     // FIXME(compiler-team#422): musl targets should be dynamically linked by default.
     base.crt_static_default = true;
+    base.llvm_abiname = "elfv2".into();
 
     Target {
         llvm_target: "powerpc64-unknown-linux-musl".into(),
diff --git a/compiler/rustc_target/src/spec/targets/powerpc64_unknown_openbsd.rs b/compiler/rustc_target/src/spec/targets/powerpc64_unknown_openbsd.rs
index f5ca54291c6..bcb328020ee 100644
--- a/compiler/rustc_target/src/spec/targets/powerpc64_unknown_openbsd.rs
+++ b/compiler/rustc_target/src/spec/targets/powerpc64_unknown_openbsd.rs
@@ -10,6 +10,7 @@ pub(crate) fn target() -> Target {
     base.add_pre_link_args(LinkerFlavor::Gnu(Cc::Yes, Lld::No), &["-m64"]);
     base.max_atomic_width = Some(64);
     base.stack_probes = StackProbeType::Inline;
+    base.llvm_abiname = "elfv2".into();
 
     Target {
         llvm_target: "powerpc64-unknown-openbsd".into(),
diff --git a/compiler/rustc_target/src/spec/targets/powerpc64_wrs_vxworks.rs b/compiler/rustc_target/src/spec/targets/powerpc64_wrs_vxworks.rs
index 3e4a58f568a..37c888ba514 100644
--- a/compiler/rustc_target/src/spec/targets/powerpc64_wrs_vxworks.rs
+++ b/compiler/rustc_target/src/spec/targets/powerpc64_wrs_vxworks.rs
@@ -10,6 +10,7 @@ pub(crate) fn target() -> Target {
     base.add_pre_link_args(LinkerFlavor::Gnu(Cc::Yes, Lld::No), &["-m64"]);
     base.max_atomic_width = Some(64);
     base.stack_probes = StackProbeType::Inline;
+    base.llvm_abiname = "elfv1".into();
 
     Target {
         llvm_target: "powerpc64-unknown-linux-gnu".into(),
diff --git a/compiler/rustc_target/src/spec/targets/powerpc64le_unknown_freebsd.rs b/compiler/rustc_target/src/spec/targets/powerpc64le_unknown_freebsd.rs
index 4640d537e8e..3096c4d14ad 100644
--- a/compiler/rustc_target/src/spec/targets/powerpc64le_unknown_freebsd.rs
+++ b/compiler/rustc_target/src/spec/targets/powerpc64le_unknown_freebsd.rs
@@ -8,6 +8,7 @@ pub(crate) fn target() -> Target {
     base.add_pre_link_args(LinkerFlavor::Gnu(Cc::Yes, Lld::No), &["-m64"]);
     base.max_atomic_width = Some(64);
     base.stack_probes = StackProbeType::Inline;
+    base.llvm_abiname = "elfv2".into();
 
     Target {
         llvm_target: "powerpc64le-unknown-freebsd".into(),
diff --git a/compiler/rustc_target/src/spec/targets/powerpc64le_unknown_linux_gnu.rs b/compiler/rustc_target/src/spec/targets/powerpc64le_unknown_linux_gnu.rs
index dd3f660d81e..9e406af53b5 100644
--- a/compiler/rustc_target/src/spec/targets/powerpc64le_unknown_linux_gnu.rs
+++ b/compiler/rustc_target/src/spec/targets/powerpc64le_unknown_linux_gnu.rs
@@ -8,6 +8,7 @@ pub(crate) fn target() -> Target {
     base.add_pre_link_args(LinkerFlavor::Gnu(Cc::Yes, Lld::No), &["-m64"]);
     base.max_atomic_width = Some(64);
     base.stack_probes = StackProbeType::Inline;
+    base.llvm_abiname = "elfv2".into();
 
     Target {
         llvm_target: "powerpc64le-unknown-linux-gnu".into(),
diff --git a/compiler/rustc_target/src/spec/targets/powerpc64le_unknown_linux_musl.rs b/compiler/rustc_target/src/spec/targets/powerpc64le_unknown_linux_musl.rs
index 9e2bfe2c56f..f145c5b8c14 100644
--- a/compiler/rustc_target/src/spec/targets/powerpc64le_unknown_linux_musl.rs
+++ b/compiler/rustc_target/src/spec/targets/powerpc64le_unknown_linux_musl.rs
@@ -10,6 +10,7 @@ pub(crate) fn target() -> Target {
     base.stack_probes = StackProbeType::Inline;
     // FIXME(compiler-team#422): musl targets should be dynamically linked by default.
     base.crt_static_default = true;
+    base.llvm_abiname = "elfv2".into();
 
     Target {
         llvm_target: "powerpc64le-unknown-linux-musl".into(),