[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