mirror of
https://github.com/rui314/mold.git
synced 2026-11-07 09:16:04 -10:00
Start x86-64 .plt.got entries of ifuncs in non-PIE executables with endbr64
In a position-dependent executable, the address of an ifunc is that of its .plt.got entry, so an indirect call to the function lands on the entry. Like a canonical PLT entry, such an entry now starts with endbr64 so that it works with IBT. This makes x86-64 .plt.got entries 16 bytes long instead of 8.
This commit is contained in:
1 parent
c00226bed7
commit
bcc453917a
2 files changed
+45
-8
No files matched your search
+21
-8
@@ -54,7 +54,7 @@ impl Target for X86_64 {
|
||||
const FAMILY: Family = Family::X86_64;
|
||||
const PAGE_SIZE: u64 = 4096;
|
||||
const E_MACHINE: u32 = EM_X86_64;
|
||||
const PLTGOT_SIZE: u64 = 8;
|
||||
const PLTGOT_SIZE: u64 = 16;
|
||||
const SFRAME_ABI: Option<u8> = Some(SFRAME_ABI_AMD64_ENDIAN_LITTLE);
|
||||
const TRAP: &'static [u8] = &[0xcc]; // int3
|
||||
|
||||
@@ -136,14 +136,27 @@ impl Target for X86_64 {
|
||||
}
|
||||
}
|
||||
|
||||
// A .plt.got entry is used as a function's address if it belongs to an
|
||||
// ifunc in a position-dependent executable, so such an entry starts with
|
||||
// endbr64.
|
||||
fn write_pltgot_entry(ctx: &Context<Self>, buf: &mut [u8], sym: &Symbol) {
|
||||
const INSN: [u8; 8] = [
|
||||
0xff, 0x25, 0, 0, 0, 0, // jmp *foo@GOT
|
||||
0xcc, 0xcc, // (padding)
|
||||
];
|
||||
buf[..8].copy_from_slice(&INSN);
|
||||
let disp = sym.got_pltgot_addr(ctx).wrapping_sub(sym.plt_addr(ctx)).wrapping_sub(6);
|
||||
write_ul32(&mut buf[2..], disp as u32);
|
||||
let disp = sym.got_pltgot_addr(ctx).wrapping_sub(sym.plt_addr(ctx));
|
||||
if sym.is_pde_ifunc(ctx) {
|
||||
const INSN: [u8; 16] = [
|
||||
0xf3, 0x0f, 0x1e, 0xfa, // endbr64
|
||||
0xff, 0x25, 0, 0, 0, 0, // jmp *foo@GOT
|
||||
0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, // (padding)
|
||||
];
|
||||
buf[..16].copy_from_slice(&INSN);
|
||||
write_ul32(&mut buf[6..], disp.wrapping_sub(10) as u32);
|
||||
} else {
|
||||
const INSN: [u8; 16] = [
|
||||
0xff, 0x25, 0, 0, 0, 0, // jmp *foo@GOT
|
||||
0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, // (padding)
|
||||
];
|
||||
buf[..16].copy_from_slice(&INSN);
|
||||
write_ul32(&mut buf[2..], disp.wrapping_sub(6) as u32);
|
||||
}
|
||||
}
|
||||
|
||||
fn apply_eh_reloc(
|
||||
|
||||
Executable
+24
@@ -0,0 +1,24 @@
|
||||
#!/usr/bin/env bash
|
||||
. $(dirname $0)/common.inc
|
||||
|
||||
supports_ifunc || skip
|
||||
|
||||
# In a position-dependent executable, the address of an ifunc is that of
|
||||
# its .plt.got entry, so the entry has to start with endbr64 for IBT.
|
||||
cat <<EOF | $CC -fno-PIE -c -o $t/a.o -xc -
|
||||
#include <stdio.h>
|
||||
|
||||
static int real_foo(void) { return 3; }
|
||||
static void *resolve_foo(void) { return real_foo; }
|
||||
int foo(void) __attribute__((ifunc("resolve_foo")));
|
||||
|
||||
int (*fp)(void) = foo;
|
||||
|
||||
int main() {
|
||||
printf("%d %d\n", foo(), fp());
|
||||
}
|
||||
EOF
|
||||
|
||||
$CC -B. -no-pie -o $t/exe $t/a.o
|
||||
$QEMU $t/exe | grep '^3 3$'
|
||||
$OBJDUMP -d -j .plt.got $t/exe | grep -A1 '<foo\$pltgot>:' | grep -w endbr64
|
||||
Reference in new issue
Block a user