Skip to content

Commit f3c4dae

Browse files
committed
[ELF] -no-pie: don't optimize addq R_X86_64_REX_GOTPCRELX when !isInt<32>(va)
When `!isInt<32>(x.va)`, `addq x@GOTPCREL(%rip), %rax` (possibly due to getelementptr of a global variable) should not be optimized to `addq offset, %rax`. We currently have either an assertion failure or an incorrect optimization. Fix it using the relaxOnce framework.
1 parent 7625465 commit f3c4dae

File tree

2 files changed

+46
-15
lines changed

2 files changed

+46
-15
lines changed

lld/ELF/Arch/X86_64.cpp

Lines changed: 10 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -314,8 +314,10 @@ bool X86_64::relaxOnce(int pass) const {
314314
minVA = std::min(minVA, osec->addr);
315315
maxVA = std::max(maxVA, osec->addr + osec->size);
316316
}
317-
// If the max VA difference is under 2^31, GOT-generating relocations with a 32-bit range cannot overflow.
318-
if (isUInt<31>(maxVA - minVA))
317+
// If the max VA is under 2^31, GOTPCRELX relocations cannot overfow. In
318+
// -pie/-shared, the condition can be relaxed to test the max VA difference as
319+
// there is no R_RELAX_GOT_PC_NOPIC.
320+
if (isUInt<31>(maxVA) || (isUInt<31>(maxVA - minVA) && config->isPic))
319321
return false;
320322

