Skip to content

[lld][ELF] Deduplicate PC-relative indirect relocation logic for RISC-V and LoongArch#176312

Merged
heiher merged 2 commits into
mainfrom
users/hev/dedup-pcrel-indirect
Jan 16, 2026
Merged

[lld][ELF] Deduplicate PC-relative indirect relocation logic for RISC-V and LoongArch#176312
heiher merged 2 commits into
mainfrom
users/hev/dedup-pcrel-indirect

Conversation

@heiher

@heiher heiher commented Jan 16, 2026

Copy link
Copy Markdown
Member

No description provided.

@llvmbot

llvmbot commented Jan 16, 2026

Copy link
Copy Markdown
Member

@llvm/pr-subscribers-lld

@llvm/pr-subscribers-lld-elf

Author: hev (heiher)

Changes

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

1 Files Affected:

  • (modified) lld/ELF/InputSection.cpp (+43-79)
diff --git a/lld/ELF/InputSection.cpp b/lld/ELF/InputSection.cpp
index a9afd3449ebb2..e2d2a8a49a47c 100644
--- a/lld/ELF/InputSection.cpp
+++ b/lld/ELF/InputSection.cpp
@@ -661,68 +661,40 @@ static uint64_t getARMStaticBase(const Symbol &sym) {
   return os->ptLoad->firstSec->addr;
 }
 
