Skip to content

Commit 79bb9f7

Browse files
authored
symcheck: Only ELFv1 ppc64 doesn't set .note.GNU-stack
`powerpc64-unknown-linux-gnu` currently is an ELFv1 target, while `powerpc64-unknown-linux-musl` is an ELFv2 target. Big-endian and little-endian ELFv2 targets both behave normally: they emit `.note.GNU-stack`. Therefore, currently the tests would fail on big-endian powerpc64 with ELFv2 ABI. To determine whether we need to special-case powerpc64, we should check the ABI instead of the endianness. The problem here is that the `e_flags` part of the ELF header is actually `0` in the output of `cc -O0 -ffunction-sections -fdata-sections -fPIC -m64 -mabi=elfv2 -Wall -Wextra -o missing_gnu_stack_section.o -c missing_gnu_stack_section.S`, the output of that command is bit-for-bit identical on ELFv1 and ELFv2 hosts. In order to know when to allow an unset `.note.GNU-stack` we therefore must set `.abiversion 2` to be able to tell them apart from the ELF header. This makes all tests pass on `powerpc64-unknown-linux-musl`.
1 parent 534a510 commit 79bb9f7

3 files changed

Lines changed: 25 additions & 9 deletions

File tree

library/compiler-builtins/crates/symbol-check/src/main.rs

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -13,8 +13,8 @@ use std::{env, fs};
1313

1414
use object::read::archive::ArchiveFile;
1515
use object::{
16-
Architecture, BinaryFormat, Endianness, File as ObjFile, Object, ObjectSection, ObjectSymbol,
17-
Result as ObjResult, SectionFlags, Symbol, SymbolKind, SymbolScope, U32, elf,
16+
Architecture, BinaryFormat, Endianness, File as ObjFile, FileFlags, Object, ObjectSection,
17+
ObjectSymbol, Result as ObjResult, SectionFlags, Symbol, SymbolKind, SymbolScope, U32, elf,
1818
};
1919
use regex::Regex;
2020
use serde_json::Value;
@@ -526,12 +526,15 @@ fn check_elf_exe_stack(obj: &ObjFile) -> Result<(), ExeStack> {
526526
return Ok(());
527527
}
528528

529+
let FileFlags::Elf { e_flags, .. } = obj.flags() else {
530+
unreachable!("only elf files are being checked");
531+
};
532+
529533
// If there is no `.note.GNU-stack` and no executable sections, behavior differs by platform.
530534
match obj.architecture() {
531535
// PPC64 doesn't set `.note.GNU-stack` since GNU nested functions don't need a trampoline,
532-
// <https://gcc.gnu.org/bugzilla/show_bug.cgi?id=21098>. From experimentation, it seems
533-
// like this only applies to big endian.
534-
Architecture::PowerPc64 if obj.endianness() == Endianness::Big => Ok(()),
536+
// <https://gcc.gnu.org/bugzilla/show_bug.cgi?id=21098>. This only applies to ELFv1.
537+
Architecture::PowerPc64 if e_flags & elf::EF_PPC64_ABI != 2 => Ok(()),
535538

536539
_ => Err(ExeStack::MissingGnuStackSec),
537540
}

library/compiler-builtins/crates/symbol-check/tests/all.rs

Lines changed: 11 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -111,8 +111,11 @@ mod exe_stack {
111111

112112
let assert = t.symcheck_exe().arg(obj).arg("--no-visibility").assert();
113113

114-
if t.is_ppc64be() || t.no_os() || t.binary_obj_format() != BinaryFormat::Elf {
115-
// Ppc64be doesn't emit `.note.GNU-stack`, not relevant without an OS, and non-elf
114+
if (t.is_ppc64be() && t.is_glibc())
115+
|| t.no_os()
116+
|| t.binary_obj_format() != BinaryFormat::Elf
117+
{
118+
// Ppc64be ELFv1 doesn't emit `.note.GNU-stack`, not relevant without an OS, and non-elf
116119
// targets don't use `.note.GNU-stack`.
117120
assert.success();
118121
return;
@@ -143,8 +146,8 @@ mod exe_stack {
143146

144147
let assert = t.symcheck_exe().arg(obj).arg("--no-visibility").assert();
145148

146-
if t.is_ppc64be() || t.no_os() {
147-
// Ppc64be doesn't emit `.note.GNU-stack`, not relevant without an OS.
149+
if (t.is_ppc64be() && t.is_glibc()) || t.no_os() {
150+
// Ppc64be ELFv1 doesn't emit `.note.GNU-stack`, not relevant without an OS.
148151
assert.success();
149152
return;
150153
}
@@ -316,6 +319,10 @@ impl TestTarget {
316319
self.triple.starts_with("powerpc64-")
317320
}
318321

322+
fn is_glibc(&self) -> bool {
323+
self.triple.contains("-linux-gnu")
324+
}
325+
319326
/// True if the target needs `--no-os` passed to symcheck.
320327
fn no_os(&self) -> bool {
321328
self.triple.contains("-none")

library/compiler-builtins/crates/symbol-check/tests/input/missing_gnu_stack_section.S

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,12 @@
44
* executability is implied (usually yes on Linux).
55
*/
66

7+
/* Unless we set the ABI version, we have no way to differentiate between
8+
big-endian ppc64 ELFv1 or ELFv2 since e_flags is otherwise unspecified */
9+
#if defined(__powerpc64__) && _CALL_ELF == 2
10+
.abiversion 2
11+
#endif
12+
713
.global func
814

915
#ifdef __wasm__

0 commit comments

Comments
 (0)