[lld] f3c4dae - [ELF] -no-pie: don't optimize addq R_X86_64_REX_GOTPCRELX when !isInt<32>(va)
Fangrui Song via llvm-commits
llvm-commits at lists.llvm.org
Thu Jun 20 20:52:12 PDT 2024
Author: Fangrui Song
Date: 2024-06-20T20:52:07-07:00
New Revision: f3c4dae6f2c44f1a7f130c4cf4b2861b62402b48
URL: https://github.com/llvm/llvm-project/commit/f3c4dae6f2c44f1a7f130c4cf4b2861b62402b48
DIFF: https://github.com/llvm/llvm-project/commit/f3c4dae6f2c44f1a7f130c4cf4b2861b62402b48.diff
LOG: [ELF] -no-pie: don't optimize addq R_X86_64_REX_GOTPCRELX when !isInt<32>(va)
When `!isInt<32>(x.va)`, `addq x at 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.
Added:
Modified:
lld/ELF/Arch/X86_64.cpp
lld/test/ELF/x86-64-gotpc-relax-too-far.s
Removed:
################################################################################
diff --git a/lld/ELF/Arch/X86_64.cpp b/lld/ELF/Arch/X86_64.cpp
index a85bf3aa0c09d..6f38c93d6e67c 100644
--- a/lld/ELF/Arch/X86_64.cpp
+++ b/lld/ELF/Arch/X86_64.cpp
@@ -314,8 +314,10 @@ bool X86_64::relaxOnce(int pass) const {
minVA = std::min(minVA, osec->addr);
maxVA = std::max(maxVA, osec->addr + osec->size);
}
- // If the max VA
diff erence is under 2^31, GOT-generating relocations with a 32-bit range cannot overflow.
- if (isUInt<31>(maxVA - minVA))
+ // If the max VA is under 2^31, GOTPCRELX relocations cannot overfow. In
+ // -pie/-shared, the condition can be relaxed to test the max VA
diff erence as
+ // there is no R_RELAX_GOT_PC_NOPIC.
+ if (isUInt<31>(maxVA) || (isUInt<31>(maxVA - minVA) && config->isPic))
return false;
SmallVector<InputSection *, 0> storage;
@@ -325,13 +327,14 @@ bool X86_64::relaxOnce(int pass) const {
continue;
for (InputSection *sec : getInputSections(*osec, storage)) {
for (Relocation &rel : sec->relocs()) {
- if (rel.expr != R_RELAX_GOT_PC)
+ if (rel.expr != R_RELAX_GOT_PC && rel.expr != R_RELAX_GOT_PC_NOPIC)
continue;
+ assert(rel.addend == -4);
- uint64_t v = sec->getRelocTargetVA(sec->file, rel.type, rel.addend,
- sec->getOutputSection()->addr +
- sec->outSecOff + rel.offset,
- *rel.sym, rel.expr);
+ uint64_t v = sec->getRelocTargetVA(
+ sec->file, rel.type, rel.expr == R_RELAX_GOT_PC_NOPIC ? 0 : -4,
+ sec->getOutputSection()->addr + sec->outSecOff + rel.offset,
+ *rel.sym, rel.expr);
if (isInt<32>(v))
continue;
if (rel.sym->auxIdx == 0) {
diff --git a/lld/test/ELF/x86-64-gotpc-relax-too-far.s b/lld/test/ELF/x86-64-gotpc-relax-too-far.s
index ba41faab67de5..0318d73ec2db2 100644
--- a/lld/test/ELF/x86-64-gotpc-relax-too-far.s
+++ b/lld/test/ELF/x86-64-gotpc-relax-too-far.s
@@ -2,26 +2,35 @@
# RUN: split-file %s %t
# RUN: llvm-mc -filetype=obj -triple=x86_64 %t/a.s -o %t/a.o
# RUN: ld.lld -T %t/lds1 %t/a.o -o %t/bin
-# RUN: llvm-objdump --no-print-imm-hex -d %t/bin | FileCheck --check-prefix=DISASM %s
+# RUN: llvm-objdump -d %t/bin | FileCheck --check-prefix=DISASM %s
# RUN: llvm-readelf -S %t/bin | FileCheck --check-prefixes=GOT %s
# RUN: ld.lld -T %t/lds2 %t/a.o -o %t/bin2
-# RUN: llvm-objdump --no-print-imm-hex -d %t/bin2 | FileCheck --check-prefix=DISASM %s
+# RUN: llvm-objdump -d %t/bin2 | FileCheck --check-prefix=DISASM %s
# RUN: llvm-readelf -S %t/bin2 | FileCheck --check-prefixes=GOT %s
# RUN: ld.lld -T %t/lds3 %t/a.o -o %t/bin3
# RUN: llvm-readelf -S %t/bin3 | FileCheck --check-prefixes=UNNECESSARY-GOT %s
+# RUN: ld.lld -T %t/lds4 %t/a.o -o %t/bin4
+# RUN: llvm-objdump -d %t/bin4 | FileCheck --check-prefix=DISASM4 %s
# DISASM: <_foo>:
-# DISASM-NEXT: movl 2097146(%rip), %eax
+# DISASM-NEXT: movl 0x1ffffa(%rip), %eax
+# DISASM-NEXT: addq 0x1ffffb(%rip), %rax
+# DISASM-NEXT: addq $0x7fffffff, %rax
# DISASM: <_start>:
-# DISASM-NEXT: movl 1048578(%rip), %eax
-# DISASM-NEXT: movq 1048571(%rip), %rax
-# DISASM-NEXT: leaq 2147483641(%rip), %rax
-# DISASM-NEXT: leal 2147483635(%rip), %eax
+# DISASM-NEXT: movl 0x10000a(%rip), %eax
+# DISASM-NEXT: movq 0x100003(%rip), %rax
+# DISASM-NEXT: leaq 0x7ffffff9(%rip), %rax
+# DISASM-NEXT: leal 0x7ffffff3(%rip), %eax
+
+# DISASM4: <_foo>:
+# DISASM4-NEXT: leal 0x7fffeffa(%rip), %eax
+# DISASM4-NEXT: addq 0x1ff3(%rip), %rax
+# DISASM4-NEXT: addq $0x7fffffff, %rax
# In our implementation, .got is retained even if all GOT-generating relocations are optimized.
# Make sure .got still exists with the right size.
# UNNECESSARY-GOT: .got PROGBITS 0000000000300000 101020 000000 00 WA 0 0 8
-# GOT: .got PROGBITS 0000000000300000 102000 000010 00 WA 0 0 8
+# GOT: .got PROGBITS 0000000000300000 102000 000018 00 WA 0 0 8
#--- a.s
.section .text.foo,"ax"
@@ -29,6 +38,8 @@
.type _foo, @function
_foo:
movl __start_data at GOTPCREL(%rip), %eax # out of range
+ addq foo_1 at GOTPCREL(%rip), %rax # out of range
+ addq foo at GOTPCREL(%rip), %rax # in range
.section .text,"ax"
.globl _start
@@ -39,6 +50,11 @@ _start:
movq __stop_data at GOTPCREL(%rip), %rax # in range
movl __stop_data at GOTPCREL(%rip), %eax # in range
+.section foo,"aw", at progbits
+.space 1
+foo_1:
+.space 1
+
.section data,"aw", at progbits
.space 13
@@ -47,6 +63,7 @@ SECTIONS {
.text.foo 0x100000 : { *(.text.foo) }
.text 0x200000 : { *(.text) }
.got 0x300000 : { *(.got) }
+ foo 0x7fffffff : { *(foo) }
data 0x80200000 : { *(data) }
}
#--- lds2
@@ -54,6 +71,7 @@ SECTIONS {
.text.foo 0x100000 : { *(.text.foo) }
.text 0x1ff000 : { . = . + 0x1000 ; *(.text) }
.got 0x300000 : { *(.got) }
+ foo 0x7fffffff : { *(foo) }
data 0x80200000 : { *(data) }
}
#--- lds3
@@ -63,3 +81,13 @@ SECTIONS {
.got 0x300000 : { *(.got) }
data 0x400000 : { *(data) }
}
+
+#--- lds4
+## Max VA
diff erence < 0x80000000
+SECTIONS {
+ .text.foo 0x02000 : { *(.text.foo) }
+ .text 0x3000 : { *(.text) }
+ .got 0x4000 : { *(.got) }
+ foo 0x7fffffff : { *(foo) }
+ data 0x80001000 : { *(data) }
+}
More information about the llvm-commits
mailing list