[llvm-branch-commits] [lld] release/19.x: [ELF] Move ElfSym into Ctx. NFC (PR #101844)

via llvm-branch-commits llvm-branch-commits at lists.llvm.org
Sat Aug 3 12:16:10 PDT 2024


https://github.com/llvmbot created https://github.com/llvm/llvm-project/pull/101844

Backport fd791f0fe562a41d8569fcb4d1e84b4c1e5719c7 8e2476e102e8ce3ae496b293bacccb248787404d 09dd0febbbd59a0c470b3909690cae6618a2416a 03be619d9434de0a9616660a2119675635239a5b

Requested by: @MaskRay

>From 0fa5e6af74d9339e760365147ba62bd84b4c59e7 Mon Sep 17 00:00:00 2001
From: Fangrui Song <i at maskray.me>
Date: Sun, 28 Jul 2024 15:32:22 -0700
Subject: [PATCH 1/4] [ELF] Move TarWriter into Ctx. NFC

Similar to e980f16d52196fb2bc672ecb87e0f622253addec.

(cherry picked from commit fd791f0fe562a41d8569fcb4d1e84b4c1e5719c7)
---
 lld/ELF/Config.h       |  4 ++++
 lld/ELF/Driver.cpp     | 13 +++++++------
 lld/ELF/InputFiles.cpp |  7 ++-----
 lld/ELF/InputFiles.h   |  3 ---
 4 files changed, 13 insertions(+), 14 deletions(-)

diff --git a/lld/ELF/Config.h b/lld/ELF/Config.h
index 0173be396163e..2f6758743c0d6 100644
--- a/lld/ELF/Config.h
+++ b/lld/ELF/Config.h
@@ -27,6 +27,7 @@
 #include "llvm/Support/FileSystem.h"
 #include "llvm/Support/GlobPattern.h"
 #include "llvm/Support/PrettyStackTrace.h"
+#include "llvm/Support/TarWriter.h"
 #include <atomic>
 #include <memory>
 #include <optional>
@@ -489,6 +490,9 @@ struct Ctx {
                  std::pair<const InputFile *, const InputFile *>>
       backwardReferences;
   llvm::SmallSet<llvm::StringRef, 0> auxiliaryFiles;
+  // If --reproduce is specified, all input files are written to this tar
+  // archive.
+  std::unique_ptr<llvm::TarWriter> tar;
   // InputFile for linker created symbols with no source location.
   InputFile *internalFile;
   // True if SHT_LLVM_SYMPART is used.
diff --git a/lld/ELF/Driver.cpp b/lld/ELF/Driver.cpp
index 40e095a133d95..810d9b0377adf 100644
--- a/lld/ELF/Driver.cpp
+++ b/lld/ELF/Driver.cpp
@@ -106,6 +106,7 @@ void Ctx::reset() {
   whyExtractRecords.clear();
   backwardReferences.clear();
   auxiliaryFiles.clear();
+  tar.reset();
   internalFile = nullptr;
   hasSympart.store(false, std::memory_order_relaxed);
   hasTlsIe.store(false, std::memory_order_relaxed);
@@ -138,7 +139,6 @@ bool link(ArrayRef<const char *> args, llvm::raw_ostream &stdoutOS,
     outputSections.clear();
     symAux.clear();
 
-    tar = nullptr;
     in.reset();
 
     partitions.clear();
@@ -224,14 +224,15 @@ std::vector<std::pair<MemoryBufferRef, uint64_t>> static getArchiveMembers(
 
   std::vector<std::pair<MemoryBufferRef, uint64_t>> v;
   Error err = Error::success();
-  bool addToTar = file->isThin() && tar;
+  bool addToTar = file->isThin() && ctx.tar;
   for (const Archive::Child &c : file->children(err)) {
     MemoryBufferRef mbref =
         CHECK(c.getMemoryBufferRef(),
               mb.getBufferIdentifier() +
                   ": could not get the buffer for a child of the archive");
     if (addToTar)
-      tar->append(relativeToRoot(check(c.getFullName())), mbref.getBuffer());
+      ctx.tar->append(relativeToRoot(check(c.getFullName())),
+                      mbref.getBuffer());
     v.push_back(std::make_pair(mbref, c.getChildOffset()));
   }
   if (err)
@@ -640,9 +641,9 @@ void LinkerDriver::linkerMain(ArrayRef<const char *> argsArr) {
     Expected<std::unique_ptr<TarWriter>> errOrWriter =
         TarWriter::create(path, path::stem(path));
     if (errOrWriter) {
-      tar = std::move(*errOrWriter);
-      tar->append("response.txt", createResponseFile(args));
-      tar->append("version.txt", getLLDVersion() + "\n");
+      ctx.tar = std::move(*errOrWriter);
+      ctx.tar->append("response.txt", createResponseFile(args));
+      ctx.tar->append("version.txt", getLLDVersion() + "\n");
       StringRef ltoSampleProfile = args.getLastArgValue(OPT_lto_sample_profile);
       if (!ltoSampleProfile.empty())
         readFile(ltoSampleProfile);
diff --git a/lld/ELF/InputFiles.cpp b/lld/ELF/InputFiles.cpp
index f1c0eb292361b..0e4ba06e9b780 100644
--- a/lld/ELF/InputFiles.cpp
+++ b/lld/ELF/InputFiles.cpp
@@ -28,7 +28,6 @@
 #include "llvm/Support/FileSystem.h"
 #include "llvm/Support/Path.h"
 #include "llvm/Support/RISCVAttributeParser.h"
-#include "llvm/Support/TarWriter.h"
 #include "llvm/Support/TimeProfiler.h"
 #include "llvm/Support/raw_ostream.h"
 #include <optional>
@@ -52,8 +51,6 @@ extern template void ObjFile<ELF64BE>::importCmseSymbols();
 bool InputFile::isInGroup;
 uint32_t InputFile::nextGroupId;
 
-std::unique_ptr<TarWriter> elf::tar;
-
 // Returns "<internal>", "foo.a(bar.o)" or "baz.o".
 std::string lld::toString(const InputFile *f) {
   static std::mutex mu;
@@ -261,8 +258,8 @@ std::optional<MemoryBufferRef> elf::readFile(StringRef path) {
   MemoryBufferRef mbref = (*mbOrErr)->getMemBufferRef();
   ctx.memoryBuffers.push_back(std::move(*mbOrErr)); // take MB ownership
 
-  if (tar)
-    tar->append(relativeToRoot(path), mbref.getBuffer());
+  if (ctx.tar)
+    ctx.tar->append(relativeToRoot(path), mbref.getBuffer());
   return mbref;
 }
 
diff --git a/lld/ELF/InputFiles.h b/lld/ELF/InputFiles.h
index 8566baf61e1ab..b0a74877d0aae 100644
--- a/lld/ELF/InputFiles.h
+++ b/lld/ELF/InputFiles.h
@@ -39,9 +39,6 @@ namespace elf {
 class InputSection;
 class Symbol;
 
-// If --reproduce is specified, all input files are written to this tar archive.
-extern std::unique_ptr<llvm::TarWriter> tar;
-
 // Opens a given file.
 std::optional<MemoryBufferRef> readFile(StringRef path);
 

>From 12037ac9b80ca1f0ee1d8e3ca7e5a7f0845f4959 Mon Sep 17 00:00:00 2001
From: Fangrui Song <i at maskray.me>
Date: Sun, 28 Jul 2024 20:51:33 -0700
Subject: [PATCH 2/4] [ELF] Move SymbolAux into Ctx. NFC

The number of uses is modest.

(cherry picked from commit 8e2476e102e8ce3ae496b293bacccb248787404d)
---
 lld/ELF/Config.h              | 11 +++++++++++
 lld/ELF/Driver.cpp            |  5 +++--
 lld/ELF/Relocations.cpp       |  4 ++--
 lld/ELF/Symbols.cpp           |  1 -
 lld/ELF/Symbols.h             | 27 ++++++++-------------------
 lld/ELF/SyntheticSections.cpp | 30 +++++++++++++++---------------
 6 files changed, 39 insertions(+), 39 deletions(-)

diff --git a/lld/ELF/Config.h b/lld/ELF/Config.h
index 2f6758743c0d6..6abd929d2343d 100644
--- a/lld/ELF/Config.h
+++ b/lld/ELF/Config.h
@@ -459,6 +459,15 @@ struct ConfigWrapper {
 
 LLVM_LIBRARY_VISIBILITY extern ConfigWrapper config;
 
+// Some index properties of a symbol are stored separately in this auxiliary
+// struct to decrease sizeof(SymbolUnion) in the majority of cases.
+struct SymbolAux {
+  uint32_t gotIdx = -1;
+  uint32_t pltIdx = -1;
+  uint32_t tlsDescIdx = -1;
+  uint32_t tlsGdIdx = -1;
+};
+
 struct DuplicateSymbol {
   const Symbol *sym;
   const InputFile *file;
@@ -476,6 +485,8 @@ struct Ctx {
   SmallVector<BitcodeFile *, 0> lazyBitcodeFiles;
   SmallVector<InputSectionBase *, 0> inputSections;
   SmallVector<EhInputSection *, 0> ehInputSections;
+
+  SmallVector<SymbolAux, 0> symAux;
   // Duplicate symbol candidates.
   SmallVector<DuplicateSymbol, 0> duplicates;
   // Symbols in a non-prevailing COMDAT group which should be changed to an
diff --git a/lld/ELF/Driver.cpp b/lld/ELF/Driver.cpp
index 810d9b0377adf..8f6ca2a98484d 100644
--- a/lld/ELF/Driver.cpp
+++ b/lld/ELF/Driver.cpp
@@ -101,6 +101,8 @@ void Ctx::reset() {
   lazyBitcodeFiles.clear();
   inputSections.clear();
   ehInputSections.clear();
+
+  symAux.clear();
   duplicates.clear();
   nonPrevailingSyms.clear();
   whyExtractRecords.clear();
@@ -137,7 +139,6 @@ bool link(ArrayRef<const char *> args, llvm::raw_ostream &stdoutOS,
     symtab = SymbolTable();
 
     outputSections.clear();
-    symAux.clear();
 
     in.reset();
 
@@ -153,7 +154,7 @@ bool link(ArrayRef<const char *> args, llvm::raw_ostream &stdoutOS,
   config = ConfigWrapper();
   script = ScriptWrapper();
 
-  symAux.emplace_back();
+  elf::ctx.symAux.emplace_back();
 
   partitions.clear();
   partitions.emplace_back();
diff --git a/lld/ELF/Relocations.cpp b/lld/ELF/Relocations.cpp
index e19b1e6c8efb8..1c0dd97ed3910 100644
--- a/lld/ELF/Relocations.cpp
+++ b/lld/ELF/Relocations.cpp
@@ -1728,7 +1728,7 @@ static bool handleNonPreemptibleIfunc(Symbol &sym, uint16_t flags) {
   auto &dyn = config->androidPackDynRelocs ? *in.relaPlt : *mainPart->relaDyn;
   addPltEntry(*in.iplt, *in.igotPlt, dyn, target->iRelativeRel, *directSym);
   sym.allocateAux();
-  symAux.back().pltIdx = symAux[directSym->auxIdx].pltIdx;
+  ctx.symAux.back().pltIdx = ctx.symAux[directSym->auxIdx].pltIdx;
 
   if (flags & HAS_DIRECT_RELOC) {
     // Change the value to the IPLT and redirect all references to it.
@@ -1846,7 +1846,7 @@ void elf::postScanRelocations() {
           {R_ADDEND, target->symbolicRel, got->getTlsIndexOff(), 1, &dummy});
   }
 
-  assert(symAux.size() == 1);
+  assert(ctx.symAux.size() == 1);
   for (Symbol *sym : symtab.getSymbols())
     fn(*sym);
 
diff --git a/lld/ELF/Symbols.cpp b/lld/ELF/Symbols.cpp
index 93653def328f8..263d4f35c5b9a 100644
--- a/lld/ELF/Symbols.cpp
+++ b/lld/ELF/Symbols.cpp
@@ -73,7 +73,6 @@ Defined *ElfSym::riscvGlobalPointer;
 Defined *ElfSym::relaIpltStart;
 Defined *ElfSym::relaIpltEnd;
 Defined *ElfSym::tlsModuleBase;
-SmallVector<SymbolAux, 0> elf::symAux;
 
 static uint64_t getSymVA(const Symbol &sym, int64_t addend) {
   switch (sym.kind()) {
diff --git a/lld/ELF/Symbols.h b/lld/ELF/Symbols.h
index e764fe8d73633..ff825615658eb 100644
--- a/lld/ELF/Symbols.h
+++ b/lld/ELF/Symbols.h
@@ -56,17 +56,6 @@ enum {
   NEEDS_TLSIE = 1 << 8,
 };
 
-// Some index properties of a symbol are stored separately in this auxiliary
-// struct to decrease sizeof(SymbolUnion) in the majority of cases.
-struct SymbolAux {
-  uint32_t gotIdx = -1;
-  uint32_t pltIdx = -1;
-  uint32_t tlsDescIdx = -1;
-  uint32_t tlsGdIdx = -1;
-};
-
-LLVM_LIBRARY_VISIBILITY extern SmallVector<SymbolAux, 0> symAux;
-
 // The base class for real symbol classes.
 class Symbol {
 public:
@@ -211,10 +200,10 @@ class Symbol {
   // truncated by Symbol::parseSymbolVersion().
   const char *getVersionSuffix() const { return nameData + nameSize; }
 
-  uint32_t getGotIdx() const { return symAux[auxIdx].gotIdx; }
-  uint32_t getPltIdx() const { return symAux[auxIdx].pltIdx; }
-  uint32_t getTlsDescIdx() const { return symAux[auxIdx].tlsDescIdx; }
-  uint32_t getTlsGdIdx() const { return symAux[auxIdx].tlsGdIdx; }
+  uint32_t getGotIdx() const { return ctx.symAux[auxIdx].gotIdx; }
+  uint32_t getPltIdx() const { return ctx.symAux[auxIdx].pltIdx; }
+  uint32_t getTlsDescIdx() const { return ctx.symAux[auxIdx].tlsDescIdx; }
+  uint32_t getTlsGdIdx() const { return ctx.symAux[auxIdx].tlsGdIdx; }
 
   bool isInGot() const { return getGotIdx() != uint32_t(-1); }
   bool isInPlt() const { return getPltIdx() != uint32_t(-1); }
@@ -325,8 +314,8 @@ class Symbol {
   // entries during postScanRelocations();
   std::atomic<uint16_t> flags;
 
-  // A symAux index used to access GOT/PLT entry indexes. This is allocated in
-  // postScanRelocations().
+  // A ctx.symAux index used to access GOT/PLT entry indexes. This is allocated
+  // in postScanRelocations().
   uint32_t auxIdx;
   uint32_t dynsymIndex;
 
@@ -357,8 +346,8 @@ class Symbol {
   }
   void allocateAux() {
     assert(auxIdx == 0);
-    auxIdx = symAux.size();
-    symAux.emplace_back();
+    auxIdx = ctx.symAux.size();
+    ctx.symAux.emplace_back();
   }
 
   bool isSection() const { return type == llvm::ELF::STT_SECTION; }
diff --git a/lld/ELF/SyntheticSections.cpp b/lld/ELF/SyntheticSections.cpp
index 41053c6472751..78962a0f012f8 100644
--- a/lld/ELF/SyntheticSections.cpp
+++ b/lld/ELF/SyntheticSections.cpp
@@ -655,20 +655,20 @@ GotSection::GotSection()
 
 void GotSection::addConstant(const Relocation &r) { relocations.push_back(r); }
 void GotSection::addEntry(const Symbol &sym) {
-  assert(sym.auxIdx == symAux.size() - 1);
-  symAux.back().gotIdx = numEntries++;
+  assert(sym.auxIdx == ctx.symAux.size() - 1);
+  ctx.symAux.back().gotIdx = numEntries++;
 }
 
 bool GotSection::addTlsDescEntry(const Symbol &sym) {
-  assert(sym.auxIdx == symAux.size() - 1);
-  symAux.back().tlsDescIdx = numEntries;
+  assert(sym.auxIdx == ctx.symAux.size() - 1);
+  ctx.symAux.back().tlsDescIdx = numEntries;
   numEntries += 2;
   return true;
 }
 
 bool GotSection::addDynTlsEntry(const Symbol &sym) {
-  assert(sym.auxIdx == symAux.size() - 1);
-  symAux.back().tlsGdIdx = numEntries;
+  assert(sym.auxIdx == ctx.symAux.size() - 1);
+  ctx.symAux.back().tlsGdIdx = numEntries;
   // Global Dynamic TLS entries take two GOT slots.
   numEntries += 2;
   return true;
@@ -999,12 +999,12 @@ void MipsGotSection::build() {
   for (auto &p : primGot->global) {
     if (p.first->auxIdx == 0)
       p.first->allocateAux();
-    symAux.back().gotIdx = p.second;
+    ctx.symAux.back().gotIdx = p.second;
   }
   for (auto &p : primGot->relocs) {
     if (p.first->auxIdx == 0)
       p.first->allocateAux();
-    symAux.back().gotIdx = p.second;
+    ctx.symAux.back().gotIdx = p.second;
   }
 
   // Create dynamic relocations.
@@ -1173,8 +1173,8 @@ GotPltSection::GotPltSection()
 }
 
 void GotPltSection::addEntry(Symbol &sym) {
-  assert(sym.auxIdx == symAux.size() - 1 &&
-         symAux.back().pltIdx == entries.size());
+  assert(sym.auxIdx == ctx.symAux.size() - 1 &&
+         ctx.symAux.back().pltIdx == entries.size());
   entries.push_back(&sym);
 }
 
@@ -1219,7 +1219,7 @@ IgotPltSection::IgotPltSection()
                        target->gotEntrySize, getIgotPltName()) {}
 
 void IgotPltSection::addEntry(Symbol &sym) {
-  assert(symAux.back().pltIdx == entries.size());
+  assert(ctx.symAux.back().pltIdx == entries.size());
   entries.push_back(&sym);
 }
 
@@ -2568,8 +2568,8 @@ void PltSection::writeTo(uint8_t *buf) {
 }
 
 void PltSection::addEntry(Symbol &sym) {
-  assert(sym.auxIdx == symAux.size() - 1);
-  symAux.back().pltIdx = entries.size();
+  assert(sym.auxIdx == ctx.symAux.size() - 1);
+  ctx.symAux.back().pltIdx = entries.size();
   entries.push_back(&sym);
 }
 
@@ -2615,8 +2615,8 @@ size_t IpltSection::getSize() const {
 }
 
 void IpltSection::addEntry(Symbol &sym) {
-  assert(sym.auxIdx == symAux.size() - 1);
-  symAux.back().pltIdx = entries.size();
+  assert(sym.auxIdx == ctx.symAux.size() - 1);
+  ctx.symAux.back().pltIdx = entries.size();
   entries.push_back(&sym);
 }
 

>From cfd8c79ecce960832087521d2b3e9b58ca289d9a Mon Sep 17 00:00:00 2001
From: Fangrui Song <i at maskray.me>
Date: Sat, 3 Aug 2024 11:00:11 -0700
Subject: [PATCH 3/4] [ELF] Move Out into Ctx. NFC

Ctx was introduced in March 2022 as a more suitable place for such
singletons. ctx's hidden visibility optimizes generated instructions.

bufferStart and tlsPhdr, which are not OutputSection, can now be moved
outside of `Out`.

(cherry picked from commit 09dd0febbbd59a0c470b3909690cae6618a2416a)
---
 lld/ELF/Config.h              | 16 ++++++
 lld/ELF/Driver.cpp            |  7 ++-
 lld/ELF/InputSection.cpp      |  2 +-
 lld/ELF/LinkerScript.cpp      | 16 +++---
 lld/ELF/OutputSections.cpp    | 10 +---
 lld/ELF/OutputSections.h      | 13 -----
 lld/ELF/Symbols.cpp           |  4 +-
 lld/ELF/SyntheticSections.cpp | 33 +++++-------
 lld/ELF/Target.cpp            |  4 +-
 lld/ELF/Writer.cpp            | 97 +++++++++++++++++------------------
 10 files changed, 97 insertions(+), 105 deletions(-)

diff --git a/lld/ELF/Config.h b/lld/ELF/Config.h
index 6abd929d2343d..699a2d966aab3 100644
--- a/lld/ELF/Config.h
+++ b/lld/ELF/Config.h
@@ -44,6 +44,8 @@ class InputSectionBase;
 class EhInputSection;
 class Symbol;
 class BitcodeCompiler;
+class OutputSection;
+struct PhdrEntry;
 
 enum ELFKind : uint8_t {
   ELFNoneKind,
@@ -477,6 +479,20 @@ struct DuplicateSymbol {
 
 struct Ctx {
   LinkerDriver driver;
+
+  // These variables are initialized by Writer and should not be used before
+  // Writer is initialized.
+  uint8_t *bufferStart;
+  PhdrEntry *tlsPhdr;
+  struct OutSections {
+    OutputSection *elfHeader;
+    OutputSection *programHeaders;
+    OutputSection *preinitArray;
+    OutputSection *initArray;
+    OutputSection *finiArray;
+  };
+  OutSections out;
+
   SmallVector<std::unique_ptr<MemoryBuffer>> memoryBuffers;
   SmallVector<ELFFileBase *, 0> objectFiles;
   SmallVector<SharedFile *, 0> sharedFiles;
diff --git a/lld/ELF/Driver.cpp b/lld/ELF/Driver.cpp
index 8f6ca2a98484d..2bebd068a1008 100644
--- a/lld/ELF/Driver.cpp
+++ b/lld/ELF/Driver.cpp
@@ -93,6 +93,11 @@ void elf::errorOrWarn(const Twine &msg) {
 
 void Ctx::reset() {
   driver = LinkerDriver();
+
+  bufferStart = nullptr;
+  tlsPhdr = nullptr;
+  out = OutSections{};
+
   memoryBuffers.clear();
   objectFiles.clear();
   sharedFiles.clear();
@@ -2934,7 +2939,7 @@ template <class ELFT> void LinkerDriver::link(opt::InputArgList &args) {
 
   // Create elfHeader early. We need a dummy section in
   // addReservedSymbols to mark the created symbols as not absolute.
-  Out::elfHeader = make<OutputSection>("", 0, SHF_ALLOC);
+  ctx.out.elfHeader = make<OutputSection>("", 0, SHF_ALLOC);
 
   // We need to create some reserved symbols such as _end. Create them.
   if (!config->relocatable)
diff --git a/lld/ELF/InputSection.cpp b/lld/ELF/InputSection.cpp
index 570e485455bad..7f8dded51fdab 100644
--- a/lld/ELF/InputSection.cpp
+++ b/lld/ELF/InputSection.cpp
@@ -679,7 +679,7 @@ static int64_t getTlsTpOffset(const Symbol &s) {
   // Variant 2. Static TLS blocks, followed by alignment padding are placed
   // before TP. The alignment padding is added so that (TP - padding -
   // p_memsz) is congruent to p_vaddr modulo p_align.
-  PhdrEntry *tls = Out::tlsPhdr;
+  PhdrEntry *tls = ctx.tlsPhdr;
   switch (config->emachine) {
     // Variant 1.
   case EM_ARM:
diff --git a/lld/ELF/LinkerScript.cpp b/lld/ELF/LinkerScript.cpp
index 055fa21d44ca6..bf7491f11eff5 100644
--- a/lld/ELF/LinkerScript.cpp
+++ b/lld/ELF/LinkerScript.cpp
@@ -1359,8 +1359,8 @@ void LinkerScript::allocateHeaders(SmallVector<PhdrEntry *, 0> &phdrs) {
   if ((paged || hasExplicitHeaders) &&
       headerSize <= min - computeBase(min, hasExplicitHeaders)) {
     min = alignDown(min - headerSize, config->maxPageSize);
-    Out::elfHeader->addr = min;
-    Out::programHeaders->addr = min + Out::elfHeader->size;
+    ctx.out.elfHeader->addr = min;
+    ctx.out.programHeaders->addr = min + ctx.out.elfHeader->size;
     return;
   }
 
@@ -1368,8 +1368,8 @@ void LinkerScript::allocateHeaders(SmallVector<PhdrEntry *, 0> &phdrs) {
   if (hasExplicitHeaders)
     error("could not allocate headers");
 
-  Out::elfHeader->ptLoad = nullptr;
-  Out::programHeaders->ptLoad = nullptr;
+  ctx.out.elfHeader->ptLoad = nullptr;
+  ctx.out.programHeaders->ptLoad = nullptr;
   firstPTLoad->firstSec = findFirstSection(firstPTLoad);
 
   llvm::erase_if(phdrs,
@@ -1397,8 +1397,8 @@ LinkerScript::assignAddresses() {
   } else {
     // Assign addresses to headers right now.
     dot = target->getImageBase();
-    Out::elfHeader->addr = dot;
-    Out::programHeaders->addr = dot + Out::elfHeader->size;
+    ctx.out.elfHeader->addr = dot;
+    ctx.out.programHeaders->addr = dot + ctx.out.elfHeader->size;
     dot += getHeaderSize();
   }
 
@@ -1543,9 +1543,9 @@ SmallVector<PhdrEntry *, 0> LinkerScript::createPhdrs() {
     PhdrEntry *phdr = make<PhdrEntry>(cmd.type, cmd.flags.value_or(PF_R));
 
     if (cmd.hasFilehdr)
-      phdr->add(Out::elfHeader);
+      phdr->add(ctx.out.elfHeader);
     if (cmd.hasPhdrs)
-      phdr->add(Out::programHeaders);
+      phdr->add(ctx.out.programHeaders);
 
     if (cmd.lmaExpr) {
       phdr->p_paddr = cmd.lmaExpr().getValue();
diff --git a/lld/ELF/OutputSections.cpp b/lld/ELF/OutputSections.cpp
index 29f18f89274f3..509098eed2b83 100644
--- a/lld/ELF/OutputSections.cpp
+++ b/lld/ELF/OutputSections.cpp
@@ -39,14 +39,6 @@ using namespace llvm::ELF;
 using namespace lld;
 using namespace lld::elf;
 
-uint8_t *Out::bufferStart;
-PhdrEntry *Out::tlsPhdr;
-OutputSection *Out::elfHeader;
-OutputSection *Out::programHeaders;
-OutputSection *Out::preinitArray;
-OutputSection *Out::initArray;
-OutputSection *Out::finiArray;
-
 SmallVector<OutputSection *, 0> elf::outputSections;
 
 uint32_t OutputSection::getPhdrFlags() const {
@@ -272,7 +264,7 @@ static void sortByOrder(MutableArrayRef<InputSection *> in,
 uint64_t elf::getHeaderSize() {
   if (config->oFormatBinary)
     return 0;
-  return Out::elfHeader->size + Out::programHeaders->size;
+  return ctx.out.elfHeader->size + ctx.out.programHeaders->size;
 }
 
 void OutputSection::sort(llvm::function_ref<int(InputSectionBase *s)> order) {
diff --git a/lld/ELF/OutputSections.h b/lld/ELF/OutputSections.h
index 8c0c52f34ac9f..6ced44be47e46 100644
--- a/lld/ELF/OutputSections.h
+++ b/lld/ELF/OutputSections.h
@@ -150,19 +150,6 @@ llvm::ArrayRef<InputSection *>
 getInputSections(const OutputSection &os,
                  SmallVector<InputSection *, 0> &storage);
 
-// All output sections that are handled by the linker specially are
-// globally accessible. Writer initializes them, so don't use them
-// until Writer is initialized.
-struct Out {
-  static uint8_t *bufferStart;
-  static PhdrEntry *tlsPhdr;
-  static OutputSection *elfHeader;
-  static OutputSection *programHeaders;
-  static OutputSection *preinitArray;
-  static OutputSection *initArray;
-  static OutputSection *finiArray;
-};
-
 uint64_t getHeaderSize();
 
 LLVM_LIBRARY_VISIBILITY extern llvm::SmallVector<OutputSection *, 0>
diff --git a/lld/ELF/Symbols.cpp b/lld/ELF/Symbols.cpp
index 263d4f35c5b9a..9cab824c37c3c 100644
--- a/lld/ELF/Symbols.cpp
+++ b/lld/ELF/Symbols.cpp
@@ -135,10 +135,10 @@ static uint64_t getSymVA(const Symbol &sym, int64_t addend) {
       // after sections are finalized. (e.g. Measuring the size of .rela.dyn
       // for Android relocation packing requires knowing TLS symbol addresses
       // during section finalization.)
-      if (!Out::tlsPhdr || !Out::tlsPhdr->firstSec)
+      if (!ctx.tlsPhdr || !ctx.tlsPhdr->firstSec)
         fatal(toString(d.file) +
               " has an STT_TLS symbol but doesn't have an SHF_TLS section");
-      return va - Out::tlsPhdr->firstSec->addr;
+      return va - ctx.tlsPhdr->firstSec->addr;
     }
     return va;
   }
diff --git a/lld/ELF/SyntheticSections.cpp b/lld/ELF/SyntheticSections.cpp
index 78962a0f012f8..97e0d84a371b5 100644
--- a/lld/ELF/SyntheticSections.cpp
+++ b/lld/ELF/SyntheticSections.cpp
@@ -553,7 +553,7 @@ void EhFrameSection::finalizeContents() {
 // to get an FDE from an address to which FDE is applied. This function
 // returns a list of such pairs.
 SmallVector<EhFrameSection::FdeData, 0> EhFrameSection::getFdeData() const {
-  uint8_t *buf = Out::bufferStart + getParent()->offset + outSecOff;
+  uint8_t *buf = ctx.bufferStart + getParent()->offset + outSecOff;
   SmallVector<FdeData, 0> ret;
 
   uint64_t va = getPartition().ehFrameHdr->getVA();
@@ -1493,17 +1493,17 @@ DynamicSection<ELFT>::computeContents() {
     addInSec(DT_HASH, *part.hashTab);
 
   if (isMain) {
-    if (Out::preinitArray) {
-      addInt(DT_PREINIT_ARRAY, Out::preinitArray->addr);
-      addInt(DT_PREINIT_ARRAYSZ, Out::preinitArray->size);
+    if (ctx.out.preinitArray) {
+      addInt(DT_PREINIT_ARRAY, ctx.out.preinitArray->addr);
+      addInt(DT_PREINIT_ARRAYSZ, ctx.out.preinitArray->size);
     }
-    if (Out::initArray) {
-      addInt(DT_INIT_ARRAY, Out::initArray->addr);
-      addInt(DT_INIT_ARRAYSZ, Out::initArray->size);
+    if (ctx.out.initArray) {
+      addInt(DT_INIT_ARRAY, ctx.out.initArray->addr);
+      addInt(DT_INIT_ARRAYSZ, ctx.out.initArray->size);
     }
-    if (Out::finiArray) {
-      addInt(DT_FINI_ARRAY, Out::finiArray->addr);
-      addInt(DT_FINI_ARRAYSZ, Out::finiArray->size);
+    if (ctx.out.finiArray) {
+      addInt(DT_FINI_ARRAY, ctx.out.finiArray->addr);
+      addInt(DT_FINI_ARRAYSZ, ctx.out.finiArray->size);
     }
 
     if (Symbol *b = symtab.find(config->init))
@@ -3631,7 +3631,7 @@ void EhFrameHeader::writeTo(uint8_t *buf) {
 // the starting PC from where FDEs covers, and the FDE's address.
 // It is sorted by PC.
 void EhFrameHeader::write() {
-  uint8_t *buf = Out::bufferStart + getParent()->offset + outSecOff;
+  uint8_t *buf = ctx.bufferStart + getParent()->offset + outSecOff;
   using FdeData = EhFrameSection::FdeData;
   SmallVector<FdeData, 0> fdes = getPartition().ehFrame->getFdeData();
 
@@ -4647,13 +4647,6 @@ static Defined *addOptionalRegular(StringRef name, SectionBase *sec,
 }
 
 template <class ELFT> void elf::createSyntheticSections() {
-  // Initialize all pointers with NULL. This is needed because
-  // you can call lld::elf::main more than once as a library.
-  Out::tlsPhdr = nullptr;
-  Out::preinitArray = nullptr;
-  Out::initArray = nullptr;
-  Out::finiArray = nullptr;
-
   // Add the .interp section first because it is not a SyntheticSection.
   // The removeUnusedSyntheticSections() function relies on the
   // SyntheticSections coming last.
@@ -4669,8 +4662,8 @@ template <class ELFT> void elf::createSyntheticSections() {
 
   in.shStrTab = std::make_unique<StringTableSection>(".shstrtab", false);
 
-  Out::programHeaders = make<OutputSection>("", 0, SHF_ALLOC);
-  Out::programHeaders->addralign = config->wordsize;
+  ctx.out.programHeaders = make<OutputSection>("", 0, SHF_ALLOC);
+  ctx.out.programHeaders->addralign = config->wordsize;
 
   if (config->strip != StripPolicy::All) {
     in.strTab = std::make_unique<StringTableSection>(".strtab", false);
diff --git a/lld/ELF/Target.cpp b/lld/ELF/Target.cpp
index 3e221646ce247..584e9270469d0 100644
--- a/lld/ELF/Target.cpp
+++ b/lld/ELF/Target.cpp
@@ -104,8 +104,8 @@ ErrorPlace elf::getErrorPlace(const uint8_t *loc) {
       continue;
 
     const uint8_t *isecLoc =
-        Out::bufferStart
-            ? (Out::bufferStart + isec->getParent()->offset + isec->outSecOff)
+        ctx.bufferStart
+            ? (ctx.bufferStart + isec->getParent()->offset + isec->outSecOff)
             : isec->contentMaybeDecompress().data();
     if (isecLoc == nullptr) {
       assert(isa<SyntheticSection>(isec) && "No data but not synthetic?");
diff --git a/lld/ELF/Writer.cpp b/lld/ELF/Writer.cpp
index 8e3a746a08eb2..0c5990351e59e 100644
--- a/lld/ELF/Writer.cpp
+++ b/lld/ELF/Writer.cpp
@@ -211,7 +211,7 @@ void elf::addReservedSymbols() {
       gotOff = 0x8000;
 
     s->resolve(Defined{ctx.internalFile, StringRef(), STB_GLOBAL, STV_HIDDEN,
-                       STT_NOTYPE, gotOff, /*size=*/0, Out::elfHeader});
+                       STT_NOTYPE, gotOff, /*size=*/0, ctx.out.elfHeader});
     ElfSym::globalOffsetTable = cast<Defined>(s);
   }
 
@@ -219,23 +219,23 @@ void elf::addReservedSymbols() {
   // this symbol unconditionally even when using a linker script, which
   // differs from the behavior implemented by GNU linker which only define
   // this symbol if ELF headers are in the memory mapped segment.
-  addOptionalRegular("__ehdr_start", Out::elfHeader, 0, STV_HIDDEN);
+  addOptionalRegular("__ehdr_start", ctx.out.elfHeader, 0, STV_HIDDEN);
 
   // __executable_start is not documented, but the expectation of at
   // least the Android libc is that it points to the ELF header.
-  addOptionalRegular("__executable_start", Out::elfHeader, 0, STV_HIDDEN);
+  addOptionalRegular("__executable_start", ctx.out.elfHeader, 0, STV_HIDDEN);
 
   // __dso_handle symbol is passed to cxa_finalize as a marker to identify
   // each DSO. The address of the symbol doesn't matter as long as they are
   // different in different DSOs, so we chose the start address of the DSO.
-  addOptionalRegular("__dso_handle", Out::elfHeader, 0, STV_HIDDEN);
+  addOptionalRegular("__dso_handle", ctx.out.elfHeader, 0, STV_HIDDEN);
 
   // If linker script do layout we do not need to create any standard symbols.
   if (script->hasSectionsCommand)
     return;
 
   auto add = [](StringRef s, int64_t pos) {
-    return addOptionalRegular(s, Out::elfHeader, pos, STV_DEFAULT);
+    return addOptionalRegular(s, ctx.out.elfHeader, pos, STV_DEFAULT);
   };
 
   ElfSym::bss = add("__bss_start", 0);
@@ -796,13 +796,14 @@ template <class ELFT> void Writer<ELFT>::addRelIpltSymbols() {
     return;
 
   // __rela_iplt_{start,end} are initially defined relative to dummy section 0.
-  // We'll override Out::elfHeader with relaDyn later when we are sure that
+  // We'll override ctx.out.elfHeader with relaDyn later when we are sure that
   // .rela.dyn will be present in the output.
   std::string name = config->isRela ? "__rela_iplt_start" : "__rel_iplt_start";
   ElfSym::relaIpltStart =
-      addOptionalRegular(name, Out::elfHeader, 0, STV_HIDDEN);
+      addOptionalRegular(name, ctx.out.elfHeader, 0, STV_HIDDEN);
   name.replace(name.size() - 5, 5, "end");
-  ElfSym::relaIpltEnd = addOptionalRegular(name, Out::elfHeader, 0, STV_HIDDEN);
+  ElfSym::relaIpltEnd =
+      addOptionalRegular(name, ctx.out.elfHeader, 0, STV_HIDDEN);
 }
 
 // This function generates assignments for predefined symbols (e.g. _end or
@@ -1693,9 +1694,9 @@ static void removeUnusedSyntheticSections() {
 // Create output section objects and add them to OutputSections.
 template <class ELFT> void Writer<ELFT>::finalizeSections() {
   if (!config->relocatable) {
-    Out::preinitArray = findSection(".preinit_array");
-    Out::initArray = findSection(".init_array");
-    Out::finiArray = findSection(".fini_array");
+    ctx.out.preinitArray = findSection(".preinit_array");
+    ctx.out.initArray = findSection(".init_array");
+    ctx.out.finiArray = findSection(".fini_array");
 
     // The linker needs to define SECNAME_start, SECNAME_end and SECNAME_stop
     // symbols for sections, so that the runtime can get the start and end
@@ -1722,13 +1723,13 @@ template <class ELFT> void Writer<ELFT>::finalizeSections() {
     // RISC-V's gp can address +/- 2 KiB, set it to .sdata + 0x800. This symbol
     // should only be defined in an executable. If .sdata does not exist, its
     // value/section does not matter but it has to be relative, so set its
-    // st_shndx arbitrarily to 1 (Out::elfHeader).
+    // st_shndx arbitrarily to 1 (ctx.out.elfHeader).
     if (config->emachine == EM_RISCV) {
       ElfSym::riscvGlobalPointer = nullptr;
       if (!config->shared) {
         OutputSection *sec = findSection(".sdata");
-        addOptionalRegular(
-            "__global_pointer$", sec ? sec : Out::elfHeader, 0x800, STV_DEFAULT);
+        addOptionalRegular("__global_pointer$", sec ? sec : ctx.out.elfHeader,
+                           0x800, STV_DEFAULT);
         // Set riscvGlobalPointer to be used by the optional global pointer
         // relaxation.
         if (config->relaxGP) {
@@ -1913,8 +1914,8 @@ template <class ELFT> void Writer<ELFT>::finalizeSections() {
   // This is a bit of a hack. A value of 0 means undef, so we set it
   // to 1 to make __ehdr_start defined. The section number is not
   // particularly relevant.
-  Out::elfHeader->sectionIndex = 1;
-  Out::elfHeader->size = sizeof(typename ELFT::Ehdr);
+  ctx.out.elfHeader->sectionIndex = 1;
+  ctx.out.elfHeader->size = sizeof(typename ELFT::Ehdr);
 
   // Binary and relocatable output does not have PHDRS.
   // The headers have to be created before finalize as that can influence the
@@ -1937,7 +1938,7 @@ template <class ELFT> void Writer<ELFT>::finalizeSections() {
         addPhdrForSection(part, SHT_RISCV_ATTRIBUTES, PT_RISCV_ATTRIBUTES,
                           PF_R);
     }
-    Out::programHeaders->size = sizeof(Elf_Phdr) * mainPart->phdrs.size();
+    ctx.out.programHeaders->size = sizeof(Elf_Phdr) * mainPart->phdrs.size();
 
     // Find the TLS segment. This happens before the section layout loop so that
     // Android relocation packing can look up TLS symbol addresses. We only need
@@ -1945,7 +1946,7 @@ template <class ELFT> void Writer<ELFT>::finalizeSections() {
     // to the main partition (see MarkLive.cpp).
     for (PhdrEntry *p : mainPart->phdrs)
       if (p->p_type == PT_TLS)
-        Out::tlsPhdr = p;
+        ctx.tlsPhdr = p;
   }
 
   // Some symbols are defined in term of program headers. Now that we
@@ -2097,14 +2098,14 @@ template <class ELFT> void Writer<ELFT>::addStartEndSymbols() {
       if (startSym || stopSym)
         os->usedInExpression = true;
     } else {
-      addOptionalRegular(start, Out::elfHeader, 0);
-      addOptionalRegular(end, Out::elfHeader, 0);
+      addOptionalRegular(start, ctx.out.elfHeader, 0);
+      addOptionalRegular(end, ctx.out.elfHeader, 0);
     }
   };
 
-  define("__preinit_array_start", "__preinit_array_end", Out::preinitArray);
-  define("__init_array_start", "__init_array_end", Out::initArray);
-  define("__fini_array_start", "__fini_array_end", Out::finiArray);
+  define("__preinit_array_start", "__preinit_array_end", ctx.out.preinitArray);
+  define("__init_array_start", "__init_array_end", ctx.out.initArray);
+  define("__fini_array_start", "__fini_array_end", ctx.out.finiArray);
 
   // As a special case, don't unnecessarily retain .ARM.exidx, which would
   // create an empty PT_ARM_EXIDX.
@@ -2174,7 +2175,7 @@ SmallVector<PhdrEntry *, 0> Writer<ELFT>::createPhdrs(Partition &part) {
     // The first phdr entry is PT_PHDR which describes the program header
     // itself.
     if (isMain)
-      addHdr(PT_PHDR, PF_R)->add(Out::programHeaders);
+      addHdr(PT_PHDR, PF_R)->add(ctx.out.programHeaders);
     else
       addHdr(PT_PHDR, PF_R)->add(part.programHeaders->getParent());
 
@@ -2187,8 +2188,8 @@ SmallVector<PhdrEntry *, 0> Writer<ELFT>::createPhdrs(Partition &part) {
     // need to be added here.
     if (isMain) {
       load = addHdr(PT_LOAD, flags);
-      load->add(Out::elfHeader);
-      load->add(Out::programHeaders);
+      load->add(ctx.out.elfHeader);
+      load->add(ctx.out.programHeaders);
     }
   }
 
@@ -2260,7 +2261,7 @@ SmallVector<PhdrEntry *, 0> Writer<ELFT>::createPhdrs(Partition &part) {
         load && !sec->lmaExpr && sec->lmaRegion == load->firstSec->lmaRegion;
     if (load && sec != relroEnd &&
         sec->memRegion == load->firstSec->memRegion &&
-        (sameLMARegion || load->lastSec == Out::programHeaders) &&
+        (sameLMARegion || load->lastSec == ctx.out.programHeaders) &&
         (script->hasSectionsCommand || sec->type == SHT_NOBITS ||
          load->lastSec->type != SHT_NOBITS)) {
       load->p_flags |= newFlags;
@@ -2407,11 +2408,11 @@ template <class ELFT> void Writer<ELFT>::fixSectionAlignments() {
       // p_align for dynamic TLS blocks (PR/24606), FreeBSD rtld has the same
       // bug, musl (TLS Variant 1 architectures) before 1.1.23 handled TLS
       // blocks correctly. We need to keep the workaround for a while.
-      else if (Out::tlsPhdr && Out::tlsPhdr->firstSec == p->firstSec)
+      else if (ctx.tlsPhdr && ctx.tlsPhdr->firstSec == p->firstSec)
         cmd->addrExpr = [] {
           return alignToPowerOf2(script->getDot(), config->maxPageSize) +
                  alignToPowerOf2(script->getDot() % config->maxPageSize,
-                                 Out::tlsPhdr->p_align);
+                                 ctx.tlsPhdr->p_align);
         };
       else
         cmd->addrExpr = [] {
@@ -2443,9 +2444,8 @@ static uint64_t computeFileOffset(OutputSection *os, uint64_t off) {
   // File offsets are not significant for .bss sections other than the first one
   // in a PT_LOAD/PT_TLS. By convention, we keep section offsets monotonically
   // increasing rather than setting to zero.
-  if (os->type == SHT_NOBITS &&
-      (!Out::tlsPhdr || Out::tlsPhdr->firstSec != os))
-     return off;
+  if (os->type == SHT_NOBITS && (!ctx.tlsPhdr || ctx.tlsPhdr->firstSec != os))
+    return off;
 
   // If the section is not in a PT_LOAD, we just have to align it.
   if (!os->ptLoad)
@@ -2484,8 +2484,8 @@ static std::string rangeToString(uint64_t addr, uint64_t len) {
 
 // Assign file offsets to output sections.
 template <class ELFT> void Writer<ELFT>::assignFileOffsets() {
-  Out::programHeaders->offset = Out::elfHeader->size;
-  uint64_t off = Out::elfHeader->size + Out::programHeaders->size;
+  ctx.out.programHeaders->offset = ctx.out.elfHeader->size;
+  uint64_t off = ctx.out.elfHeader->size + ctx.out.programHeaders->size;
 
   PhdrEntry *lastRX = nullptr;
   for (Partition &part : partitions)
@@ -2706,10 +2706,10 @@ static uint16_t getELFType() {
 }
 
 template <class ELFT> void Writer<ELFT>::writeHeader() {
-  writeEhdr<ELFT>(Out::bufferStart, *mainPart);
-  writePhdrs<ELFT>(Out::bufferStart + sizeof(Elf_Ehdr), *mainPart);
+  writeEhdr<ELFT>(ctx.bufferStart, *mainPart);
+  writePhdrs<ELFT>(ctx.bufferStart + sizeof(Elf_Ehdr), *mainPart);
 
-  auto *eHdr = reinterpret_cast<Elf_Ehdr *>(Out::bufferStart);
+  auto *eHdr = reinterpret_cast<Elf_Ehdr *>(ctx.bufferStart);
   eHdr->e_type = getELFType();
   eHdr->e_entry = getEntryAddr();
   eHdr->e_shoff = sectionHeaderOff;
@@ -2723,7 +2723,7 @@ template <class ELFT> void Writer<ELFT>::writeHeader() {
   // the value. The sentinel values and fields are:
   // e_shnum = 0, SHdrs[0].sh_size = number of sections.
   // e_shstrndx = SHN_XINDEX, SHdrs[0].sh_link = .shstrtab section index.
-  auto *sHdrs = reinterpret_cast<Elf_Shdr *>(Out::bufferStart + eHdr->e_shoff);
+  auto *sHdrs = reinterpret_cast<Elf_Shdr *>(ctx.bufferStart + eHdr->e_shoff);
   size_t num = outputSections.size() + 1;
   if (num >= SHN_LORESERVE)
     sHdrs->sh_size = num;
@@ -2771,14 +2771,14 @@ template <class ELFT> void Writer<ELFT>::openFile() {
     return;
   }
   buffer = std::move(*bufferOrErr);
-  Out::bufferStart = buffer->getBufferStart();
+  ctx.bufferStart = buffer->getBufferStart();
 }
 
 template <class ELFT> void Writer<ELFT>::writeSectionsBinary() {
   parallel::TaskGroup tg;
   for (OutputSection *sec : outputSections)
     if (sec->flags & SHF_ALLOC)
-      sec->writeTo<ELFT>(Out::bufferStart + sec->offset, tg);
+      sec->writeTo<ELFT>(ctx.bufferStart + sec->offset, tg);
 }
 
 static void fillTrap(uint8_t *i, uint8_t *end) {
@@ -2797,11 +2797,10 @@ template <class ELFT> void Writer<ELFT>::writeTrapInstr() {
     // Fill the last page.
     for (PhdrEntry *p : part.phdrs)
       if (p->p_type == PT_LOAD && (p->p_flags & PF_X))
-        fillTrap(Out::bufferStart +
-                     alignDown(p->firstSec->offset + p->p_filesz, 4),
-                 Out::bufferStart +
-                     alignToPowerOf2(p->firstSec->offset + p->p_filesz,
-                                     config->maxPageSize));
+        fillTrap(
+            ctx.bufferStart + alignDown(p->firstSec->offset + p->p_filesz, 4),
+            ctx.bufferStart + alignToPowerOf2(p->firstSec->offset + p->p_filesz,
+                                              config->maxPageSize));
 
     // Round up the file size of the last segment to the page boundary iff it is
     // an executable segment to ensure that other tools don't accidentally
@@ -2828,20 +2827,20 @@ template <class ELFT> void Writer<ELFT>::writeSections() {
     parallel::TaskGroup tg;
     for (OutputSection *sec : outputSections)
       if (isStaticRelSecType(sec->type))
-        sec->writeTo<ELFT>(Out::bufferStart + sec->offset, tg);
+        sec->writeTo<ELFT>(ctx.bufferStart + sec->offset, tg);
   }
   {
     parallel::TaskGroup tg;
     for (OutputSection *sec : outputSections)
       if (!isStaticRelSecType(sec->type))
-        sec->writeTo<ELFT>(Out::bufferStart + sec->offset, tg);
+        sec->writeTo<ELFT>(ctx.bufferStart + sec->offset, tg);
   }
 
   // Finally, check that all dynamic relocation addends were written correctly.
   if (config->checkDynamicRelocs && config->writeAddends) {
     for (OutputSection *sec : outputSections)
       if (isStaticRelSecType(sec->type))
-        sec->checkDynRelAddends(Out::bufferStart);
+        sec->checkDynRelAddends(ctx.bufferStart);
   }
 }
 
@@ -2880,7 +2879,7 @@ template <class ELFT> void Writer<ELFT>::writeBuildId() {
   size_t hashSize = mainPart->buildId->hashSize;
   std::unique_ptr<uint8_t[]> buildId(new uint8_t[hashSize]);
   MutableArrayRef<uint8_t> output(buildId.get(), hashSize);
-  llvm::ArrayRef<uint8_t> input{Out::bufferStart, size_t(fileSize)};
+  llvm::ArrayRef<uint8_t> input{ctx.bufferStart, size_t(fileSize)};
 
   // Fedora introduced build ID as "approximation of true uniqueness across all
   // binaries that might be used by overlapping sets of people". It does not

>From 7e364cac47a54f610b65b1bf637b86fe57bda68e Mon Sep 17 00:00:00 2001
From: Fangrui Song <i at maskray.me>
Date: Sat, 3 Aug 2024 11:20:32 -0700
Subject: [PATCH 4/4] [ELF] Move ElfSym into Ctx. NFC

Ctx was introduced in March 2022 as a more suitable place for such
singletons. ctx's hidden visibility optimizes generated instructions.

This change fixes a pitfall: certain ElfSym members (e.g.
globalOffsetTable, tlsModuleBase) were not zeroed and might be stale
when lld::elf::link was invoked the second time.

(cherry picked from commit 03be619d9434de0a9616660a2119675635239a5b)
---
 lld/ELF/Arch/Mips.cpp         |  4 +-
 lld/ELF/Arch/RISCV.cpp        |  4 +-
 lld/ELF/Config.h              | 41 +++++++++++++++++++
 lld/ELF/Driver.cpp            |  2 +
 lld/ELF/InputSection.cpp      |  2 +-
 lld/ELF/Symbols.cpp           | 16 --------
 lld/ELF/Symbols.h             | 39 ------------------
 lld/ELF/SyntheticSections.cpp |  6 +--
 lld/ELF/Writer.cpp            | 77 +++++++++++++++++------------------
 9 files changed, 89 insertions(+), 102 deletions(-)

diff --git a/lld/ELF/Arch/Mips.cpp b/lld/ELF/Arch/Mips.cpp
index e36e9d59a7401..7c7137117d78e 100644
--- a/lld/ELF/Arch/Mips.cpp
+++ b/lld/ELF/Arch/Mips.cpp
@@ -121,9 +121,9 @@ RelExpr MIPS<ELFT>::getRelExpr(RelType type, const Symbol &s,
     // offset between start of function and 'gp' value which by default
     // equal to the start of .got section. In that case we consider these
     // relocations as relative.
-    if (&s == ElfSym::mipsGpDisp)
+    if (&s == ctx.sym.mipsGpDisp)
       return R_MIPS_GOT_GP_PC;
-    if (&s == ElfSym::mipsLocalGp)
+    if (&s == ctx.sym.mipsLocalGp)
       return R_MIPS_GOT_GP;
     [[fallthrough]];
   case R_MIPS_32:
diff --git a/lld/ELF/Arch/RISCV.cpp b/lld/ELF/Arch/RISCV.cpp
index 56759c28dcf41..8c2db2145f305 100644
--- a/lld/ELF/Arch/RISCV.cpp
+++ b/lld/ELF/Arch/RISCV.cpp
@@ -466,7 +466,7 @@ void RISCV::relocate(uint8_t *loc, const Relocation &rel, uint64_t val) const {
 
   case INTERNAL_R_RISCV_GPREL_I:
   case INTERNAL_R_RISCV_GPREL_S: {
-    Defined *gp = ElfSym::riscvGlobalPointer;
+    Defined *gp = ctx.sym.riscvGlobalPointer;
     int64_t displace = SignExtend64(val - gp->getVA(), bits);
     checkInt(loc, displace, 12, rel);
     uint32_t insn = (read32le(loc) & ~(31 << 15)) | (X_GP << 15);
@@ -789,7 +789,7 @@ static void relaxTlsLe(const InputSection &sec, size_t i, uint64_t loc,
 
 static void relaxHi20Lo12(const InputSection &sec, size_t i, uint64_t loc,
                           Relocation &r, uint32_t &remove) {
-  const Defined *gp = ElfSym::riscvGlobalPointer;
+  const Defined *gp = ctx.sym.riscvGlobalPointer;
   if (!gp)
     return;
 
diff --git a/lld/ELF/Config.h b/lld/ELF/Config.h
index 699a2d966aab3..f562985630be4 100644
--- a/lld/ELF/Config.h
+++ b/lld/ELF/Config.h
@@ -42,6 +42,7 @@ class ELFFileBase;
 class SharedFile;
 class InputSectionBase;
 class EhInputSection;
+class Defined;
 class Symbol;
 class BitcodeCompiler;
 class OutputSection;
@@ -493,6 +494,46 @@ struct Ctx {
   };
   OutSections out;
 
+  // Some linker-generated symbols need to be created as
+  // Defined symbols.
+  struct ElfSym {
+    // __bss_start
+    Defined *bss;
+
+    // etext and _etext
+    Defined *etext1;
+    Defined *etext2;
+
+    // edata and _edata
+    Defined *edata1;
+    Defined *edata2;
+
+    // end and _end
+    Defined *end1;
+    Defined *end2;
+
+    // The _GLOBAL_OFFSET_TABLE_ symbol is defined by target convention to
+    // be at some offset from the base of the .got section, usually 0 or
+    // the end of the .got.
+    Defined *globalOffsetTable;
+
+    // _gp, _gp_disp and __gnu_local_gp symbols. Only for MIPS.
+    Defined *mipsGp;
+    Defined *mipsGpDisp;
+    Defined *mipsLocalGp;
+
+    // __global_pointer$ for RISC-V.
+    Defined *riscvGlobalPointer;
+
+    // __rel{,a}_iplt_{start,end} symbols.
+    Defined *relaIpltStart;
+    Defined *relaIpltEnd;
+
+    // _TLS_MODULE_BASE_ on targets that support TLSDESC.
+    Defined *tlsModuleBase;
+  };
+  ElfSym sym;
+
   SmallVector<std::unique_ptr<MemoryBuffer>> memoryBuffers;
   SmallVector<ELFFileBase *, 0> objectFiles;
   SmallVector<SharedFile *, 0> sharedFiles;
diff --git a/lld/ELF/Driver.cpp b/lld/ELF/Driver.cpp
index 2bebd068a1008..806f1e52e7244 100644
--- a/lld/ELF/Driver.cpp
+++ b/lld/ELF/Driver.cpp
@@ -98,6 +98,8 @@ void Ctx::reset() {
   tlsPhdr = nullptr;
   out = OutSections{};
 
+  sym = ElfSym{};
+
   memoryBuffers.clear();
   objectFiles.clear();
   sharedFiles.clear();
diff --git a/lld/ELF/InputSection.cpp b/lld/ELF/InputSection.cpp
index 7f8dded51fdab..da4c90516ec30 100644
--- a/lld/ELF/InputSection.cpp
+++ b/lld/ELF/InputSection.cpp
@@ -665,7 +665,7 @@ static Relocation *getRISCVPCRelHi20(const Symbol *sym, uint64_t addend) {
 // target-specific adjustment to produce a thread-pointer-relative offset.
 static int64_t getTlsTpOffset(const Symbol &s) {
   // On targets that support TLSDESC, _TLS_MODULE_BASE_ at tpoff = 0.
-  if (&s == ElfSym::tlsModuleBase)
+  if (&s == ctx.sym.tlsModuleBase)
     return 0;
 
   // There are 2 TLS layouts. Among targets we support, x86 uses TLS Variant 2
diff --git a/lld/ELF/Symbols.cpp b/lld/ELF/Symbols.cpp
index 9cab824c37c3c..4e1ae819b86fa 100644
--- a/lld/ELF/Symbols.cpp
+++ b/lld/ELF/Symbols.cpp
@@ -58,22 +58,6 @@ std::string lld::toString(const elf::Symbol &sym) {
   return ret;
 }
 
-Defined *ElfSym::bss;
-Defined *ElfSym::etext1;
-Defined *ElfSym::etext2;
-Defined *ElfSym::edata1;
-Defined *ElfSym::edata2;
-Defined *ElfSym::end1;
-Defined *ElfSym::end2;
-Defined *ElfSym::globalOffsetTable;
-Defined *ElfSym::mipsGp;
-Defined *ElfSym::mipsGpDisp;
-Defined *ElfSym::mipsLocalGp;
-Defined *ElfSym::riscvGlobalPointer;
-Defined *ElfSym::relaIpltStart;
-Defined *ElfSym::relaIpltEnd;
-Defined *ElfSym::tlsModuleBase;
-
 static uint64_t getSymVA(const Symbol &sym, int64_t addend) {
   switch (sym.kind()) {
   case Symbol::DefinedKind: {
diff --git a/lld/ELF/Symbols.h b/lld/ELF/Symbols.h
index ff825615658eb..05aed16bfb0dc 100644
--- a/lld/ELF/Symbols.h
+++ b/lld/ELF/Symbols.h
@@ -501,45 +501,6 @@ class LazySymbol : public Symbol {
   static bool classof(const Symbol *s) { return s->kind() == LazyKind; }
 };
 
-// Some linker-generated symbols need to be created as
-// Defined symbols.
-struct ElfSym {
-  // __bss_start
-  static Defined *bss;
-
-  // etext and _etext
-  static Defined *etext1;
-  static Defined *etext2;
-
-  // edata and _edata
-  static Defined *edata1;
-  static Defined *edata2;
-
-  // end and _end
-  static Defined *end1;
-  static Defined *end2;
-
-  // The _GLOBAL_OFFSET_TABLE_ symbol is defined by target convention to
-  // be at some offset from the base of the .got section, usually 0 or
-  // the end of the .got.
-  static Defined *globalOffsetTable;
-
-  // _gp, _gp_disp and __gnu_local_gp symbols. Only for MIPS.
-  static Defined *mipsGp;
-  static Defined *mipsGpDisp;
-  static Defined *mipsLocalGp;
-
-  // __global_pointer$ for RISC-V.
-  static Defined *riscvGlobalPointer;
-
-  // __rel{,a}_iplt_{start,end} symbols.
-  static Defined *relaIpltStart;
-  static Defined *relaIpltEnd;
-
-  // _TLS_MODULE_BASE_ on targets that support TLSDESC.
-  static Defined *tlsModuleBase;
-};
-
 // A buffer class that is large enough to hold any Symbol-derived
 // object. We allocate memory using this class and instantiate a symbol
 // using the placement new.
diff --git a/lld/ELF/SyntheticSections.cpp b/lld/ELF/SyntheticSections.cpp
index 97e0d84a371b5..da372370ccfeb 100644
--- a/lld/ELF/SyntheticSections.cpp
+++ b/lld/ELF/SyntheticSections.cpp
@@ -702,7 +702,7 @@ uint64_t GotSection::getGlobalDynOffset(const Symbol &b) const {
 
 void GotSection::finalizeContents() {
   if (config->emachine == EM_PPC64 &&
-      numEntries <= target->gotHeaderEntriesNum && !ElfSym::globalOffsetTable)
+      numEntries <= target->gotHeaderEntriesNum && !ctx.sym.globalOffsetTable)
     size = 0;
   else
     size = numEntries * config->wordsize;
@@ -1090,7 +1090,7 @@ uint64_t MipsGotSection::getGp(const InputFile *f) const {
   // returns "common" _gp value. For secondary GOTs calculate
   // individual _gp values.
   if (!f || f->mipsGotIndex == uint32_t(-1) || f->mipsGotIndex == 0)
-    return ElfSym::mipsGp->getVA(0);
+    return ctx.sym.mipsGp->getVA(0);
   return getVA() + gots[f->mipsGotIndex].startIndex * config->wordsize + 0x7ff0;
 }
 
@@ -4859,7 +4859,7 @@ template <class ELFT> void elf::createSyntheticSections() {
 
   // _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 (ElfSym::globalOffsetTable && config->emachine != EM_MIPS) {
+  if (ctx.sym.globalOffsetTable && config->emachine != EM_MIPS) {
     if (target->gotBaseSymInGotPlt)
       in.gotPlt->hasGotPltOffRel = true;
     else
diff --git a/lld/ELF/Writer.cpp b/lld/ELF/Writer.cpp
index 0c5990351e59e..7f6ec49274c6a 100644
--- a/lld/ELF/Writer.cpp
+++ b/lld/ELF/Writer.cpp
@@ -167,19 +167,19 @@ void elf::addReservedSymbols() {
     // to GOT. Default offset is 0x7ff0.
     // See "Global Data Symbols" in Chapter 6 in the following document:
     // ftp://www.linux-mips.org/pub/linux/mips/doc/ABI/mipsabi.pdf
-    ElfSym::mipsGp = addAbsolute("_gp");
+    ctx.sym.mipsGp = addAbsolute("_gp");
 
     // On MIPS O32 ABI, _gp_disp is a magic symbol designates offset between
     // start of function and 'gp' pointer into GOT.
     if (symtab.find("_gp_disp"))
-      ElfSym::mipsGpDisp = addAbsolute("_gp_disp");
+      ctx.sym.mipsGpDisp = addAbsolute("_gp_disp");
 
     // The __gnu_local_gp is a magic symbol equal to the current value of 'gp'
     // pointer. This symbol is used in the code generated by .cpload pseudo-op
     // in case of using -mno-shared option.
     // https://sourceware.org/ml/binutils/2004-12/msg00094.html
     if (symtab.find("__gnu_local_gp"))
-      ElfSym::mipsLocalGp = addAbsolute("__gnu_local_gp");
+      ctx.sym.mipsLocalGp = addAbsolute("__gnu_local_gp");
   } else if (config->emachine == EM_PPC) {
     // glibc *crt1.o has a undefined reference to _SDA_BASE_. Since we don't
     // support Small Data Area, define it arbitrarily as 0.
@@ -212,7 +212,7 @@ void elf::addReservedSymbols() {
 
     s->resolve(Defined{ctx.internalFile, StringRef(), STB_GLOBAL, STV_HIDDEN,
                        STT_NOTYPE, gotOff, /*size=*/0, ctx.out.elfHeader});
-    ElfSym::globalOffsetTable = cast<Defined>(s);
+    ctx.sym.globalOffsetTable = cast<Defined>(s);
   }
 
   // __ehdr_start is the location of ELF file headers. Note that we define
@@ -238,13 +238,13 @@ void elf::addReservedSymbols() {
     return addOptionalRegular(s, ctx.out.elfHeader, pos, STV_DEFAULT);
   };
 
-  ElfSym::bss = add("__bss_start", 0);
-  ElfSym::end1 = add("end", -1);
-  ElfSym::end2 = add("_end", -1);
-  ElfSym::etext1 = add("etext", -1);
-  ElfSym::etext2 = add("_etext", -1);
-  ElfSym::edata1 = add("edata", -1);
-  ElfSym::edata2 = add("_edata", -1);
+  ctx.sym.bss = add("__bss_start", 0);
+  ctx.sym.end1 = add("end", -1);
+  ctx.sym.end2 = add("_end", -1);
+  ctx.sym.etext1 = add("etext", -1);
+  ctx.sym.etext2 = add("_etext", -1);
+  ctx.sym.edata1 = add("edata", -1);
+  ctx.sym.edata2 = add("_edata", -1);
 }
 
 static void demoteDefined(Defined &sym, DenseMap<SectionBase *, size_t> &map) {
@@ -799,10 +799,10 @@ template <class ELFT> void Writer<ELFT>::addRelIpltSymbols() {
   // We'll override ctx.out.elfHeader with relaDyn later when we are sure that
   // .rela.dyn will be present in the output.
   std::string name = config->isRela ? "__rela_iplt_start" : "__rel_iplt_start";
-  ElfSym::relaIpltStart =
+  ctx.sym.relaIpltStart =
       addOptionalRegular(name, ctx.out.elfHeader, 0, STV_HIDDEN);
   name.replace(name.size() - 5, 5, "end");
-  ElfSym::relaIpltEnd =
+  ctx.sym.relaIpltEnd =
       addOptionalRegular(name, ctx.out.elfHeader, 0, STV_HIDDEN);
 }
 
@@ -812,21 +812,21 @@ template <class ELFT> void Writer<ELFT>::addRelIpltSymbols() {
 // time any references to these symbols are processed and is equivalent to
 // defining these symbols explicitly in the linker script.
 template <class ELFT> void Writer<ELFT>::setReservedSymbolSections() {
-  if (ElfSym::globalOffsetTable) {
+  if (ctx.sym.globalOffsetTable) {
     // The _GLOBAL_OFFSET_TABLE_ symbol is defined by target convention usually
     // to the start of the .got or .got.plt section.
     InputSection *sec = in.gotPlt.get();
     if (!target->gotBaseSymInGotPlt)
       sec = in.mipsGot ? cast<InputSection>(in.mipsGot.get())
                        : cast<InputSection>(in.got.get());
-    ElfSym::globalOffsetTable->section = sec;
+    ctx.sym.globalOffsetTable->section = sec;
   }
 
   // .rela_iplt_{start,end} mark the start and the end of .rel[a].dyn.
-  if (ElfSym::relaIpltStart && mainPart->relaDyn->isNeeded()) {
-    ElfSym::relaIpltStart->section = mainPart->relaDyn.get();
-    ElfSym::relaIpltEnd->section = mainPart->relaDyn.get();
-    ElfSym::relaIpltEnd->value = mainPart->relaDyn->getSize();
+  if (ctx.sym.relaIpltStart && mainPart->relaDyn->isNeeded()) {
+    ctx.sym.relaIpltStart->section = mainPart->relaDyn.get();
+    ctx.sym.relaIpltEnd->section = mainPart->relaDyn.get();
+    ctx.sym.relaIpltEnd->value = mainPart->relaDyn->getSize();
   }
 
   PhdrEntry *last = nullptr;
@@ -847,10 +847,10 @@ template <class ELFT> void Writer<ELFT>::setReservedSymbolSections() {
   if (lastRO) {
     // _etext is the first location after the last read-only loadable segment
     // that does not contain large sections.
-    if (ElfSym::etext1)
-      ElfSym::etext1->section = lastRO;
-    if (ElfSym::etext2)
-      ElfSym::etext2->section = lastRO;
+    if (ctx.sym.etext1)
+      ctx.sym.etext1->section = lastRO;
+    if (ctx.sym.etext2)
+      ctx.sym.etext2->section = lastRO;
   }
 
   if (last) {
@@ -864,34 +864,34 @@ template <class ELFT> void Writer<ELFT>::setReservedSymbolSections() {
         break;
     }
 
-    if (ElfSym::edata1)
-      ElfSym::edata1->section = edata;
-    if (ElfSym::edata2)
-      ElfSym::edata2->section = edata;
+    if (ctx.sym.edata1)
+      ctx.sym.edata1->section = edata;
+    if (ctx.sym.edata2)
+      ctx.sym.edata2->section = edata;
 
     // _end is the first location after the uninitialized data region.
-    if (ElfSym::end1)
-      ElfSym::end1->section = last->lastSec;
-    if (ElfSym::end2)
-      ElfSym::end2->section = last->lastSec;
+    if (ctx.sym.end1)
+      ctx.sym.end1->section = last->lastSec;
+    if (ctx.sym.end2)
+      ctx.sym.end2->section = last->lastSec;
   }
 
-  if (ElfSym::bss) {
+  if (ctx.sym.bss) {
     // On RISC-V, set __bss_start to the start of .sbss if present.
     OutputSection *sbss =
         config->emachine == EM_RISCV ? findSection(".sbss") : nullptr;
-    ElfSym::bss->section = sbss ? sbss : findSection(".bss");
+    ctx.sym.bss->section = sbss ? sbss : findSection(".bss");
   }
 
   // Setup MIPS _gp_disp/__gnu_local_gp symbols which should
   // be equal to the _gp symbol's value.
-  if (ElfSym::mipsGp) {
+  if (ctx.sym.mipsGp) {
     // Find GP-relative section with the lowest address
     // and use this address to calculate default _gp value.
     for (OutputSection *os : outputSections) {
       if (os->flags & SHF_MIPS_GPREL) {
-        ElfSym::mipsGp->section = os;
-        ElfSym::mipsGp->value = 0x7ff0;
+        ctx.sym.mipsGp->section = os;
+        ctx.sym.mipsGp->value = 0x7ff0;
         break;
       }
     }
@@ -1725,7 +1725,6 @@ template <class ELFT> void Writer<ELFT>::finalizeSections() {
     // value/section does not matter but it has to be relative, so set its
     // st_shndx arbitrarily to 1 (ctx.out.elfHeader).
     if (config->emachine == EM_RISCV) {
-      ElfSym::riscvGlobalPointer = nullptr;
       if (!config->shared) {
         OutputSection *sec = findSection(".sdata");
         addOptionalRegular("__global_pointer$", sec ? sec : ctx.out.elfHeader,
@@ -1735,7 +1734,7 @@ template <class ELFT> void Writer<ELFT>::finalizeSections() {
         if (config->relaxGP) {
           Symbol *s = symtab.find("__global_pointer$");
           if (s && s->isDefined())
-            ElfSym::riscvGlobalPointer = cast<Defined>(s);
+            ctx.sym.riscvGlobalPointer = cast<Defined>(s);
         }
       }
     }
@@ -1757,7 +1756,7 @@ template <class ELFT> void Writer<ELFT>::finalizeSections() {
         s->resolve(Defined{ctx.internalFile, StringRef(), STB_GLOBAL,
                            STV_HIDDEN, STT_TLS, /*value=*/0, 0,
                            /*section=*/nullptr});
-        ElfSym::tlsModuleBase = cast<Defined>(s);
+        ctx.sym.tlsModuleBase = cast<Defined>(s);
       }
     }
 



More information about the llvm-branch-commits mailing list