1
1
mirror of https://github.com/rui314/mold.git synced 2024-12-28 02:44:48 +03:00

Relax indirect call or jump with GOTPCRELX relocation

This commit is contained in:
Rui Ueyama 2021-03-16 12:13:30 +09:00
parent bfc3ef6f08
commit 5671de698b
3 changed files with 104 additions and 7 deletions

View File

@ -260,8 +260,21 @@ void InputSection::apply_reloc_alloc(u8 *base) {
case R_GOTPCREL:
write(G + GOT + A - P);
break;
case R_GOTPCREL_RELAX_REX_MOV:
loc[-2] = 0x8d; // rewrite mov insn to lea insn
case R_GOTPCREL_RELAX_CALL:
// Rewrite indirect call to direct call.
loc[-2] = 0x90;
loc[-1] = 0xe8;
write(S + A - P);
break;
case R_GOTPCREL_RELAX_JMP:
// Rewrite indirect jmp to direct jmp.
loc[-2] = 0x90;
loc[-1] = 0xe9;
write(S + A - P);
break;
case R_GOTPCREL_RELAX_MOV:
// Rewrite mov to lea.
loc[-2] = 0x8d;
write(S + A - P);
break;
case R_TLSGD:
@ -540,14 +553,36 @@ void InputSection::scan_relocations() {
rel_types[i] = R_GOTPC;
break;
case R_X86_64_GOTPCREL:
case R_X86_64_GOTPCRELX:
sym.flags |= NEEDS_GOT;
rel_types[i] = R_GOTPCREL;
break;
case R_X86_64_GOTPCRELX: {
if (rel.r_addend != -4)
Fatal() << *this << ": bad r_addend for R_X86_64_GOTPCRELX";
if (config.relax && !sym.is_imported && sym.is_relative()) {
u8 *insn = (u8 *)(contents.data() + rel.r_offset - 2);
if (insn[0] == 0xff && insn[1] == 0x15) {
rel_types[i] = R_GOTPCREL_RELAX_CALL;
break;
}
if (insn[0] == 0xff && insn[1] == 0x25) {
rel_types[i] = R_GOTPCREL_RELAX_JMP;
break;
}
}
sym.flags |= NEEDS_GOT;
rel_types[i] = R_GOTPCREL;
break;
}
case R_X86_64_REX_GOTPCRELX:
if (config.relax && sym.is_relative() && !sym.is_imported &&
rel.r_addend == -4 && is_mov_insn(contents, rel.r_offset)) {
rel_types[i] = R_GOTPCREL_RELAX_REX_MOV;
if (rel.r_addend != -4)
Fatal() << *this << ": bad r_addend for R_X86_64_REX_GOTPCRELX";
if (config.relax && !sym.is_imported && sym.is_relative() &&
is_mov_insn(contents, rel.r_offset)) {
rel_types[i] = R_GOTPCREL_RELAX_MOV;
} else {
sym.flags |= NEEDS_GOT;
rel_types[i] = R_GOTPCREL;

4
mold.h
View File

@ -335,7 +335,9 @@ enum RelType : u8 {
R_GOT,
R_GOTPC,
R_GOTPCREL,
R_GOTPCREL_RELAX_REX_MOV,
R_GOTPCREL_RELAX_CALL,
R_GOTPCREL_RELAX_JMP,
R_GOTPCREL_RELAX_MOV,
R_TLSGD,
R_TLSGD_RELAX_LE,
R_TLSLD,

60
test/relax.sh Executable file
View File

@ -0,0 +1,60 @@
#!/bin/bash
set -e
cd $(dirname $0)
echo -n "Testing $(basename -s .sh $0) ... "
t=$(pwd)/tmp/$(basename -s .sh $0)
mkdir -p $t
cat <<EOF | clang -o $t/a.o -c -x assembler -Wa,-mrelax-relocations=yes -
.globl bar
bar:
mov foo@GOTPCREL(%rip), %rax
mov foo@GOTPCREL(%rip), %rcx
mov foo@GOTPCREL(%rip), %rdx
mov foo@GOTPCREL(%rip), %rbx
mov foo@GOTPCREL(%rip), %rbp
mov foo@GOTPCREL(%rip), %rsi
mov foo@GOTPCREL(%rip), %rdi
mov foo@GOTPCREL(%rip), %r8
mov foo@GOTPCREL(%rip), %r9
mov foo@GOTPCREL(%rip), %r10
mov foo@GOTPCREL(%rip), %r11
mov foo@GOTPCREL(%rip), %r12
mov foo@GOTPCREL(%rip), %r13
mov foo@GOTPCREL(%rip), %r14
mov foo@GOTPCREL(%rip), %r15
call *foo@GOTPCREL(%rip)
jmp *foo@GOTPCREL(%rip)
EOF
cat <<EOF | clang -o $t/b.o -c -xc -
void foo() {}
int main() {
return 0;
}
EOF
clang -fuse-ld=`pwd`/../mold -o $t/exe $t/a.o $t/b.o
objdump -d $t/exe | grep -A20 '<bar>:' > $t/log
grep -Pq 'lea \s*0x.+\(%rip\),%rax .*<foo>' $t/log
grep -Pq 'lea \s*0x.+\(%rip\),%rcx .*<foo>' $t/log
grep -Pq 'lea \s*0x.+\(%rip\),%rdx .*<foo>' $t/log
grep -Pq 'lea \s*0x.+\(%rip\),%rbx .*<foo>' $t/log
grep -Pq 'lea \s*0x.+\(%rip\),%rbp .*<foo>' $t/log
grep -Pq 'lea \s*0x.+\(%rip\),%rsi .*<foo>' $t/log
grep -Pq 'lea \s*0x.+\(%rip\),%rdi .*<foo>' $t/log
grep -Pq 'lea \s*0x.+\(%rip\),%r8 .*<foo>' $t/log
grep -Pq 'lea \s*0x.+\(%rip\),%r9 .*<foo>' $t/log
grep -Pq 'lea \s*0x.+\(%rip\),%r10 .*<foo>' $t/log
grep -Pq 'lea \s*0x.+\(%rip\),%r11 .*<foo>' $t/log
grep -Pq 'lea \s*0x.+\(%rip\),%r12 .*<foo>' $t/log
grep -Pq 'lea \s*0x.+\(%rip\),%r13 .*<foo>' $t/log
grep -Pq 'lea \s*0x.+\(%rip\),%r14 .*<foo>' $t/log
grep -Pq 'lea \s*0x.+\(%rip\),%r15 .*<foo>' $t/log
grep -Pq 'callq.*<foo>' $t/log
grep -Pq 'jmpq.*<foo>' $t/log
echo OK