-// For RE_RISCV_PC_INDIRECT (R_RISCV_PCREL_LO12_{I,S}), the symbol actually
-// points the corresponding R_RISCV_PCREL_HI20 relocation, and the target VA
-// is calculated using PCREL_HI20's symbol.
-//
-// This function returns the R_RISCV_PCREL_HI20 relocation from the
-// R_RISCV_PCREL_LO12 relocation.
-static Relocation *getRISCVPCRelHi20(Ctx &ctx, const InputSectionBase *loSec,
-                                     const Relocation &loReloc) {
-  uint64_t addend = loReloc.addend;
-  Symbol *sym = loReloc.sym;
+struct RISCVPCRel {
+  static constexpr const char *loReloc = "R_RISCV_PCREL_LO12";
+  static constexpr const char *hiReloc = "R_RISCV_PCREL_HI20";
 
-  const Defined *d = cast<Defined>(sym);
-  if (!d->section) {
-    Err(ctx) << loSec->getLocation(loReloc.offset)
-             << ": R_RISCV_PCREL_LO12 relocation points to an absolute symbol: "
-             << sym->getName();
-    return nullptr;
+  static bool isHiReloc(uint32_t type) {
+    return type == R_RISCV_PCREL_HI20 || type == R_RISCV_GOT_HI20 ||
+           type == R_RISCV_TLS_GD_HI20 || type == R_RISCV_TLS_GOT_HI20;
   }
-  InputSection *hiSec = cast<InputSection>(d->section);
-
-  if (hiSec != loSec)
-    Err(ctx) << loSec->getLocation(loReloc.offset)
-             << ": R_RISCV_PCREL_LO12 relocation points to a symbol '"
-             << sym->getName() << "' in a different section '" << hiSec->name
-             << "'";
-
-  if (addend != 0)
-    Warn(ctx) << loSec->getLocation(loReloc.offset)
-              << ": non-zero addend in R_RISCV_PCREL_LO12 relocation to "
-              << hiSec->getObjMsg(d->value) << " is ignored";
-
-  // Relocations are sorted by offset, so we can use std::equal_range to do
-  // binary search.
-  Relocation hiReloc;
-  hiReloc.offset = d->value;
-  auto range =
-      std::equal_range(hiSec->relocs().begin(), hiSec->relocs().end(), hiReloc,
-                       [](const Relocation &lhs, const Relocation &rhs) {
-                         return lhs.offset < rhs.offset;
-                       });
-
-  for (auto it = range.first; it != range.second; ++it)
-    if (it->type == R_RISCV_PCREL_HI20 || it->type == R_RISCV_GOT_HI20 ||
-        it->type == R_RISCV_TLS_GD_HI20 || it->type == R_RISCV_TLS_GOT_HI20)
-      return &*it;
-
-  Err(ctx) << loSec->getLocation(loReloc.offset)
-           << ": R_RISCV_PCREL_LO12 relocation points to "
-           << hiSec->getObjMsg(d->value)
-           << " without an associated R_RISCV_PCREL_HI20 relocation";
-  return nullptr;
-}
+};
+
+struct LoongArchPCAdd {
+  static constexpr const char *loReloc = "R_LARCH_*PCADD_LO12";
+  static constexpr const char *hiReloc = "R_LARCH_*PCADD_HI20";
+
+  static bool isHiReloc(uint32_t type) {
+    return type == R_LARCH_PCADD_HI20 || type == R_LARCH_GOT_PCADD_HI20 ||
+           type == R_LARCH_TLS_IE_PCADD_HI20 ||
+           type == R_LARCH_TLS_LD_PCADD_HI20 ||
+           type == R_LARCH_TLS_GD_PCADD_HI20 ||
+           type == R_LARCH_TLS_DESC_PCADD_HI20;
+  }
+};
 
-// For RE_LARCH_PC_INDIRECT (R_LARCH_*PCADD_LO12), the symbol actually points
-// the corresponding R_LARCH_*PCADD_HI20 relocation, and the target VA is
-// calculated using PCADD_HI20's symbol.
+// For PC-relative indirect relocations (e.g. R_RISCV_PCREL_LO12_* and
+// R_LARCH_*PCADD_LO12), the symbol referenced by the LO12 relocation does not
+// directly represent the final target address. Instead, it points to the
+// corresponding HI20 relocation, and the target VA is computed using the
+// symbol associated with that HI20 relocation.
 //
-// This function returns the R_LARCH_*PCADD_HI20 relocation from the
-// R_LARCH_*PCADD_LO12 relocation.
-static Relocation *getLoongArchPCAddHi20(Ctx &ctx,
-                                         const InputSectionBase *loSec,
-                                         const Relocation &loReloc) {
+// This helper locates and returns the matching HI20 relocation corresponding
+// to a given LO12 relocation.
+template <typename PCRel>
+static Relocation *getPCRelHi20(Ctx &ctx, const InputSectionBase *loSec,
+                                const Relocation &loReloc) {
   int64_t addend = loReloc.addend;
   Symbol *sym = loReloc.sym;
 
@@ -733,25 +705,22 @@ static Relocation *getLoongArchPCAddHi20(Ctx &ctx,
     return nullptr;
   }
   if (!d->section) {
-    Err(ctx)
-        << loSec->getLocation(loReloc.offset)
-        << ": R_LARCH_*PCADD_LO12 relocation points to an absolute symbol: "
-        << sym->getName();
+    Err(ctx) << loSec->getLocation(loReloc.offset) << ": " << PCRel::loReloc
+             << " relocation points to an absolute symbol: " << sym->getName();
     return nullptr;
   }
   InputSection *hiSec = cast<InputSection>(d->section);
 
   if (hiSec != loSec) {
-    Err(ctx) << loSec->getLocation(loReloc.offset)
-             << ": R_LARCH_*PCADD_LO12 relocation points to a symbol '"
-             << sym->getName() << "' in a different section '" << hiSec->name
-             << "'";
+    Err(ctx) << loSec->getLocation(loReloc.offset) << ": " << PCRel::loReloc
+             << " relocation points to a symbol '" << sym->getName()
+             << "' in a different section '" << hiSec->name << "'";
     return nullptr;
   }
 
   if (addend != 0)
-    Warn(ctx) << loSec->getLocation(loReloc.offset)
-              << ": non-zero addend in R_LARCH_*PCADD_LO12 relocation to "
+    Warn(ctx) << loSec->getLocation(loReloc.offset) << ": non-zero addend in "
+              << PCRel::loReloc << " relocation to "
               << hiSec->getObjMsg(d->value) << " is ignored";
 
   // Relocations are sorted by offset, so we can use std::equal_range to do
@@ -765,17 +734,12 @@ static Relocation *getLoongArchPCAddHi20(Ctx &ctx,
                        });
 
   for (auto it = range.first; it != range.second; ++it)
-    if (it->type == R_LARCH_PCADD_HI20 || it->type == R_LARCH_GOT_PCADD_HI20 ||
-        it->type == R_LARCH_TLS_IE_PCADD_HI20 ||
-        it->type == R_LARCH_TLS_LD_PCADD_HI20 ||
-        it->type == R_LARCH_TLS_GD_PCADD_HI20 ||
-        it->type == R_LARCH_TLS_DESC_PCADD_HI20)
+    if (PCRel::isHiReloc(it->type))
       return &*it;
 
-  Err(ctx) << loSec->getLocation(loReloc.offset)
-           << ": R_LARCH_*PCADD_LO12 relocation points to "
-           << hiSec->getObjMsg(d->value)
-           << " without an associated R_LARCH_*PCADD_HI20 relocation";
+  Err(ctx) << loSec->getLocation(loReloc.offset) << ": " << PCRel::loReloc
+           << " relocation points to " << hiSec->getObjMsg(d->value)
+           << " without an associated " << PCRel::hiReloc << " relocation";
   return nullptr;
 }
 
@@ -954,12 +918,12 @@ uint64_t InputSectionBase::getRelocTargetVA(Ctx &ctx, const Relocation &r,
     return getAArch64Page(val) - getAArch64Page(p);
   }
   case RE_RISCV_PC_INDIRECT: {
-    if (const Relocation *hiRel = getRISCVPCRelHi20(ctx, this, r))
+    if (const Relocation *hiRel = getPCRelHi20<RISCVPCRel>(ctx, this, r))
       return getRelocTargetVA(ctx, *hiRel, r.sym->getVA(ctx));
     return 0;
   }
   case RE_LOONGARCH_PC_INDIRECT: {
-    if (const Relocation *hiRel = getLoongArchPCAddHi20(ctx, this, r))
+    if (const Relocation *hiRel = getPCRelHi20<LoongArchPCAdd>(ctx, this, r))
       return getRelocTargetVA(ctx, *hiRel, r.sym->getVA(ctx, a));
     return 0;
   }

@heiher heiher requested review from MaskRay and jrtc27 January 16, 2026 05:54
Comment thread lld/ELF/InputSection.cpp Outdated
@heiher heiher merged commit 3af2e51 into main Jan 16, 2026
11 checks passed
@heiher heiher deleted the users/hev/dedup-pcrel-indirect branch January 16, 2026 09:35
kkwli pushed a commit to kkwli/llvm-project that referenced this pull request Jan 16, 2026
Priyanshu3820 pushed a commit to Priyanshu3820/llvm-project that referenced this pull request Jan 18, 2026
heiher added a commit that referenced this pull request Jan 19, 2026
c-rhodes pushed a commit that referenced this pull request Jan 22, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants