mirror of
https://github.com/rui314/mold.git
synced 2026-11-07 09:16:04 -10:00
Read ARM64 build attributes for BTI, PAC and GCS
GCC 16 records -mbranch-protection in AArch64 build attributes (.ARM.attributes) instead of .note.gnu.property, so an output lost the BTI, PAC and GCS bits even if all its inputs were compiled with the flag, and -z force-bti warned about every object file. We now read the aeabi_feature_and_bits subsection and merge it into GNU_PROPERTY_AARCH64_FEATURE_1_AND. Fixes https://github.com/rui314/mold/issues/1725
This commit is contained in:
1 parent
7866fb4799
commit
ff6a03bc69
4 files changed
+81
-4
No files matched your search
+4
-4
@@ -862,9 +862,9 @@ point symbol in a script.
|
||||
|
||||
`-z bti-report` flag is used to make sure that all object files were
|
||||
compiled with BTI. If `warning` or `error` are given, `mold` prints out a
|
||||
warning or an error message if an object file lacks
|
||||
warning or an error message if an object file has neither
|
||||
`GNU_PROPERTY_AARCH64_FEATURE_1_BTI` bit in its `.note.gnu.property`
|
||||
section.
|
||||
section nor `Tag_Feature_BTI` in its build attributes.
|
||||
|
||||
* `-z force-bti`:
|
||||
Turn on `GNU_PROPERTY_AARCH64_FEATURE_1_BTI` bit in `.note.gnu.property`
|
||||
@@ -880,9 +880,9 @@ point symbol in a script.
|
||||
off.
|
||||
|
||||
* `-z gcs-report`=[ `warning` | `error` | `none` ]:
|
||||
Print out a warning or an error message if an object file lacks
|
||||
Print out a warning or an error message if an object file has neither
|
||||
`GNU_PROPERTY_AARCH64_FEATURE_1_GCS` bit in its `.note.gnu.property`
|
||||
section.
|
||||
section nor `Tag_Feature_GCS` in its build attributes.
|
||||
|
||||
* `-z gcs-report-dynamic`=[ `warning` | `error` | `none` ]:
|
||||
Print out a warning or an error message if a shared library lacks
|
||||
|
||||
@@ -41,6 +41,7 @@ pub const SHT_HIOS: u32 = 0x6fffffff;
|
||||
pub const SHT_X86_64_UNWIND: u32 = 0x70000001;
|
||||
pub const SHT_ARM_EXIDX: u32 = 0x70000001;
|
||||
pub const SHT_ARM_ATTRIBUTES: u32 = 0x70000003;
|
||||
pub const SHT_AARCH64_ATTRIBUTES: u32 = 0x70000003;
|
||||
pub const SHT_RISCV_ATTRIBUTES: u32 = 0x70000003;
|
||||
pub const SHT_LOUSER: u32 = 0x80000000;
|
||||
pub const SHT_HIUSER: u32 = 0xffffffff;
|
||||
|
||||
@@ -1544,6 +1544,38 @@ impl<E: Target> ObjectFile<E> {
|
||||
}
|
||||
}
|
||||
|
||||
// AArch64 build attributes. GCC 16 records -mbranch-protection in them
|
||||
// instead of in .note.gnu.property. Tag N of the aeabi_feature_and_bits
|
||||
// subsection corresponds to bit N of GNU_PROPERTY_AARCH64_FEATURE_1_AND,
|
||||
// so we merge them into the property.
|
||||
//
|
||||
// 'A' [ <subsection-length> "subsection-name" <optional> <type> [ <tag> <value> ]* ]*
|
||||
fn read_arm64_attributes(&mut self, data: &'static [u8]) {
|
||||
let Some(mut data) = data.strip_prefix(b"A") else {
|
||||
return;
|
||||
};
|
||||
while !data.is_empty() {
|
||||
let size = E::read_u32(data) as usize;
|
||||
let p = &data[4..size];
|
||||
data = &data[size..];
|
||||
|
||||
if let Some(p) = p.strip_prefix(b"aeabi_feature_and_bits\0") {
|
||||
// Skip the optional and type fields, which are always 1 and
|
||||
// 0 (ULEB128) for this subsection.
|
||||
let mut p = &p[2..];
|
||||
let mut features = 0;
|
||||
while !p.is_empty() {
|
||||
let tag = read_uleb(&mut p);
|
||||
if read_uleb(&mut p) == 1 && tag < 32 {
|
||||
features |= 1 << tag;
|
||||
}
|
||||
}
|
||||
*self.gnu_properties.entry(GNU_PROPERTY_AARCH64_FEATURE_1_AND).or_insert(0) |=
|
||||
features;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// <format-version>
|
||||
// [ <section-length> "vendor-name" [ <file-tag> <size> <attribute>*]+ ]*
|
||||
fn read_riscv_attributes(&mut self, data: &'static [u8]) {
|
||||
@@ -1620,6 +1652,11 @@ impl<E: Target> ObjectFile<E> {
|
||||
continue;
|
||||
}
|
||||
|
||||
if E::FAMILY == Family::Arm64 && sh_type == SHT_AARCH64_ATTRIBUTES {
|
||||
let contents = self.base.section_contents_from_shdr(shdr);
|
||||
self.read_arm64_attributes(contents);
|
||||
continue;
|
||||
}
|
||||
if E::IS_ARM && sh_type == SHT_ARM_ATTRIBUTES {
|
||||
continue;
|
||||
}
|
||||
|
||||
Executable
+39
@@ -0,0 +1,39 @@
|
||||
#!/usr/bin/env bash
|
||||
. $(dirname $0)/common.inc
|
||||
|
||||
# GCC 16 records -mbranch-protection in AArch64 build attributes instead
|
||||
# of .note.gnu.property. Skip if the compiler is older.
|
||||
echo 'void foo() {}' | $CC -mbranch-protection=bti -c -o $t/a.o -xc - || skip
|
||||
readelf --sections $t/a.o | grep -F .ARM.attributes || skip
|
||||
|
||||
# _start calls foo with an indirect branch, which must land on a BTI
|
||||
# landing pad if the output is BTI-enabled.
|
||||
cat <<EOF | $CC -O2 -mbranch-protection=standard -c -o $t/b.o -xc -
|
||||
int foo();
|
||||
int (*fp)() = foo;
|
||||
|
||||
void _start() {
|
||||
register long x0 __asm__("x0") = fp() == 42 ? 0 : 1;
|
||||
register long x8 __asm__("x8") = 93; // exit
|
||||
__asm__ volatile("svc 0" :: "r"(x0), "r"(x8));
|
||||
}
|
||||
EOF
|
||||
|
||||
cat <<EOF | $CC -O2 -mbranch-protection=bti -c -o $t/c.o -xc -
|
||||
int foo() { return 42; }
|
||||
EOF
|
||||
|
||||
cat <<EOF | $CC -O2 -mbranch-protection=none -c -o $t/d.o -xc -
|
||||
int foo() { return 42; }
|
||||
EOF
|
||||
|
||||
./mold -static -o $t/exe1 $t/b.o $t/c.o
|
||||
readelf -n $t/exe1 | grep 'AArch64 feature: BTI$'
|
||||
$QEMU $t/exe1
|
||||
|
||||
./mold -static -o $t/exe2 $t/b.o $t/d.o
|
||||
readelf -n $t/exe2 | not grep 'AArch64 feature'
|
||||
$QEMU $t/exe2
|
||||
|
||||
./mold -r -o $t/e.o $t/b.o $t/c.o
|
||||
readelf -n $t/e.o | grep 'AArch64 feature: BTI$'
|
||||
Reference in new issue
Block a user