[lld] [ELF] Retain .got for revertible no-PIC GOTPCRELX optimization (PR #212077)

Fangrui Song via llvm-commits llvm-commits at lists.llvm.org
Sat Jul 25 17:49:45 PDT 2026


https://github.com/MaskRay created https://github.com/llvm/llvm-project/pull/212077

Commit 9d6ec280fc537b55ef8641ea85d3522426bc5766 (2023) sets
GotSection::hasGotOffRel when adjustGotPcExpr returns R_RELAX_GOT_PC,
keeping .got alive for an optimization that X86_64::relaxOnce may
revert.

R_RELAX_GOT_PC_NOPIC (e.g. `addq`) in -no-pie mode has the same issue.

>From 35ae548308ed975d976d681ca74b2789dd18ee21 Mon Sep 17 00:00:00 2001
From: Fangrui Song <i at maskray.me>
Date: Sat, 25 Jul 2026 17:18:16 -0700
Subject: [PATCH] [ELF] Retain .got for revertible no-PIC GOTPCRELX
 optimization

Commit 9d6ec280fc537b55ef8641ea85d3522426bc5766 (2023) sets
GotSection::hasGotOffRel when adjustGotPcExpr returns R_RELAX_GOT_PC,
keeping .got alive for an optimization that X86_64::relaxOnce may
revert.

R_RELAX_GOT_PC_NOPIC (e.g. `addq`) in -no-pie mode has the same issue.
---
 lld/ELF/Relocations.cpp                   |  6 +++---
 lld/test/ELF/x86-64-gotpc-relax-too-far.s | 16 ++++++++++++++++
 2 files changed, 19 insertions(+), 3 deletions(-)

diff --git a/lld/ELF/Relocations.cpp b/lld/ELF/Relocations.cpp
index 4702d941d28ca..ff06fe1602d95 100644
--- a/lld/ELF/Relocations.cpp
+++ b/lld/ELF/Relocations.cpp
@@ -927,9 +927,9 @@ void RelocScan::process(RelExpr expr, RelType type, uint64_t offset,
     } else if (!isAbsoluteOrTls(sym)) {
       expr = ctx.target->adjustGotPcExpr(type, addend,
                                          sec->content().data() + offset);
-      // If the target adjusted the expression to R_RELAX_GOT_PC, we may end up
-      // needing the GOT if we can't relax everything.
-      if (expr == R_RELAX_GOT_PC)
+      // If the target adjusted the expression to an optimizable form, we may
+      // end up needing the GOT if we can't optimize everything.
+      if (expr == R_RELAX_GOT_PC || expr == R_RELAX_GOT_PC_NOPIC)
         ctx.in.got->hasGotOffRel.store(true, std::memory_order_relaxed);
     }
   }
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 0318d73ec2db2..2019b8c51d050 100644
--- a/lld/test/ELF/x86-64-gotpc-relax-too-far.s
+++ b/lld/test/ELF/x86-64-gotpc-relax-too-far.s
@@ -11,6 +11,10 @@
 # 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
+# RUN: llvm-mc -filetype=obj -triple=x86_64 %t/b.s -o %t/b.o
+# RUN: ld.lld -T %t/lds1 %t/b.o -o %t/bin5
+# RUN: llvm-objdump -d %t/bin5 | FileCheck --check-prefix=DISASM5 %s
+# RUN: llvm-readelf -S %t/bin5 | FileCheck --check-prefixes=GOT5 %s
 
 # DISASM:      <_foo>:
 # DISASM-NEXT: movl    0x1ffffa(%rip), %eax
@@ -27,10 +31,14 @@
 # DISASM4-NEXT: addq    0x1ff3(%rip), %rax
 # DISASM4-NEXT: addq    $0x7fffffff, %rax
 
+# DISASM5:      <_start>:
+# DISASM5-NEXT: addq    0xffff9(%rip), %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 000018 00 WA 0 0 8
+#            GOT5: .got PROGBITS 0000000000300000 002000 000008 00 WA 0 0 8
 
 #--- a.s
 .section .text.foo,"ax"
@@ -91,3 +99,11 @@ SECTIONS {
   foo 0x7fffffff : { *(foo) }
   data 0x80001000 : { *(data) }
 }
+
+#--- b.s
+.globl _start
+_start:
+  addq __stop_data at GOTPCREL(%rip), %rax  # out of range
+
+.section data,"aw", at progbits
+.space 13



More information about the llvm-commits mailing list