[lld] [ELF] Retain relocation sections for GOT entries added by relaxOnce (PR #225594)

via llvm-commits llvm-commits at lists.llvm.org
Tue Sep 22 22:08:47 PDT 2026


llvmorg-github-actions[bot] wrote:


<!--LLVM PR SUMMARY COMMENT-->

@llvm/pr-subscribers-lld

Author: Fangrui Song (MaskRay)

<details>
<summary>Changes</summary>

x86-64 and SystemZ relax GOTPCRELX/GOTENT and, in relaxOnce, revert
relaxations that turn out to be out of range or misaligned. The reverted
relocation needs a GOT entry, which in -pie/-shared needs a relative
relocation. If .rela.dyn (or .relr.dyn) was empty, it has already been
removed by removeUnusedSyntheticSections, triggering an assertion
failure.

Retain the section that will receive the relative relocations when
relaxOnce may add GOT entries, and recompute .dynamic after relaxOnce.

LLM-aided. Fixes #<!-- -->224011

---
Full diff: https://github.com/llvm/llvm-project/pull/225594.diff


6 Files Affected:

- (modified) lld/ELF/Relocations.cpp (+1-1) 
- (modified) lld/ELF/SyntheticSections.cpp (+2-1) 
- (modified) lld/ELF/SyntheticSections.h (+2) 
- (modified) lld/ELF/Writer.cpp (+9-1) 
- (modified) lld/test/ELF/systemz-gotent-relax-align.s (+16) 
- (modified) lld/test/ELF/x86-64-gotpc-relax-too-far-relr.s (+17-12) 


``````````diff
diff --git a/lld/ELF/Relocations.cpp b/lld/ELF/Relocations.cpp
index b6540a943bd18..db5ba7d023b7f 100644
--- a/lld/ELF/Relocations.cpp
+++ b/lld/ELF/Relocations.cpp
@@ -945,7 +945,7 @@ void RelocScan::process(RelExpr expr, RelType type, uint64_t offset,
       // 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);
+        ctx.in.got->hasDeferredEntries.store(true, std::memory_order_relaxed);
     }
   }
 
