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:
parent
bfc3ef6f08
commit
5671de698b
@ -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
4
mold.h
@ -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
60
test/relax.sh
Executable 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
|
Loading…
Reference in New Issue
Block a user