[lld] [ELF] Move target-specific synthetic sections into Arch/ files (PR #184057)

Fangrui Song via llvm-commits llvm-commits at lists.llvm.org
Mon Mar 2 09:56:15 PST 2026


https://github.com/MaskRay updated https://github.com/llvm/llvm-project/pull/184057

>From 0789278aa9cb846310504c1aeb421c28373f31e2 Mon Sep 17 00:00:00 2001
From: Fangrui Song <i at maskray.me>
Date: Sun, 1 Mar 2026 18:16:53 -0800
Subject: [PATCH 1/2] [ELF] Move target-specific synthetic sections into Arch/
 files

Add a TargetInfo::initTargetSections hook, called from
createSyntheticSections, for targets to create target-specific synthetic
sections.

Move target-specific synthetic section classes from
SyntheticSections.h/.cpp into their respective Arch/ files. Remove the
target-specific prefix while moving classes.

Some synthetic sections (e.g. ARMExidxSyntheticSection,
PPC64LongBranchTargetSection) have their members referenced by other
generic files, therefore they are not moved.
---
 lld/ELF/Arch/ARM.cpp          |  46 ++++++-
 lld/ELF/Arch/Mips.cpp         | 179 ++++++++++++++++++++++++
 lld/ELF/Arch/PPC.cpp          |  41 ++++++
 lld/ELF/Arch/PPC64.cpp        |   7 +
 lld/ELF/Arch/X86.cpp          |  21 +++
 lld/ELF/Arch/X86_64.cpp       |  21 +++
 lld/ELF/Config.h              |   9 +-
 lld/ELF/SyntheticSections.cpp | 253 +---------------------------------
 lld/ELF/SyntheticSections.h   | 120 ----------------
 lld/ELF/Target.h              |   1 +
 10 files changed, 316 insertions(+), 382 deletions(-)

diff --git a/lld/ELF/Arch/ARM.cpp b/lld/ELF/Arch/ARM.cpp
index fc6eee24cf4ff..b4486f53a0042 100644
--- a/lld/ELF/Arch/ARM.cpp
+++ b/lld/ELF/Arch/ARM.cpp
@@ -25,11 +25,17 @@ using namespace lld;
 using namespace lld::elf;
 using namespace llvm::object;
 
+// Cortex-M Security Extensions. Prefix for functions that should be exported
+// for the non-secure world.
+constexpr char ACLESESYM_PREFIX[] = "__acle_se_";
+constexpr int ACLESESYM_SIZE = 8;
+
 namespace {
 class ARM final : public TargetInfo {
 public:
   ARM(Ctx &);
   uint32_t calcEFlags() const override;
+  void initTargetSections() override;
   RelExpr getRelExpr(RelType type, const Symbol &s,
                      const uint8_t *loc) const override;
   RelType getDynRel(RelType type) const override;
@@ -64,6 +70,33 @@ class ARM final : public TargetInfo {
                       int group, bool check) const;
 };
 enum class CodeState { Data = 0, Thumb = 2, Arm = 4 };
+
+struct CmseSGVeneer {
+  CmseSGVeneer(Symbol *sym, Symbol *acleSeSym,
+               std::optional<uint64_t> addr = std::nullopt)
+      : sym(sym), acleSeSym(acleSeSym), entAddr{addr} {}
+  static const size_t size{ACLESESYM_SIZE};
+  std::optional<uint64_t> getAddr() const { return entAddr; };
+
+  Symbol *sym;
+  Symbol *acleSeSym;
+  uint64_t offset = 0;
+  const std::optional<uint64_t> entAddr;
+};
+
+struct ArmCmseSGSection : SyntheticSection {
+  ArmCmseSGSection(Ctx &ctx);
+  bool isNeeded() const override { return !entries.empty(); }
+  size_t getSize() const override;
+  void writeTo(uint8_t *buf) override;
+  void addSGVeneer(Symbol *sym, Symbol *ext_sym);
+  void addMappingSymbol();
+  void finalizeContents() override;
+  uint64_t impLibMaxAddr = 0;
+  SmallVector<std::pair<Symbol *, Symbol *>, 0> entries;
+  SmallVector<std::unique_ptr<CmseSGVeneer>, 0> sgVeneers;
+  uint64_t newEntries = 0;
+};
 } // namespace
 
 ARM::ARM(Ctx &ctx) : TargetInfo(ctx) {
@@ -108,6 +141,11 @@ uint32_t ARM::calcEFlags() const {
   return EF_ARM_EABI_VER5 | abiFloatType | armBE8;
 }
 
+void ARM::initTargetSections() {
+  ctx.in.armCmseSGSection = std::make_unique<ArmCmseSGSection>(ctx);
+  ctx.inputSections.push_back(ctx.in.armCmseSGSection.get());
+}
+
 // Only needed to support relocations used by relocateNonAlloc and
 // preprocessRelocs.
 RelExpr ARM::getRelExpr(RelType type, const Symbol &s,
@@ -1444,20 +1482,20 @@ void ArmCmseSGSection::addSGVeneer(Symbol *acleSeSym, Symbol *sym) {
     return;
   // Only secure symbols with values equal to that of it's non-secure
   // counterpart needs to be in the .gnu.sgstubs section.
-  std::unique_ptr<ArmCmseSGVeneer> ss;
+  std::unique_ptr<CmseSGVeneer> ss;
   auto it = ctx.symtab->cmseImportLib.find(sym->getName());
   if (it != ctx.symtab->cmseImportLib.end()) {
     Defined *impSym = it->second;
-    ss = std::make_unique<ArmCmseSGVeneer>(sym, acleSeSym, impSym->value);
+    ss = std::make_unique<CmseSGVeneer>(sym, acleSeSym, impSym->value);
   } else {
-    ss = std::make_unique<ArmCmseSGVeneer>(sym, acleSeSym);
+    ss = std::make_unique<CmseSGVeneer>(sym, acleSeSym);
     ++newEntries;
   }
   sgVeneers.emplace_back(std::move(ss));
 }
 
 void ArmCmseSGSection::writeTo(uint8_t *buf) {
-  for (std::unique_ptr<ArmCmseSGVeneer> &s : sgVeneers) {
+  for (std::unique_ptr<CmseSGVeneer> &s : sgVeneers) {
     uint8_t *p = buf + s->offset;
     write16(ctx, p + 0, 0xe97f); // SG
     write16(ctx, p + 2, 0xe97f);
diff --git a/lld/ELF/Arch/Mips.cpp b/lld/ELF/Arch/Mips.cpp
index 1f8abbb98b1fd..1c319b1d760e4 100644
--- a/lld/ELF/Arch/Mips.cpp
+++ b/lld/ELF/Arch/Mips.cpp
@@ -24,6 +24,7 @@ template <class ELFT> class MIPS final : public TargetInfo {
 public:
   MIPS(Ctx &);
   uint32_t calcEFlags() const override;
+  void initTargetSections() override;
   RelExpr getRelExpr(RelType type, const Symbol &s,
                      const uint8_t *loc) const override;
   int64_t getImplicitAddend(const uint8_t *buf, RelType type) const override;
@@ -42,6 +43,47 @@ template <class ELFT> class MIPS final : public TargetInfo {
                 uint64_t val) const override;
   bool usesOnlyLowPageBits(RelType type) const override;
 };
+
+struct RldMapSection : SyntheticSection {
+  RldMapSection(Ctx &ctx)
+      : SyntheticSection(ctx, ".rld_map", SHT_PROGBITS, SHF_ALLOC | SHF_WRITE,
+                         ctx.arg.wordsize) {}
+  size_t getSize() const override { return ctx.arg.wordsize; }
+  void writeTo(uint8_t *buf) override {}
+};
+
+template <class ELFT> struct AbiFlagsSection : SyntheticSection {
+  using Elf_Mips_ABIFlags = llvm::object::Elf_Mips_ABIFlags<ELFT>;
+  AbiFlagsSection(Ctx &ctx);
+  bool isNeeded() const override { return needed; }
+  size_t getSize() const override { return sizeof(Elf_Mips_ABIFlags); }
+  void writeTo(uint8_t *buf) override { memcpy(buf, &flags, sizeof(flags)); }
+  Elf_Mips_ABIFlags flags = {};
+  bool needed = false;
+};
+
+template <class ELFT> struct OptionsSection : SyntheticSection {
+  using Elf_Mips_Options = llvm::object::Elf_Mips_Options<ELFT>;
+  using Elf_Mips_RegInfo = llvm::object::Elf_Mips_RegInfo<ELFT>;
+  OptionsSection(Ctx &ctx);
+  bool isNeeded() const override { return needed; }
+  size_t getSize() const override {
+    return sizeof(Elf_Mips_Options) + sizeof(Elf_Mips_RegInfo);
+  }
+  void writeTo(uint8_t *buf) override;
+  Elf_Mips_RegInfo reginfo = {};
+  bool needed = false;
+};
+
+template <class ELFT> struct ReginfoSection : SyntheticSection {
+  using Elf_Mips_RegInfo = llvm::object::Elf_Mips_RegInfo<ELFT>;
+  ReginfoSection(Ctx &ctx);
+  bool isNeeded() const override { return needed; }
+  size_t getSize() const override { return sizeof(Elf_Mips_RegInfo); }
+  void writeTo(uint8_t *buf) override;
+  Elf_Mips_RegInfo reginfo = {};
+  bool needed = false;
+};
 } // namespace
 
 uint64_t elf::getMipsPageAddr(uint64_t addr) {
@@ -79,6 +121,19 @@ template <class ELFT> uint32_t MIPS<ELFT>::calcEFlags() const {
   return calcMipsEFlags<ELFT>(ctx);
 }
 
+template <class ELFT> void MIPS<ELFT>::initTargetSections() {
+  if (!ctx.arg.shared && ctx.hasDynsym) {
+    ctx.in.mipsRldMap = std::make_unique<RldMapSection>(ctx);
+    ctx.inputSections.push_back(ctx.in.mipsRldMap.get());
+  }
+  ctx.in.mipsAbiFlags = std::make_unique<AbiFlagsSection<ELFT>>(ctx);
+  ctx.inputSections.push_back(ctx.in.mipsAbiFlags.get());
+  ctx.in.mipsOptions = std::make_unique<OptionsSection<ELFT>>(ctx);
+  ctx.inputSections.push_back(ctx.in.mipsOptions.get());
+  ctx.in.mipsReginfo = std::make_unique<ReginfoSection<ELFT>>(ctx);
+  ctx.inputSections.push_back(ctx.in.mipsReginfo.get());
+}
+
 template <class ELFT>
 RelExpr MIPS<ELFT>::getRelExpr(RelType type, const Symbol &s,
                                const uint8_t *loc) const {
@@ -906,6 +961,130 @@ template <class ELFT> bool elf::isMipsPIC(const Defined *sym) {
   return cast<ObjFile<ELFT>>(file)->getObj().getHeader().e_flags & EF_MIPS_PIC;
 }
 
+template <class ELFT>
+AbiFlagsSection<ELFT>::AbiFlagsSection(Ctx &ctx)
+    : SyntheticSection(ctx, ".MIPS.abiflags", SHT_MIPS_ABIFLAGS, SHF_ALLOC, 8) {
+  this->entsize = sizeof(Elf_Mips_ABIFlags);
+
+  for (InputSectionBase *sec : ctx.inputSections) {
+    if (sec->type != SHT_MIPS_ABIFLAGS)
+      continue;
+    sec->markDead();
+    needed = true;
+
+    const size_t size = sec->content().size();
+    // Older version of BFD (such as the default FreeBSD linker) concatenate
+    // .MIPS.abiflags instead of merging. To allow for this case (or potential
+    // zero padding) we ignore everything after the first Elf_Mips_ABIFlags
+    if (size < sizeof(Elf_Mips_ABIFlags)) {
+      Err(ctx) << sec->file << ": invalid size of .MIPS.abiflags section: got "
+               << size << " instead of " << sizeof(Elf_Mips_ABIFlags);
+      return;
+    }
+    auto *s =
+        reinterpret_cast<const Elf_Mips_ABIFlags *>(sec->content().data());
+    if (s->version != 0) {
+      Err(ctx) << sec->file << ": unexpected .MIPS.abiflags version "
+               << s->version;
+      return;
+    }
+
+    // LLD checks ISA compatibility in calcMipsEFlags(). Here we just
+    // select the highest number of ISA/Rev/Ext.
+    flags.isa_level = std::max(flags.isa_level, s->isa_level);
+    flags.isa_rev = std::max(flags.isa_rev, s->isa_rev);
+    flags.isa_ext = std::max(flags.isa_ext, s->isa_ext);
+    flags.gpr_size = std::max(flags.gpr_size, s->gpr_size);
+    flags.cpr1_size = std::max(flags.cpr1_size, s->cpr1_size);
+    flags.cpr2_size = std::max(flags.cpr2_size, s->cpr2_size);
+    flags.ases |= s->ases;
+    flags.flags1 |= s->flags1;
+    flags.flags2 |= s->flags2;
+    flags.fp_abi =
+        elf::getMipsFpAbiFlag(ctx, sec->file, flags.fp_abi, s->fp_abi);
+  }
+}
+
+template <class ELFT>
+OptionsSection<ELFT>::OptionsSection(Ctx &ctx)
+    : SyntheticSection(ctx, ".MIPS.options", SHT_MIPS_OPTIONS, SHF_ALLOC, 8) {
+  this->entsize = sizeof(Elf_Mips_Options) + sizeof(Elf_Mips_RegInfo);
+
+  // N64 ABI only.
+  if (!ELFT::Is64Bits)
+    return;
+
+  for (InputSectionBase *sec : ctx.inputSections) {
+    if (sec->type != SHT_MIPS_OPTIONS)
+      continue;
+    sec->markDead();
+    needed = true;
+
+    ArrayRef<uint8_t> d = sec->content();
+    while (!d.empty()) {
+      if (d.size() < sizeof(Elf_Mips_Options)) {
+        Err(ctx) << sec->file << ": invalid size of .MIPS.options section";
+        break;
+      }
+
+      auto *opt = reinterpret_cast<const Elf_Mips_Options *>(d.data());
+      if (opt->kind == ODK_REGINFO) {
+        reginfo.ri_gprmask |= opt->getRegInfo().ri_gprmask;
+        sec->getFile<ELFT>()->mipsGp0 = opt->getRegInfo().ri_gp_value;
+        break;
+      }
+
+      if (!opt->size) {
+        Err(ctx) << sec->file << ": zero option descriptor size";
+        break;
+      }
+      d = d.slice(opt->size);
+    }
+  }
+}
+
+template <class ELFT> void OptionsSection<ELFT>::writeTo(uint8_t *buf) {
+  auto *options = reinterpret_cast<Elf_Mips_Options *>(buf);
+  options->kind = ODK_REGINFO;
+  options->size = getSize();
+
+  if (!ctx.arg.relocatable)
+    reginfo.ri_gp_value = ctx.in.mipsGot->getGp();
+  memcpy(buf + sizeof(Elf_Mips_Options), &reginfo, sizeof(reginfo));
+}
+
+template <class ELFT>
+ReginfoSection<ELFT>::ReginfoSection(Ctx &ctx)
+    : SyntheticSection(ctx, ".reginfo", SHT_MIPS_REGINFO, SHF_ALLOC, 4) {
+  this->entsize = sizeof(Elf_Mips_RegInfo);
+
+  // Section should be alive for O32 and N32 ABIs only.
+  if (ELFT::Is64Bits)
+    return;
+
+  for (InputSectionBase *sec : ctx.inputSections) {
+    if (sec->type != SHT_MIPS_REGINFO)
+      continue;
+    sec->markDead();
+    needed = true;
+
+    if (sec->content().size() != sizeof(Elf_Mips_RegInfo)) {
+      Err(ctx) << sec->file << ": invalid size of .reginfo section";
+      return;
+    }
+
+    auto *r = reinterpret_cast<const Elf_Mips_RegInfo *>(sec->content().data());
+    reginfo.ri_gprmask |= r->ri_gprmask;
+    sec->getFile<ELFT>()->mipsGp0 = r->ri_gp_value;
+  }
+}
+
+template <class ELFT> void ReginfoSection<ELFT>::writeTo(uint8_t *buf) {
+  if (!ctx.arg.relocatable)
+    reginfo.ri_gp_value = ctx.in.mipsGot->getGp();
+  memcpy(buf, &reginfo, sizeof(reginfo));
+}
+
 void elf::setMipsTargetInfo(Ctx &ctx) {
   switch (ctx.arg.ekind) {
   case ELF32LEKind: {
diff --git a/lld/ELF/Arch/PPC.cpp b/lld/ELF/Arch/PPC.cpp
index d517125d16a3d..e6290874bec2f 100644
--- a/lld/ELF/Arch/PPC.cpp
+++ b/lld/ELF/Arch/PPC.cpp
@@ -27,6 +27,7 @@ namespace {
 class PPC final : public TargetInfo {
 public:
   PPC(Ctx &);
+  void initTargetSections() override;
   RelExpr getRelExpr(RelType type, const Symbol &s,
                      const uint8_t *loc) const override;
   RelType getDynRel(RelType type) const override;
@@ -52,12 +53,23 @@ class PPC final : public TargetInfo {
   bool inBranchRange(RelType type, uint64_t src, uint64_t dst) const override;
   void relocate(uint8_t *loc, const Relocation &rel,
                 uint64_t val) const override;
+
 private:
   void relaxTlsGdToIe(uint8_t *loc, const Relocation &rel, uint64_t val) const;
   void relaxTlsGdToLe(uint8_t *loc, const Relocation &rel, uint64_t val) const;
   void relaxTlsLdToLe(uint8_t *loc, const Relocation &rel, uint64_t val) const;
   void relaxTlsIeToLe(uint8_t *loc, const Relocation &rel, uint64_t val) const;
 };
+
+struct Got2Section : SyntheticSection {
+  Got2Section(Ctx &ctx)
+      : SyntheticSection(ctx, ".got2", SHT_PROGBITS, SHF_ALLOC | SHF_WRITE, 4) {
+  }
+  bool isNeeded() const override;
+  size_t getSize() const override { return 0; }
+  void writeTo(uint8_t *buf) override {}
+  void finalizeContents() override;
+};
 } // namespace
 
 static uint16_t lo(uint32_t v) { return v; }
@@ -180,6 +192,11 @@ PPC::PPC(Ctx &ctx) : TargetInfo(ctx) {
   write32(ctx, trapInstr.data(), 0x7fe00008);
 }
 
+void PPC::initTargetSections() {
+  ctx.in.ppc32Got2 = std::make_unique<Got2Section>(ctx);
+  ctx.inputSections.push_back(ctx.in.ppc32Got2.get());
+}
+
 void PPC::writeIplt(uint8_t *buf, const Symbol &sym,
                     uint64_t /*pltEntryAddr*/) const {
   // In -pie or -shared mode, assume r30 points to .got2+0x8000, and use a
@@ -601,3 +618,27 @@ void PPC::relaxTlsIeToLe(uint8_t *loc, const Relocation &rel,
 }
 
 void elf::setPPCTargetInfo(Ctx &ctx) { ctx.target.reset(new PPC(ctx)); }
+
+bool Got2Section::isNeeded() const {
+  for (SectionCommand *cmd : getParent()->commands)
+    if (auto *isd = dyn_cast<InputSectionDescription>(cmd))
+      for (InputSection *isec : isd->sections)
+        if (isec != this)
+          return true;
+  return false;
+}
+
+void Got2Section::finalizeContents() {
+  // PPC32 may create multiple GOT sections for -fPIC/-fPIE, one per file in
+  // .got2 . This function computes outSecOff of each .got2 to be used in
+  // PPC32PltCallStub::writeTo(). The purpose of this empty synthetic section is
+  // to collect input sections named ".got2".
+  for (SectionCommand *cmd : getParent()->commands)
+    if (auto *isd = dyn_cast<InputSectionDescription>(cmd)) {
+      for (InputSection *isec : isd->sections) {
+        // isec->file may be nullptr for MergeSyntheticSection.
+        if (isec != this && isec->file)
+          isec->file->ppc32Got2 = isec;
+      }
+    }
+}
diff --git a/lld/ELF/Arch/PPC64.cpp b/lld/ELF/Arch/PPC64.cpp
index 59dea59d16e68..32a1c04ed61a6 100644
--- a/lld/ELF/Arch/PPC64.cpp
+++ b/lld/ELF/Arch/PPC64.cpp
@@ -169,6 +169,7 @@ class PPC64 final : public TargetInfo {
 public:
   PPC64(Ctx &);
   uint32_t calcEFlags() const override;
+  void initTargetSections() override;
   RelExpr getRelExpr(RelType type, const Symbol &s,
                      const uint8_t *loc) const override;
   RelType getDynRel(RelType type) const override;
@@ -969,6 +970,12 @@ void PPC64::relaxTlsIeToLe(uint8_t *loc, const Relocation &rel,
   }
 }
 
+void PPC64::initTargetSections() {
+  ctx.in.ppc64LongBranchTarget =
+      std::make_unique<PPC64LongBranchTargetSection>(ctx);
+  ctx.inputSections.push_back(ctx.in.ppc64LongBranchTarget.get());
+}
+
 // Only needed to support relocations used by relocateNonAlloc and relocateEh.
 RelExpr PPC64::getRelExpr(RelType type, const Symbol &s,
                           const uint8_t *loc) const {
diff --git a/lld/ELF/Arch/X86.cpp b/lld/ELF/Arch/X86.cpp
index 30d78e9ebd460..94d3b1696aea5 100644
--- a/lld/ELF/Arch/X86.cpp
+++ b/lld/ELF/Arch/X86.cpp
@@ -23,6 +23,7 @@ namespace {
 class X86 : public TargetInfo {
 public:
   X86(Ctx &);
+  void initTargetSections() override;
   RelExpr getRelExpr(RelType type, const Symbol &s,
                      const uint8_t *loc) const override;
   int64_t getImplicitAddend(const uint8_t *buf, RelType type) const override;
@@ -46,6 +47,19 @@ class X86 : public TargetInfo {
   void relaxTlsLdToLe(uint8_t *loc, const Relocation &rel, uint64_t val) const;
   void relaxTlsIeToLe(uint8_t *loc, const Relocation &rel, uint64_t val) const;
 };
+
+struct IBTPltSection : SyntheticSection {
+  IBTPltSection(Ctx &ctx)
+      : SyntheticSection(ctx, ".plt", SHT_PROGBITS, SHF_ALLOC | SHF_EXECINSTR,
+                         16) {}
+  bool isNeeded() const override { return ctx.in.plt->getNumEntries() > 0; }
+  size_t getSize() const override {
+    return 16 + ctx.in.plt->getNumEntries() * ctx.target->pltEntrySize;
+  }
+  void writeTo(uint8_t *buf) override {
+    ctx.target->writeIBTPlt(buf, ctx.in.plt->getNumEntries());
+  }
+};
 } // namespace
 
 X86::X86(Ctx &ctx) : TargetInfo(ctx) {
@@ -70,6 +84,13 @@ X86::X86(Ctx &ctx) : TargetInfo(ctx) {
   defaultImageBase = 0x400000;
 }
 
+void X86::initTargetSections() {
+  if (ctx.arg.andFeatures & GNU_PROPERTY_X86_FEATURE_1_IBT) {
+    ctx.in.ibtPlt = std::make_unique<IBTPltSection>(ctx);
+    ctx.inputSections.push_back(ctx.in.ibtPlt.get());
+  }
+}
+
 // Only needed to support relocations used by relocateNonAlloc and relocateEh.
 RelExpr X86::getRelExpr(RelType type, const Symbol &s,
                         const uint8_t *loc) const {
diff --git a/lld/ELF/Arch/X86_64.cpp b/lld/ELF/Arch/X86_64.cpp
index 2d12b5cd9df04..1bd8619cf601f 100644
--- a/lld/ELF/Arch/X86_64.cpp
+++ b/lld/ELF/Arch/X86_64.cpp
@@ -28,6 +28,7 @@ namespace {
 class X86_64 : public TargetInfo {
 public:
   X86_64(Ctx &);
+  void initTargetSections() override;
   RelExpr getRelExpr(RelType type, const Symbol &s,
                      const uint8_t *loc) const override;
   RelType getDynRel(RelType type) const override;
@@ -61,6 +62,19 @@ class X86_64 : public TargetInfo {
   void relaxTlsLdToLe(uint8_t *loc, const Relocation &rel, uint64_t val) const;
   void relaxTlsIeToLe(uint8_t *loc, const Relocation &rel, uint64_t val) const;
 };
+
+struct IBTPltSection : SyntheticSection {
+  IBTPltSection(Ctx &ctx)
+      : SyntheticSection(ctx, ".plt", SHT_PROGBITS, SHF_ALLOC | SHF_EXECINSTR,
+                         16) {}
+  bool isNeeded() const override { return ctx.in.plt->getNumEntries() > 0; }
+  size_t getSize() const override {
+    return 16 + ctx.in.plt->getNumEntries() * ctx.target->pltEntrySize;
+  }
+  void writeTo(uint8_t *buf) override {
+    ctx.target->writeIBTPlt(buf, ctx.in.plt->getNumEntries());
+  }
+};
 } // namespace
 
 // This is vector of NOP instructions of sizes from 1 to 8 bytes.  The
@@ -355,6 +369,13 @@ bool X86_64::relaxOnce(int pass) const {
   return changed;
 }
 
+void X86_64::initTargetSections() {
+  if (ctx.arg.andFeatures & GNU_PROPERTY_X86_FEATURE_1_IBT) {
+    ctx.in.ibtPlt = std::make_unique<IBTPltSection>(ctx);
+    ctx.inputSections.push_back(ctx.in.ibtPlt.get());
+  }
+}
+
 // Only needed to support relocations used by relocateNonAlloc and relocateEh.
 RelExpr X86_64::getRelExpr(RelType type, const Symbol &s,
                            const uint8_t *loc) const {
diff --git a/lld/ELF/Config.h b/lld/ELF/Config.h
index 237df52194210..a9f74460f6f99 100644
--- a/lld/ELF/Config.h
+++ b/lld/ELF/Config.h
@@ -59,13 +59,10 @@ class BssSection;
 class GdbIndexSection;
 class GotPltSection;
 class GotSection;
-class IBTPltSection;
 class IgotPltSection;
 class InputSection;
 class IpltSection;
 class MipsGotSection;
-class MipsRldMapSection;
-class PPC32Got2Section;
 class PPC64LongBranchTargetSection;
 class PltSection;
 class RelocationBaseSection;
@@ -581,13 +578,13 @@ struct InStruct {
   std::unique_ptr<MipsGotSection> mipsGot;
   std::unique_ptr<SyntheticSection> mipsOptions;
   std::unique_ptr<SyntheticSection> mipsReginfo;
-  std::unique_ptr<MipsRldMapSection> mipsRldMap;
+  std::unique_ptr<SyntheticSection> mipsRldMap;
   std::unique_ptr<SyntheticSection> partEnd;
   std::unique_ptr<SyntheticSection> partIndex;
   std::unique_ptr<PltSection> plt;
   std::unique_ptr<IpltSection> iplt;
-  std::unique_ptr<PPC32Got2Section> ppc32Got2;
-  std::unique_ptr<IBTPltSection> ibtPlt;
+  std::unique_ptr<SyntheticSection> ppc32Got2;
+  std::unique_ptr<SyntheticSection> ibtPlt;
   std::unique_ptr<RelocationBaseSection> relaPlt;
   // Non-SHF_ALLOC sections
   std::unique_ptr<SyntheticSection> debugNames;
diff --git a/lld/ELF/SyntheticSections.cpp b/lld/ELF/SyntheticSections.cpp
index 2cfc88d8389b0..78eb77fdc614d 100644
--- a/lld/ELF/SyntheticSections.cpp
+++ b/lld/ELF/SyntheticSections.cpp
@@ -90,176 +90,6 @@ MergeInputSection *elf::createCommentSection(Ctx &ctx) {
   return sec;
 }
 
-// .MIPS.abiflags section.
-template <class ELFT>
-MipsAbiFlagsSection<ELFT>::MipsAbiFlagsSection(Ctx &ctx,
-                                               Elf_Mips_ABIFlags flags)
-    : SyntheticSection(ctx, ".MIPS.abiflags", SHT_MIPS_ABIFLAGS, SHF_ALLOC, 8),
-      flags(flags) {
-  this->entsize = sizeof(Elf_Mips_ABIFlags);
-}
-
-template <class ELFT> void MipsAbiFlagsSection<ELFT>::writeTo(uint8_t *buf) {
-  memcpy(buf, &flags, sizeof(flags));
-}
-
-template <class ELFT>
-std::unique_ptr<MipsAbiFlagsSection<ELFT>>
-MipsAbiFlagsSection<ELFT>::create(Ctx &ctx) {
-  Elf_Mips_ABIFlags flags = {};
-  bool create = false;
-
-  for (InputSectionBase *sec : ctx.inputSections) {
-    if (sec->type != SHT_MIPS_ABIFLAGS)
-      continue;
-    sec->markDead();
-    create = true;
-
-    const size_t size = sec->content().size();
-    // Older version of BFD (such as the default FreeBSD linker) concatenate
-    // .MIPS.abiflags instead of merging. To allow for this case (or potential
-    // zero padding) we ignore everything after the first Elf_Mips_ABIFlags
-    if (size < sizeof(Elf_Mips_ABIFlags)) {
-      Err(ctx) << sec->file << ": invalid size of .MIPS.abiflags section: got "
-               << size << " instead of " << sizeof(Elf_Mips_ABIFlags);
-      return nullptr;
-    }
-    auto *s =
-        reinterpret_cast<const Elf_Mips_ABIFlags *>(sec->content().data());
-    if (s->version != 0) {
-      Err(ctx) << sec->file << ": unexpected .MIPS.abiflags version "
-               << s->version;
-      return nullptr;
-    }
-
-    // LLD checks ISA compatibility in calcMipsEFlags(). Here we just
-    // select the highest number of ISA/Rev/Ext.
-    flags.isa_level = std::max(flags.isa_level, s->isa_level);
-    flags.isa_rev = std::max(flags.isa_rev, s->isa_rev);
-    flags.isa_ext = std::max(flags.isa_ext, s->isa_ext);
-    flags.gpr_size = std::max(flags.gpr_size, s->gpr_size);
-    flags.cpr1_size = std::max(flags.cpr1_size, s->cpr1_size);
-    flags.cpr2_size = std::max(flags.cpr2_size, s->cpr2_size);
-    flags.ases |= s->ases;
-    flags.flags1 |= s->flags1;
-    flags.flags2 |= s->flags2;
-    flags.fp_abi =
-        elf::getMipsFpAbiFlag(ctx, sec->file, flags.fp_abi, s->fp_abi);
-  };
-
-  if (create)
-    return std::make_unique<MipsAbiFlagsSection<ELFT>>(ctx, flags);
-  return nullptr;
-}
-
-// .MIPS.options section.
-template <class ELFT>
-MipsOptionsSection<ELFT>::MipsOptionsSection(Ctx &ctx, Elf_Mips_RegInfo reginfo)
-    : SyntheticSection(ctx, ".MIPS.options", SHT_MIPS_OPTIONS, SHF_ALLOC, 8),
-      reginfo(reginfo) {
-  this->entsize = sizeof(Elf_Mips_Options) + sizeof(Elf_Mips_RegInfo);
-}
-
-template <class ELFT> void MipsOptionsSection<ELFT>::writeTo(uint8_t *buf) {
-  auto *options = reinterpret_cast<Elf_Mips_Options *>(buf);
-  options->kind = ODK_REGINFO;
-  options->size = getSize();
-
-  if (!ctx.arg.relocatable)
-    reginfo.ri_gp_value = ctx.in.mipsGot->getGp();
-  memcpy(buf + sizeof(Elf_Mips_Options), &reginfo, sizeof(reginfo));
-}
-
-template <class ELFT>
-std::unique_ptr<MipsOptionsSection<ELFT>>
-MipsOptionsSection<ELFT>::create(Ctx &ctx) {
-  // N64 ABI only.
-  if (!ELFT::Is64Bits)
-    return nullptr;
-
-  SmallVector<InputSectionBase *, 0> sections;
-  for (InputSectionBase *sec : ctx.inputSections)
-    if (sec->type == SHT_MIPS_OPTIONS)
-      sections.push_back(sec);
-
-  if (sections.empty())
-    return nullptr;
-
-  Elf_Mips_RegInfo reginfo = {};
-  for (InputSectionBase *sec : sections) {
-    sec->markDead();
-
-    ArrayRef<uint8_t> d = sec->content();
-    while (!d.empty()) {
-      if (d.size() < sizeof(Elf_Mips_Options)) {
-        Err(ctx) << sec->file << ": invalid size of .MIPS.options section";
-        break;
-      }
-
-      auto *opt = reinterpret_cast<const Elf_Mips_Options *>(d.data());
-      if (opt->kind == ODK_REGINFO) {
-        reginfo.ri_gprmask |= opt->getRegInfo().ri_gprmask;
-        sec->getFile<ELFT>()->mipsGp0 = opt->getRegInfo().ri_gp_value;
-        break;
-      }
-
-      if (!opt->size) {
-        Err(ctx) << sec->file << ": zero option descriptor size";
-        break;
-      }
-      d = d.slice(opt->size);
-    }
-  };
-
-  return std::make_unique<MipsOptionsSection<ELFT>>(ctx, reginfo);
-}
-
-// MIPS .reginfo section.
-template <class ELFT>
-MipsReginfoSection<ELFT>::MipsReginfoSection(Ctx &ctx, Elf_Mips_RegInfo reginfo)
-    : SyntheticSection(ctx, ".reginfo", SHT_MIPS_REGINFO, SHF_ALLOC, 4),
-      reginfo(reginfo) {
-  this->entsize = sizeof(Elf_Mips_RegInfo);
-}
-
-template <class ELFT> void MipsReginfoSection<ELFT>::writeTo(uint8_t *buf) {
-  if (!ctx.arg.relocatable)
-    reginfo.ri_gp_value = ctx.in.mipsGot->getGp();
-  memcpy(buf, &reginfo, sizeof(reginfo));
-}
-
-template <class ELFT>
-std::unique_ptr<MipsReginfoSection<ELFT>>
-MipsReginfoSection<ELFT>::create(Ctx &ctx) {
-  // Section should be alive for O32 and N32 ABIs only.
-  if (ELFT::Is64Bits)
-    return nullptr;
-
-  SmallVector<InputSectionBase *, 0> sections;
-  for (InputSectionBase *sec : ctx.inputSections)
-    if (sec->type == SHT_MIPS_REGINFO)
-      sections.push_back(sec);
-
-  if (sections.empty())
-    return nullptr;
-
-  Elf_Mips_RegInfo reginfo = {};
-  for (InputSectionBase *sec : sections) {
-    sec->markDead();
-
-    if (sec->content().size() != sizeof(Elf_Mips_RegInfo)) {
-      Err(ctx) << sec->file << ": invalid size of .reginfo section";
-      return nullptr;
-    }
-
-    auto *r = reinterpret_cast<const Elf_Mips_RegInfo *>(sec->content().data());
-    reginfo.ri_gprmask |= r->ri_gprmask;
-    sec->getFile<ELFT>()->mipsGp0 = r->ri_gp_value;
-  };
-
-  return std::make_unique<MipsReginfoSection<ELFT>>(ctx, reginfo);
-}
-
 InputSection *elf::createInterpSection(Ctx &ctx) {
   // StringSaver guarantees that the returned string ends with '\0'.
   StringRef s = ctx.saver.save(ctx.arg.dynamicLinker);
@@ -2746,20 +2576,6 @@ size_t PPC32GlinkSection::getSize() const {
 //
 // That said, the 2-PLT scheme is a part of the ABI, debuggers and other tools
 // depend on it, so we implement the ABI.
-IBTPltSection::IBTPltSection(Ctx &ctx)
-    : SyntheticSection(ctx, ".plt", SHT_PROGBITS, SHF_ALLOC | SHF_EXECINSTR,
-                       16) {}
-
-void IBTPltSection::writeTo(uint8_t *buf) {
-  ctx.target->writeIBTPlt(buf, ctx.in.plt->getNumEntries());
-}
-
-size_t IBTPltSection::getSize() const {
-  // 16 is the header size of .plt.
-  return 16 + ctx.in.plt->getNumEntries() * ctx.target->pltEntrySize;
-}
-
-bool IBTPltSection::isNeeded() const { return ctx.in.plt->getNumEntries() > 0; }
 
 RelroPaddingSection::RelroPaddingSection(Ctx &ctx)
     : SyntheticSection(ctx, ".relro_padding", SHT_NOBITS, SHF_ALLOC | SHF_WRITE,
@@ -4002,10 +3818,6 @@ void elf::combineEhSections(Ctx &ctx) {
   });
 }
 
-MipsRldMapSection::MipsRldMapSection(Ctx &ctx)
-    : SyntheticSection(ctx, ".rld_map", SHT_PROGBITS, SHF_ALLOC | SHF_WRITE,
-                       ctx.arg.wordsize) {}
-
 ARMExidxSyntheticSection::ARMExidxSyntheticSection(Ctx &ctx)
     : SyntheticSection(ctx, ".ARM.exidx", SHT_ARM_EXIDX,
                        SHF_ALLOC | SHF_LINK_ORDER, ctx.arg.wordsize) {}
@@ -4283,35 +4095,6 @@ bool ThunkSection::assignOffsets() {
   return changed;
 }
 
-PPC32Got2Section::PPC32Got2Section(Ctx &ctx)
-    : SyntheticSection(ctx, ".got2", SHT_PROGBITS, SHF_ALLOC | SHF_WRITE, 4) {}
-
-bool PPC32Got2Section::isNeeded() const {
-  // See the comment below. This is not needed if there is no other
-  // InputSection.
-  for (SectionCommand *cmd : getParent()->commands)
-    if (auto *isd = dyn_cast<InputSectionDescription>(cmd))
-      for (InputSection *isec : isd->sections)
-        if (isec != this)
-          return true;
-  return false;
-}
-
-void PPC32Got2Section::finalizeContents() {
-  // PPC32 may create multiple GOT sections for -fPIC/-fPIE, one per file in
-  // .got2 . This function computes outSecOff of each .got2 to be used in
-  // PPC32PltCallStub::writeTo(). The purpose of this empty synthetic section is
-  // to collect input sections named ".got2".
-  for (SectionCommand *cmd : getParent()->commands)
-    if (auto *isd = dyn_cast<InputSectionDescription>(cmd)) {
-      for (InputSection *isec : isd->sections) {
-        // isec->file may be nullptr for MergeSyntheticSection.
-        if (isec != this && isec->file)
-          isec->file->ppc32Got2 = isec;
-      }
-    }
-}
-
 // If linking position-dependent code then the table will store the addresses
 // directly in the binary so the section has type SHT_PROGBITS. If linking
 // position-independent code the section has type SHT_NOBITS since it will be
@@ -4691,19 +4474,7 @@ template <class ELFT> void elf::createSyntheticSections(Ctx &ctx) {
       ctx, hasDataRelRo ? ".data.rel.ro.bss" : ".bss.rel.ro", 0, 1);
   add(*ctx.in.bssRelRo);
 
-  // Add MIPS-specific sections.
-  if (ctx.arg.emachine == EM_MIPS) {
-    if (!ctx.arg.shared && ctx.hasDynsym) {
-      ctx.in.mipsRldMap = std::make_unique<MipsRldMapSection>(ctx);
-      add(*ctx.in.mipsRldMap);
-    }
-    if ((ctx.in.mipsAbiFlags = MipsAbiFlagsSection<ELFT>::create(ctx)))
-      add(*ctx.in.mipsAbiFlags);
-    if ((ctx.in.mipsOptions = MipsOptionsSection<ELFT>::create(ctx)))
-      add(*ctx.in.mipsOptions);
-    if ((ctx.in.mipsReginfo = MipsReginfoSection<ELFT>::create(ctx)))
-      add(*ctx.in.mipsReginfo);
-  }
+  ctx.target->initTargetSections();
 
   StringRef relaDynName = ctx.arg.isRela ? ".rela.dyn" : ".rel.dyn";
 
@@ -4838,17 +4609,6 @@ template <class ELFT> void elf::createSyntheticSections(Ctx &ctx) {
     add(*ctx.in.got);
   }
 
-  if (ctx.arg.emachine == EM_PPC) {
-    ctx.in.ppc32Got2 = std::make_unique<PPC32Got2Section>(ctx);
-    add(*ctx.in.ppc32Got2);
-  }
-
-  if (ctx.arg.emachine == EM_PPC64) {
-    ctx.in.ppc64LongBranchTarget =
-        std::make_unique<PPC64LongBranchTargetSection>(ctx);
-    add(*ctx.in.ppc64LongBranchTarget);
-  }
-
   ctx.in.gotPlt = std::make_unique<GotPltSection>(ctx);
   add(*ctx.in.gotPlt);
   ctx.in.igotPlt = std::make_unique<IgotPltSection>(ctx);
@@ -4862,11 +4622,6 @@ template <class ELFT> void elf::createSyntheticSections(Ctx &ctx) {
     add(*ctx.in.relroPadding);
   }
 
-  if (ctx.arg.emachine == EM_ARM) {
-    ctx.in.armCmseSGSection = std::make_unique<ArmCmseSGSection>(ctx);
-    add(*ctx.in.armCmseSGSection);
-  }
-
   // _GLOBAL_OFFSET_TABLE_ is defined relative to either .got.plt or .got. Treat
   // it as a relocation and ensure the referenced section is created.
   if (ctx.sym.globalOffsetTable && ctx.arg.emachine != EM_MIPS) {
@@ -4883,12 +4638,6 @@ template <class ELFT> void elf::createSyntheticSections(Ctx &ctx) {
       /*threadCount=*/1);
   add(*ctx.in.relaPlt);
 
-  if ((ctx.arg.emachine == EM_386 || ctx.arg.emachine == EM_X86_64) &&
-      (ctx.arg.andFeatures & GNU_PROPERTY_X86_FEATURE_1_IBT)) {
-    ctx.in.ibtPlt = std::make_unique<IBTPltSection>(ctx);
-    add(*ctx.in.ibtPlt);
-  }
-
   if (ctx.arg.emachine == EM_PPC)
     ctx.in.plt = std::make_unique<PPC32GlinkSection>(ctx);
   else
diff --git a/lld/ELF/SyntheticSections.h b/lld/ELF/SyntheticSections.h
index 1ae03dc24a2f2..3269b17b84d39 100644
--- a/lld/ELF/SyntheticSections.h
+++ b/lld/ELF/SyntheticSections.h
@@ -797,15 +797,6 @@ class PPC32GlinkSection : public PltSection {
   static constexpr size_t footerSize = 64;
 };
 
-// This is x86-only.
-class IBTPltSection : public SyntheticSection {
-public:
-  IBTPltSection(Ctx &);
-  void writeTo(uint8_t *Buf) override;
-  bool isNeeded() const override;
-  size_t getSize() const override;
-};
-
 // Used to align the end of the PT_GNU_RELRO segment and the associated PT_LOAD
 // segment to a common-page-size boundary. This padding section ensures that all
 // pages in the PT_LOAD segment is covered by at least one section.
@@ -1141,67 +1132,6 @@ class MergeNoTailSection final : public MergeSyntheticSection {
   size_t shardOffsets[numShards];
 };
 
-// .MIPS.abiflags section.
-template <class ELFT>
-class MipsAbiFlagsSection final : public SyntheticSection {
-  using Elf_Mips_ABIFlags = llvm::object::Elf_Mips_ABIFlags<ELFT>;
-
-public:
-  static std::unique_ptr<MipsAbiFlagsSection> create(Ctx &);
-
-  MipsAbiFlagsSection(Ctx &, Elf_Mips_ABIFlags flags);
-  size_t getSize() const override { return sizeof(Elf_Mips_ABIFlags); }
-  void writeTo(uint8_t *buf) override;
-
-private:
-  Elf_Mips_ABIFlags flags;
-};
-
-// .MIPS.options section.
-template <class ELFT> class MipsOptionsSection final : public SyntheticSection {
-  using Elf_Mips_Options = llvm::object::Elf_Mips_Options<ELFT>;
-  using Elf_Mips_RegInfo = llvm::object::Elf_Mips_RegInfo<ELFT>;
-
-public:
-  static std::unique_ptr<MipsOptionsSection<ELFT>> create(Ctx &);
-
-  MipsOptionsSection(Ctx &, Elf_Mips_RegInfo reginfo);
-  void writeTo(uint8_t *buf) override;
-
-  size_t getSize() const override {
-    return sizeof(Elf_Mips_Options) + sizeof(Elf_Mips_RegInfo);
-  }
-
-private:
-  Elf_Mips_RegInfo reginfo;
-};
-
-// MIPS .reginfo section.
-template <class ELFT> class MipsReginfoSection final : public SyntheticSection {
-  using Elf_Mips_RegInfo = llvm::object::Elf_Mips_RegInfo<ELFT>;
-
-public:
-  static std::unique_ptr<MipsReginfoSection> create(Ctx &);
-
-  MipsReginfoSection(Ctx &, Elf_Mips_RegInfo reginfo);
-  size_t getSize() const override { return sizeof(Elf_Mips_RegInfo); }
-  void writeTo(uint8_t *buf) override;
-
-private:
-  Elf_Mips_RegInfo reginfo;
-};
-
-// This is a MIPS specific section to hold a space within the data segment
-// of executable file which is pointed to by the DT_MIPS_RLD_MAP entry.
-// See "Dynamic section" in Chapter 5 in the following document:
-// ftp://www.linux-mips.org/pub/linux/mips/doc/ABI/mipsabi.pdf
-class MipsRldMapSection final : public SyntheticSection {
-public:
-  MipsRldMapSection(Ctx &);
-  size_t getSize() const override { return ctx.arg.wordsize; }
-  void writeTo(uint8_t *buf) override {}
-};
-
 // Representation of the combined .ARM.Exidx input sections. We process these
 // as a SyntheticSection like .eh_frame as we need to merge duplicate entries
 // and add terminating sentinel entries.
@@ -1306,56 +1236,6 @@ class ThunkSection final : public SyntheticSection {
   size_t size = 0;
 };
 
-// Cortex-M Security Extensions. Prefix for functions that should be exported
-// for the non-secure world.
-const char ACLESESYM_PREFIX[] = "__acle_se_";
-const int ACLESESYM_SIZE = 8;
-
-class ArmCmseSGVeneer {
-public:
-  ArmCmseSGVeneer(Symbol *sym, Symbol *acleSeSym,
-                  std::optional<uint64_t> addr = std::nullopt)
-      : sym(sym), acleSeSym(acleSeSym), entAddr{addr} {}
-  static const size_t size{ACLESESYM_SIZE};
-  std::optional<uint64_t> getAddr() const { return entAddr; };
-
-  Symbol *sym;
-  Symbol *acleSeSym;
-  uint64_t offset = 0;
-
-private:
-  const std::optional<uint64_t> entAddr;
-};
-
-class ArmCmseSGSection final : public SyntheticSection {
-public:
-  ArmCmseSGSection(Ctx &ctx);
-  bool isNeeded() const override { return !entries.empty(); }
-  size_t getSize() const override;
-  void writeTo(uint8_t *buf) override;
-  void addSGVeneer(Symbol *sym, Symbol *ext_sym);
-  void addMappingSymbol();
-  void finalizeContents() override;
-  void exportEntries(SymbolTableBaseSection *symTab);
-  uint64_t impLibMaxAddr = 0;
-
-private:
-  SmallVector<std::pair<Symbol *, Symbol *>, 0> entries;
-  SmallVector<std::unique_ptr<ArmCmseSGVeneer>, 0> sgVeneers;
-  uint64_t newEntries = 0;
-};
-
-// Used to compute outSecOff of .got2 in each object file. This is needed to
-// synthesize PLT entries for PPC32 Secure PLT ABI.
-class PPC32Got2Section final : public SyntheticSection {
-public:
-  PPC32Got2Section(Ctx &);
-  size_t getSize() const override { return 0; }
-  bool isNeeded() const override;
-  void finalizeContents() override;
-  void writeTo(uint8_t *buf) override {}
-};
-
 // This section is used to store the addresses of functions that are called
 // in range-extending thunks on PowerPC64. When producing position dependent
 // code the addresses are link-time constants and the table is written out to
diff --git a/lld/ELF/Target.h b/lld/ELF/Target.h
index 85fa683b84a6d..9ce33fdfc7c73 100644
--- a/lld/ELF/Target.h
+++ b/lld/ELF/Target.h
@@ -32,6 +32,7 @@ class TargetInfo {
 public:
   TargetInfo(Ctx &ctx) : ctx(ctx) {}
   virtual uint32_t calcEFlags() const { return 0; }
+  virtual void initTargetSections() {}
   virtual RelExpr getRelExpr(RelType type, const Symbol &s,
                              const uint8_t *loc) const = 0;
   virtual RelType getDynRel(RelType type) const { return 0; }

>From 5d450a2e3e9b7fae3599e46c92e9642073f985b4 Mon Sep 17 00:00:00 2001
From: Fangrui Song <i at maskray.me>
Date: Sun, 1 Mar 2026 19:10:50 -0800
Subject: [PATCH 2/2] restore comments

---
 lld/ELF/Arch/Mips.cpp | 4 ++++
 lld/ELF/Arch/PPC.cpp  | 2 ++
 2 files changed, 6 insertions(+)

diff --git a/lld/ELF/Arch/Mips.cpp b/lld/ELF/Arch/Mips.cpp
index 1c319b1d760e4..efaa4e83056ff 100644
--- a/lld/ELF/Arch/Mips.cpp
+++ b/lld/ELF/Arch/Mips.cpp
@@ -44,6 +44,10 @@ template <class ELFT> class MIPS final : public TargetInfo {
   bool usesOnlyLowPageBits(RelType type) const override;
 };
 
+// This is a MIPS specific section to hold a space within the data segment
+// of executable file which is pointed to by the DT_MIPS_RLD_MAP entry.
+// See "Dynamic section" in Chapter 5 in the following document:
+// ftp://www.linux-mips.org/pub/linux/mips/doc/ABI/mipsabi.pdf
 struct RldMapSection : SyntheticSection {
   RldMapSection(Ctx &ctx)
       : SyntheticSection(ctx, ".rld_map", SHT_PROGBITS, SHF_ALLOC | SHF_WRITE,
diff --git a/lld/ELF/Arch/PPC.cpp b/lld/ELF/Arch/PPC.cpp
index e6290874bec2f..0b6821c4a6eb5 100644
--- a/lld/ELF/Arch/PPC.cpp
+++ b/lld/ELF/Arch/PPC.cpp
@@ -61,6 +61,8 @@ class PPC final : public TargetInfo {
   void relaxTlsIeToLe(uint8_t *loc, const Relocation &rel, uint64_t val) const;
 };
 
+// Used to compute outSecOff of .got2 in each object file. This is needed to
+// synthesize PLT entries for PPC32 Secure PLT ABI.
 struct Got2Section : SyntheticSection {
   Got2Section(Ctx &ctx)
       : SyntheticSection(ctx, ".got2", SHT_PROGBITS, SHF_ALLOC | SHF_WRITE, 4) {



More information about the llvm-commits mailing list