diff --git a/lld/ELF/SyntheticSections.cpp b/lld/ELF/SyntheticSections.cpp
index 2e7e898a55c63..f59e676c2e6f5 100644
--- a/lld/ELF/SyntheticSections.cpp
+++ b/lld/ELF/SyntheticSections.cpp
@@ -579,7 +579,8 @@ void GotSection::finalizeContents() {
 bool GotSection::isNeeded() const {
   // Needed if the GOT symbol is used or the number of entries is more than just
   // the header. A GOT with just the header may not be needed.
-  return hasGotOffRel || numEntries > ctx.target->gotHeaderEntriesNum;
+  return hasGotOffRel || hasDeferredEntries ||
+         numEntries > ctx.target->gotHeaderEntriesNum;
 }
 
 void GotSection::writeTo(uint8_t *buf) {
diff --git a/lld/ELF/SyntheticSections.h b/lld/ELF/SyntheticSections.h
index 355e1c35c20e3..85596e1339545 100644
--- a/lld/ELF/SyntheticSections.h
+++ b/lld/ELF/SyntheticSections.h
@@ -136,6 +136,8 @@ class GotSection final : public SyntheticSection {
   // Flag to force GOT to be in output if we have relocations
   // that relies on its address.
   std::atomic<bool> hasGotOffRel = false;
+  // Set if relaxOnce may add entries after removeUnusedSyntheticSections.
+  std::atomic<bool> hasDeferredEntries = false;
 
 protected:
   size_t numEntries = 0;
diff --git a/lld/ELF/Writer.cpp b/lld/ELF/Writer.cpp
index 1acab70af15fe..0f72e2b43f47d 100644
--- a/lld/ELF/Writer.cpp
+++ b/lld/ELF/Writer.cpp
@@ -1583,7 +1583,9 @@ template <class ELFT> void Writer<ELFT>::finalizeAddressDependentContent() {
       changed |= ctx.in.relrDyn->updateAllocSize(ctx);
     if (ctx.in.relrAuthDyn)
       changed |= ctx.in.relrAuthDyn->updateAllocSize(ctx);
-    if (ctx.in.relrAuthDyn && ctx.in.dynamic && ctx.in.dynamic->getParent()) {
+    if ((ctx.in.relrAuthDyn ||
+         (ctx.in.got && ctx.in.got->hasDeferredEntries)) &&
+        ctx.in.dynamic && ctx.in.dynamic->getParent()) {
       size_t oldSize = ctx.in.dynamic->getSize();
       finalizeSynthetic(ctx, ctx.in.dynamic.get());
       changed |= (oldSize != ctx.in.dynamic->getSize());
@@ -1753,6 +1755,12 @@ template <class ELFT> void Writer<ELFT>::optimizeBasicBlockJumps() {
 
 // Sections that finalizeAddressDependentContent may add to.
 static bool mayGrowLate(Ctx &ctx, SyntheticSection *sec) {
+  // relaxOnce may add GOT entries that need relative relocations.
+  if (ctx.arg.isPic && ctx.in.got && ctx.in.got->hasDeferredEntries &&
+      sec == (ctx.in.relrDyn
+                  ? static_cast<SyntheticSection *>(ctx.in.relrDyn.get())
+                  : ctx.in.relaDyn.get()))
+    return true;
   if (sec != ctx.in.relaDyn.get())
     return false;
   // Relocations may move here from .relr.auth.dyn.
diff --git a/lld/test/ELF/systemz-gotent-relax-align.s b/lld/test/ELF/systemz-gotent-relax-align.s
index 125d74ba4a21e..cfcf572c6781c 100644
--- a/lld/test/ELF/systemz-gotent-relax-align.s
+++ b/lld/test/ELF/systemz-gotent-relax-align.s
@@ -6,6 +6,13 @@
 # RUN: llvm-readelf -S -r -x .got -x .got.plt %t1 | FileCheck --check-prefixes=CHECK %s
 # RUN: llvm-objdump --no-print-imm-hex -d %t1 | FileCheck --check-prefix=DISASM %s
 
+## In -pie, the retained .got entry needs a relative relocation, even if
+## .rela.dyn or .relr.dyn is empty before relaxOnce.
+# RUN: ld.lld -pie %t.o -o %t2
+# RUN: llvm-readelf -d -r %t2 | FileCheck --check-prefix=RELA %s
+# RUN: ld.lld -pie -z pack-relative-relocs %t.o -o %t3
+# RUN: llvm-readelf -d -r %t3 | FileCheck --check-prefix=RELR %s
+
 ## We retain one .got entry for the unaligned symbol.
 # CHECK:      Name              Type            Address          Off    Size   ES Flg Lk Inf Al
 # CHECK:      .got              PROGBITS        00000000010021e0 0001e0 000020 00  WA  0   0  8
@@ -16,6 +23,15 @@
 # CHECK-NEXT:    0x010021e0 00000000 00000000 00000000 00000000
 # CHECK-NEXT:    0x010021f0 00000000 00000000 00000000 01003205
 
+# RELA:      (RELASZ) 24 (bytes)
+# RELA:      (NULL) 0x0
+# RELA:      Relocation section '.rela.dyn' at offset {{.*}} contains 1 entries:
+# RELA-NEXT: Offset Info Type Symbol's Value Symbol's Name + Addend
+# RELA-NEXT: {{.*}} R_390_RELATIVE
+
+# RELR:      (RELRSZ) 8 (bytes)
+# RELR:      Relocation section '.relr.dyn' at offset {{.*}} contains 1 entries:
+
 # DISASM:      Disassembly of section .text:
 # DISASM:      <_start>:
 # DISASM-NEXT:   larl    %r1, 0x1003200
diff --git a/lld/test/ELF/x86-64-gotpc-relax-too-far-relr.s b/lld/test/ELF/x86-64-gotpc-relax-too-far-relr.s
index 6c5e5f4368a41..c8489e9d9c2a6 100644
--- a/lld/test/ELF/x86-64-gotpc-relax-too-far-relr.s
+++ b/lld/test/ELF/x86-64-gotpc-relax-too-far-relr.s
@@ -1,18 +1,24 @@
 # REQUIRES: x86
-## Test that RELR relocations added when unrelaxing GOTPCREL relocations
-## during layout optimization (relaxOnce) are included in .relr.dyn.
-## .quad foo ensures .relr.dyn is not removed before unrelaxing.
+## Test that relative relocations added when unrelaxing GOTPCREL relocations
+## during layout optimization (relaxOnce) are emitted, even if .rela.dyn or
+## .relr.dyn is empty before relaxOnce.
 
 # RUN: llvm-mc -filetype=obj -triple=x86_64 %s -o %t.o
 # RUN: ld.lld -pie --pack-dyn-relocs=relr --section-start=.text=0x10000 --section-start=.got=0x20000 --section-start=.data=0x100000000 %t.o -o %t
-# RUN: llvm-readobj -r %t | FileCheck %s
+# RUN: llvm-readelf -d -r %t | FileCheck %s --check-prefix=RELR
+# RUN: ld.lld -pie --section-start=.text=0x10000 --section-start=.got=0x20000 --section-start=.data=0x100000000 %t.o -o %t.rela
+# RUN: llvm-readelf -d -r %t.rela | FileCheck %s --check-prefix=RELA
 
-# CHECK:      Relocations [
-# CHECK-NEXT:   Section ({{.*}}) .relr.dyn {
-# CHECK-NEXT:     0x20000 R_X86_64_RELATIVE -
-# CHECK-NEXT:     0x100000000 R_X86_64_RELATIVE -
-# CHECK-NEXT:   }
-# CHECK-NEXT: ]
+# RELR:      (RELRSZ) 8 (bytes)
+# RELR:      Relocation section '.relr.dyn' at offset {{.*}} contains 1 entries:
+# RELR-NEXT: Index: Entry Address Symbolic Address
+# RELR-NEXT: 0000: 0000000000020000 0000000000020000
+
+# RELA:      (RELASZ) 24 (bytes)
+# RELA:      (NULL) 0x0
+# RELA:      Relocation section '.rela.dyn' at offset {{.*}} contains 1 entries:
+# RELA-NEXT: Offset Info Type Symbol's Value Symbol's Name + Addend
+# RELA-NEXT: 0000000000020000 0000000000000008 R_X86_64_RELATIVE 100000000
 
 .text
 .globl _start
@@ -20,7 +26,6 @@ _start:
   movq foo at GOTPCREL(%rip), %rax
 
 .section .data,"aw", at progbits
-.align 8
 .globl foo
 foo:
-  .quad foo
+  .quad 0

``````````

</details>


https://github.com/llvm/llvm-project/pull/225594


More information about the llvm-commits mailing list