321323
SmallVector<InputSection *, 0> storage;
@@ -325,13 +327,14 @@ bool X86_64::relaxOnce(int pass) const {
325327
continue;
326328
for (InputSection *sec : getInputSections(*osec, storage)) {
327329
for (Relocation &rel : sec->relocs()) {
328-
if (rel.expr != R_RELAX_GOT_PC)
330+
if (rel.expr != R_RELAX_GOT_PC && rel.expr != R_RELAX_GOT_PC_NOPIC)
329331
continue;
332+
assert(rel.addend == -4);
330333

331-
uint64_t v = sec->getRelocTargetVA(sec->file, rel.type, rel.addend,
332-
sec->getOutputSection()->addr +
333-
sec->outSecOff + rel.offset,
334-
*rel.sym, rel.expr);
334+
uint64_t v = sec->getRelocTargetVA(
335+
sec->file, rel.type, rel.expr == R_RELAX_GOT_PC_NOPIC ? 0 : -4,
336+
sec->getOutputSection()->addr + sec->outSecOff + rel.offset,
337+
*rel.sym, rel.expr);
335338
if (isInt<32>(v))
336339
continue;
337340
if (rel.sym->auxIdx == 0) {

lld/test/ELF/x86-64-gotpc-relax-too-far.s

Lines changed: 36 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -2,33 +2,44 @@
22
# RUN: split-file %s %t
33
# RUN: llvm-mc -filetype=obj -triple=x86_64 %t/a.s -o %t/a.o
44
# RUN: ld.lld -T %t/lds1 %t/a.o -o %t/bin
5-
# RUN: llvm-objdump --no-print-imm-hex -d %t/bin | FileCheck --check-prefix=DISASM %s
5+
# RUN: llvm-objdump -d %t/bin | FileCheck --check-prefix=DISASM %s
66
# RUN: llvm-readelf -S %t/bin | FileCheck --check-prefixes=GOT %s
77
# RUN: ld.lld -T %t/lds2 %t/a.o -o %t/bin2
8-
# RUN: llvm-objdump --no-print-imm-hex -d %t/bin2 | FileCheck --check-prefix=DISASM %s
8+
# RUN: llvm-objdump -d %t/bin2 | FileCheck --check-prefix=DISASM %s
99
# RUN: llvm-readelf -S %t/bin2 | FileCheck --check-prefixes=GOT %s
1010
# RUN: ld.lld -T %t/lds3 %t/a.o -o %t/bin3
1111
# RUN: llvm-readelf -S %t/bin3 | FileCheck --check-prefixes=UNNECESSARY-GOT %s
12+
# RUN: ld.lld -T %t/lds4 %t/a.o -o %t/bin4
13+
# RUN: llvm-objdump -d %t/bin4 | FileCheck --check-prefix=DISASM4 %s
1214

1315
# DISASM: <_foo>:
14-
# DISASM-NEXT: movl 2097146(%rip), %eax
16+
# DISASM-NEXT: movl 0x1ffffa(%rip), %eax
17+
# DISASM-NEXT: addq 0x1ffffb(%rip), %rax
18+
# DISASM-NEXT: addq $0x7fffffff, %rax
1519
# DISASM: <_start>:
16-
# DISASM-NEXT: movl 1048578(%rip), %eax
17-
# DISASM-NEXT: movq 1048571(%rip), %rax
18-
# DISASM-NEXT: leaq 2147483641(%rip), %rax
19-
# DISASM-NEXT: leal 2147483635(%rip), %eax
20+
# DISASM-NEXT: movl 0x10000a(%rip), %eax
21+
# DISASM-NEXT: movq 0x100003(%rip), %rax
22+
# DISASM-NEXT: leaq 0x7ffffff9(%rip), %rax
23+
# DISASM-NEXT: leal 0x7ffffff3(%rip), %eax
24+
25+
# DISASM4: <_foo>:
26+
# DISASM4-NEXT: leal 0x7fffeffa(%rip), %eax
27+
# DISASM4-NEXT: addq 0x1ff3(%rip), %rax
28+
# DISASM4-NEXT: addq $0x7fffffff, %rax
2029

2130
# In our implementation, .got is retained even if all GOT-generating relocations are optimized.
2231
# Make sure .got still exists with the right size.
2332
# UNNECESSARY-GOT: .got PROGBITS 0000000000300000 101020 000000 00 WA 0 0 8
24-
# GOT: .got PROGBITS 0000000000300000 102000 000010 00 WA 0 0 8
33+
# GOT: .got PROGBITS 0000000000300000 102000 000018 00 WA 0 0 8
2534

2635
#--- a.s
2736
.section .text.foo,"ax"
2837
.globl _foo
2938
.type _foo, @function
3039
_foo:
3140
movl __start_data@GOTPCREL(%rip), %eax # out of range
41+
addq foo_1@GOTPCREL(%rip), %rax # out of range
42+
addq foo@GOTPCREL(%rip), %rax # in range
3243

3344
.section .text,"ax"
3445
.globl _start
@@ -39,6 +50,11 @@ _start:
3950
movq __stop_data@GOTPCREL(%rip), %rax # in range
4051
movl __stop_data@GOTPCREL(%rip), %eax # in range
4152

53+
.section foo,"aw",@progbits
54+
.space 1
55+
foo_1:
56+
.space 1
57+
4258
.section data,"aw",@progbits
4359
.space 13
4460

@@ -47,13 +63,15 @@ SECTIONS {
4763
.text.foo 0x100000 : { *(.text.foo) }
4864
.text 0x200000 : { *(.text) }
4965
.got 0x300000 : { *(.got) }
66+
foo 0x7fffffff : { *(foo) }
5067
data 0x80200000 : { *(data) }
5168
}
5269
#--- lds2
5370
SECTIONS {
5471
.text.foo 0x100000 : { *(.text.foo) }
5572
.text 0x1ff000 : { . = . + 0x1000 ; *(.text) }
5673
.got 0x300000 : { *(.got) }
74+
foo 0x7fffffff : { *(foo) }
5775
data 0x80200000 : { *(data) }
5876
}
5977
#--- lds3
@@ -63,3 +81,13 @@ SECTIONS {
6381
.got 0x300000 : { *(.got) }
6482
data 0x400000 : { *(data) }
6583
}
84+
85+
#--- lds4
86+
## Max VA difference < 0x80000000
87+
SECTIONS {
88+
.text.foo 0x02000 : { *(.text.foo) }
89+
.text 0x3000 : { *(.text) }
90+
.got 0x4000 : { *(.got) }
91+
foo 0x7fffffff : { *(foo) }
92+
data 0x80001000 : { *(data) }
93+
}

0 commit comments

Comments
 (0)