mirror of
https://github.com/rust-lang/rust.git
synced 2026-05-30 21:16:27 +03:00
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`.
This commit is contained in:
@@ -13,8 +13,8 @@
|
||||
|
||||
use object::read::archive::ArchiveFile;
|
||||
use object::{
|
||||
Architecture, BinaryFormat, Endianness, File as ObjFile, Object, ObjectSection, ObjectSymbol,
|
||||
Result as ObjResult, SectionFlags, Symbol, SymbolKind, SymbolScope, U32, elf,
|
||||
Architecture, BinaryFormat, Endianness, File as ObjFile, FileFlags, Object, ObjectSection,
|
||||
ObjectSymbol, Result as ObjResult, SectionFlags, Symbol, SymbolKind, SymbolScope, U32, elf,
|
||||
};
|
||||
use regex::Regex;
|
||||
use serde_json::Value;
|
||||
@@ -526,12 +526,15 @@ fn check_elf_exe_stack(obj: &ObjFile) -> Result<(), ExeStack> {
|
||||
return Ok(());
|
||||
}
|
||||
|
||||
let FileFlags::Elf { e_flags, .. } = obj.flags() else {
|
||||
unreachable!("only elf files are being checked");
|
||||
};
|
||||
|
||||
// If there is no `.note.GNU-stack` and no executable sections, behavior differs by platform.
|
||||
match obj.architecture() {
|
||||
// PPC64 doesn't set `.note.GNU-stack` since GNU nested functions don't need a trampoline,
|
||||
// <https://gcc.gnu.org/bugzilla/show_bug.cgi?id=21098>. From experimentation, it seems
|
||||
// like this only applies to big endian.
|
||||
Architecture::PowerPc64 if obj.endianness() == Endianness::Big => Ok(()),
|
||||
// <https://gcc.gnu.org/bugzilla/show_bug.cgi?id=21098>. This only applies to ELFv1.
|
||||
Architecture::PowerPc64 if e_flags & elf::EF_PPC64_ABI != 2 => Ok(()),
|
||||
|
||||
_ => Err(ExeStack::MissingGnuStackSec),
|
||||
}
|
||||
|
||||
@@ -111,8 +111,11 @@ fn test_missing_gnu_stack_section() {
|
||||
|
||||
let assert = t.symcheck_exe().arg(obj).arg("--no-visibility").assert();
|
||||
|
||||
if t.is_ppc64be() || t.no_os() || t.binary_obj_format() != BinaryFormat::Elf {
|
||||
// Ppc64be doesn't emit `.note.GNU-stack`, not relevant without an OS, and non-elf
|
||||
if (t.is_ppc64be() && t.is_glibc())
|
||||
|| t.no_os()
|
||||
|| t.binary_obj_format() != BinaryFormat::Elf
|
||||
{
|
||||
// Ppc64be ELFv1 doesn't emit `.note.GNU-stack`, not relevant without an OS, and non-elf
|
||||
// targets don't use `.note.GNU-stack`.
|
||||
assert.success();
|
||||
return;
|
||||
@@ -143,8 +146,8 @@ fn test_exe_gnu_stack_section() {
|
||||
|
||||
let assert = t.symcheck_exe().arg(obj).arg("--no-visibility").assert();
|
||||
|
||||
if t.is_ppc64be() || t.no_os() {
|
||||
// Ppc64be doesn't emit `.note.GNU-stack`, not relevant without an OS.
|
||||
if (t.is_ppc64be() && t.is_glibc()) || t.no_os() {
|
||||
// Ppc64be ELFv1 doesn't emit `.note.GNU-stack`, not relevant without an OS.
|
||||
assert.success();
|
||||
return;
|
||||
}
|
||||
@@ -316,6 +319,10 @@ fn is_ppc64be(&self) -> bool {
|
||||
self.triple.starts_with("powerpc64-")
|
||||
}
|
||||
|
||||
fn is_glibc(&self) -> bool {
|
||||
self.triple.contains("-linux-gnu")
|
||||
}
|
||||
|
||||
/// True if the target needs `--no-os` passed to symcheck.
|
||||
fn no_os(&self) -> bool {
|
||||
self.triple.contains("-none")
|
||||
|
||||
@@ -4,6 +4,12 @@
|
||||
* executability is implied (usually yes on Linux).
|
||||
*/
|
||||
|
||||
/* Unless we set the ABI version, we have no way to differentiate between
|
||||
big-endian ppc64 ELFv1 or ELFv2 since e_flags is otherwise unspecified */
|
||||
#if defined(__powerpc64__) && _CALL_ELF == 2
|
||||
.abiversion 2
|
||||
#endif
|
||||
|
||||
.global func
|
||||
|
||||
#ifdef __wasm__
|
||||
|
||||
Reference in New Issue
Block a user