[lld] [ELF] Always separate relative relocations regardless of -z combreloc (PR #187964)

Fangrui Song via llvm-commits llvm-commits at lists.llvm.org
Sun Mar 22 20:09:21 PDT 2026


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

Remove the combreloc guard from addReloc and mergeRels so that
relative relocations are always routed to relativeRelocs, even with -z
nocombreloc or --pack-dyn-relocs=android.

Update AndroidPackedRelocationSection::updateAllocSize to iterate
both relativeRelocs and relocs.

>From 56aab5f58d35f7a725211d95f137611e30d61c4e Mon Sep 17 00:00:00 2001
From: Fangrui Song <i at maskray.me>
Date: Sun, 22 Mar 2026 16:38:52 -0700
Subject: [PATCH] [ELF] Always separate relative relocations regardless of -z
 combreloc

Remove the combreloc guard from addReloc and mergeRels so that
relative relocations are always routed to relativeRelocs, even with -z
nocombreloc or --pack-dyn-relocs=android.

Update AndroidPackedRelocationSection::updateAllocSize to iterate
both relativeRelocs and relocs.
---
 lld/ELF/SyntheticSections.cpp | 31 ++++++++++++++++---------------
 lld/ELF/SyntheticSections.h   |  2 +-
 lld/test/ELF/combreloc.s      |  2 +-
 3 files changed, 18 insertions(+), 17 deletions(-)

diff --git a/lld/ELF/SyntheticSections.cpp b/lld/ELF/SyntheticSections.cpp
index 38d9eeacf0cf6..8157365f89b30 100644
--- a/lld/ELF/SyntheticSections.cpp
+++ b/lld/ELF/SyntheticSections.cpp
@@ -1519,9 +1519,11 @@ void RelocationBaseSection::mergeRels() {
 
 void RelocationBaseSection::finalizeContents() {
   mergeRels();
-  // Cache the count for DT_RELACOUNT. This must not change after
-  // DynamicSection::finalizeContents sizes the .dynamic section.
-  numRelativeRelocs = relativeRelocs.size();
+  // Cache the count for DT_RELACOUNT. DynamicSection<ELFT>::computeContents
+  // uses ctx.arg.zCombreloc (not the per-section combreloc) to decide whether
+  // to emit DT_RELACOUNT, so this must match.
+  if (combreloc)
+    numRelativeRelocs = relativeRelocs.size();
   SymbolTableBaseSection *symTab = getPartition(ctx).dynSymTab.get();
 
   // When linking glibc statically, .rel{,a}.plt contains R_*_IRELATIVE
@@ -1685,23 +1687,22 @@ bool AndroidPackedRelocationSection<ELFT>::updateAllocSize(Ctx &ctx) {
   // The format header includes the number of relocations and the initial
   // offset (we set this to zero because the first relocation group will
   // perform the initial adjustment).
-  add(relocs.size());
+  add(relativeRelocs.size() + relocs.size());
   add(0);
 
-  std::vector<Elf_Rela> relatives, nonRelatives;
-
-  for (const DynamicReloc &rel : relocs) {
+  SymbolTableBaseSection *symTab = getPartition(ctx).dynSymTab.get();
+  auto makeRela = [&](const DynamicReloc &rel) {
     Elf_Rela r;
     r.r_offset = rel.getOffset();
-    r.setSymbolAndType(rel.getSymIndex(getPartition(ctx).dynSymTab.get()),
-                       rel.type, false);
+    r.setSymbolAndType(rel.getSymIndex(symTab), rel.type, false);
     r.r_addend = ctx.arg.isRela ? rel.computeAddend(ctx) : 0;
-
-    if (r.getType(ctx.arg.isMips64EL) == ctx.target->relativeRel)
-      relatives.push_back(r);
-    else
-      nonRelatives.push_back(r);
-  }
+    return r;
+  };
+  std::vector<Elf_Rela> relatives, nonRelatives;
+  for (const DynamicReloc &rel : relativeRelocs)
+    relatives.push_back(makeRela(rel));
+  for (const DynamicReloc &rel : relocs)
+    nonRelatives.push_back(makeRela(rel));
 
   llvm::sort(relatives, [](const Elf_Rel &a, const Elf_Rel &b) {
     return a.r_offset < b.r_offset;
diff --git a/lld/ELF/SyntheticSections.h b/lld/ELF/SyntheticSections.h
index 0373518ecd421..92dcbb922aa58 100644
--- a/lld/ELF/SyntheticSections.h
+++ b/lld/ELF/SyntheticSections.h
@@ -495,7 +495,7 @@ class RelocationBaseSection : public SyntheticSection {
   /// This overload can be used if the addends are written directly instead of
   /// using relocations on the input section (e.g. MipsGotSection::writeTo()).
   template <bool shard = false> void addReloc(const DynamicReloc &reloc) {
-    if (combreloc && reloc.type == relativeRel)
+    if (reloc.type == relativeRel)
       relativeRelocs.push_back(reloc);
     else
       relocs.push_back(reloc);
diff --git a/lld/test/ELF/combreloc.s b/lld/test/ELF/combreloc.s
index 59dedceb633fc..08e404c66676e 100644
--- a/lld/test/ELF/combreloc.s
+++ b/lld/test/ELF/combreloc.s
@@ -31,12 +31,12 @@
 # NOCOMB-NOT:    RELACOUNT
 # NOCOMB:      Relocations [
 # NOCOMB-NEXT:   Section ({{.*}}) .rela.dyn {
+# NOCOMB-NEXT:     0x3418 R_X86_64_RELATIVE - 0x3420
 # NOCOMB-NEXT:     0x33F8 R_X86_64_64 aaa 0x0
 # NOCOMB-NEXT:     0x3400 R_X86_64_64 ccc 0x0
 # NOCOMB-NEXT:     0x3408 R_X86_64_64 bbb 0x0
 # NOCOMB-NEXT:     0x3410 R_X86_64_64 aaa 0x0
 # NOCOMB-NEXT:     0x23F0 R_X86_64_GLOB_DAT aaa 0x0
-# NOCOMB-NEXT:     0x3418 R_X86_64_RELATIVE - 0x3420
 # NOCOMB-NEXT:   }
 
 .globl aaa, bbb, ccc



More information about the llvm-commits mailing list