[llvm] b4fa71e - [LLD] Remove global state in lld/COFF
Amy Huang via llvm-commits
llvm-commits at lists.llvm.org
Thu Sep 16 11:02:36 PDT 2021
Author: Amy Huang
Date: 2021-09-16T11:00:23-07:00
New Revision: b4fa71eed34d967195514fe9b0a5211fca2bc5bc
URL: https://github.com/llvm/llvm-project/commit/b4fa71eed34d967195514fe9b0a5211fca2bc5bc
DIFF: https://github.com/llvm/llvm-project/commit/b4fa71eed34d967195514fe9b0a5211fca2bc5bc.diff
LOG: [LLD] Remove global state in lld/COFF
This patch removes globals from the lldCOFF library, by moving globals
into a context class (COFFLinkingContext) and passing it around wherever
it's needed.
See https://lists.llvm.org/pipermail/llvm-dev/2021-June/151184.html for
context about removing globals from LLD.
I also haven't moved the `driver` or `config` variables yet.
Differential Revision: https://reviews.llvm.org/D109634
Added:
lld/COFF/COFFLinkerContext.cpp
lld/COFF/COFFLinkerContext.h
Modified:
lld/COFF/CMakeLists.txt
lld/COFF/CallGraphSort.cpp
lld/COFF/CallGraphSort.h
lld/COFF/Chunks.cpp
lld/COFF/Chunks.h
lld/COFF/DLL.cpp
lld/COFF/DLL.h
lld/COFF/DebugTypes.cpp
lld/COFF/DebugTypes.h
lld/COFF/Driver.cpp
lld/COFF/Driver.h
lld/COFF/ICF.cpp
lld/COFF/ICF.h
lld/COFF/InputFiles.cpp
lld/COFF/InputFiles.h
lld/COFF/LLDMapFile.cpp
lld/COFF/LLDMapFile.h
lld/COFF/LTO.cpp
lld/COFF/LTO.h
lld/COFF/MapFile.cpp
lld/COFF/MapFile.h
lld/COFF/MarkLive.cpp
lld/COFF/MarkLive.h
lld/COFF/MinGW.cpp
lld/COFF/MinGW.h
lld/COFF/PDB.cpp
lld/COFF/PDB.h
lld/COFF/SymbolTable.cpp
lld/COFF/SymbolTable.h
lld/COFF/TypeMerger.h
lld/COFF/Writer.cpp
lld/COFF/Writer.h
lld/Common/Timer.cpp
lld/include/lld/Common/Timer.h
llvm/utils/gn/secondary/lld/COFF/BUILD.gn
Removed:
################################################################################
diff --git a/lld/COFF/CMakeLists.txt b/lld/COFF/CMakeLists.txt
index bbcd337b210f3..b32b9cfcff04e 100644
--- a/lld/COFF/CMakeLists.txt
+++ b/lld/COFF/CMakeLists.txt
@@ -5,6 +5,7 @@ add_public_tablegen_target(COFFOptionsTableGen)
add_lld_library(lldCOFF
CallGraphSort.cpp
Chunks.cpp
+ COFFLinkerContext.cpp
DebugTypes.cpp
DLL.cpp
Driver.cpp
diff --git a/lld/COFF/COFFLinkerContext.cpp b/lld/COFF/COFFLinkerContext.cpp
new file mode 100644
index 0000000000000..39da96a9ecf17
--- /dev/null
+++ b/lld/COFF/COFFLinkerContext.cpp
@@ -0,0 +1,53 @@
+//===- COFFContext.cpp ----------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+// Description
+//
+//===----------------------------------------------------------------------===//
+
+#include "COFFLinkerContext.h"
+#include "lld/Common/Memory.h"
+#include "llvm/DebugInfo/CodeView/TypeHashing.h"
+
+namespace lld {
+namespace coff {
+
+COFFLinkerContext::COFFLinkerContext()
+ : symtab(*this), rootTimer("Total Linking Time"),
+ inputFileTimer("Input File Reading", rootTimer),
+ ltoTimer("LTO", rootTimer), gcTimer("GC", rootTimer),
+ icfTimer("ICF", rootTimer), codeLayoutTimer("Code Layout", rootTimer),
+ outputCommitTimer("Commit Output File", rootTimer),
+ totalMapTimer("MAP Emission (Cumulative)", rootTimer),
+ symbolGatherTimer("Gather Symbols", totalMapTimer),
+ symbolStringsTimer("Build Symbol strings", totalMapTimer),
+ writeTimer("Write to File", totalMapTimer),
+ totalPdbLinkTimer("PDB Emission (Cumulative)", rootTimer),
+ addObjectsTimer("Add Objects", totalPdbLinkTimer),
+ symbolMergingTimer("Symbol Merging", addObjectsTimer),
+ typeMergingTimer("Type Merging", addObjectsTimer),
+ tpiStreamLayoutTimer("TPI Stream Layout", totalPdbLinkTimer),
+ publicsLayoutTimer("Publics Stream Layout", totalPdbLinkTimer),
+ diskCommitTimer("Commit to Disk", totalPdbLinkTimer),
+ loadGHashTimer("Global Type Hashing", addObjectsTimer),
+ mergeGHashTimer("GHash Type Merging", addObjectsTimer) {}
+
+COFFLinkerContext::~COFFLinkerContext() { clearGHashes(); }
+
+void COFFLinkerContext::clearGHashes() {
+ for (TpiSource *src : tpiSourceList) {
+ if (src->ownedGHashes)
+ delete[] src->ghashes.data();
+ src->ghashes = {};
+ src->isItemIndex.clear();
+ src->uniqueTypes.clear();
+ }
+}
+
+} // namespace coff
+} // namespace lld
diff --git a/lld/COFF/COFFLinkerContext.h b/lld/COFF/COFFLinkerContext.h
new file mode 100644
index 0000000000000..594c9fde89a2d
--- /dev/null
+++ b/lld/COFF/COFFLinkerContext.h
@@ -0,0 +1,88 @@
+//===- COFFLinkerContext.h --------------------------------------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLD_COFF_COFFLinkerContext_H
+#define LLD_COFF_COFFLinkerContext_H
+
+#include "Chunks.h"
+#include "Config.h"
+#include "DebugTypes.h"
+#include "InputFiles.h"
+#include "SymbolTable.h"
+#include "Writer.h"
+#include "lld/Common/Timer.h"
+
+namespace lld {
+namespace coff {
+
+class COFFLinkerContext {
+public:
+ COFFLinkerContext();
+ COFFLinkerContext(const COFFLinkerContext &) = delete;
+ COFFLinkerContext &operator=(const COFFLinkerContext &) = delete;
+ ~COFFLinkerContext();
+
+ void addTpiSource(TpiSource *tpi) { tpiSourceList.push_back(tpi); }
+
+ /// Free heap allocated ghashes.
+ void clearGHashes();
+
+ SymbolTable symtab;
+
+ std::vector<ObjFile *> objFileInstances;
+ std::map<std::string, PDBInputFile *> pdbInputFileInstances;
+ std::vector<ImportFile *> importFileInstances;
+ std::vector<BitcodeFile *> bitcodeFileInstances;
+
+ MergeChunk *mergeChunkInstances[Log2MaxSectionAlignment + 1] = {};
+
+ /// All sources of type information in the program.
+ std::vector<TpiSource *> tpiSourceList;
+
+ std::map<llvm::codeview::GUID, TpiSource *> typeServerSourceMappings;
+ std::map<uint32_t, TpiSource *> precompSourceMappings;
+
+ /// List of all output sections. After output sections are finalized, this
+ /// can be indexed by getOutputSection.
+ std::vector<OutputSection *> outputSections;
+
+ OutputSection *getOutputSection(const Chunk *c) const {
+ return c->osidx == 0 ? nullptr : outputSections[c->osidx - 1];
+ }
+
+ // All timers used in the COFF linker.
+ Timer rootTimer;
+ Timer inputFileTimer;
+ Timer ltoTimer;
+ Timer gcTimer;
+ Timer icfTimer;
+
+ // Writer timers.
+ Timer codeLayoutTimer;
+ Timer outputCommitTimer;
+ Timer totalMapTimer;
+ Timer symbolGatherTimer;
+ Timer symbolStringsTimer;
+ Timer writeTimer;
+
+ // PDB timers.
+ Timer totalPdbLinkTimer;
+ Timer addObjectsTimer;
+ Timer symbolMergingTimer;
+ Timer typeMergingTimer;
+ Timer tpiStreamLayoutTimer;
+ Timer publicsLayoutTimer;
+ Timer diskCommitTimer;
+ Timer loadGHashTimer;
+ Timer mergeGHashTimer;
+};
+
+} // namespace coff
+} // namespace lld
+
+#endif
diff --git a/lld/COFF/CallGraphSort.cpp b/lld/COFF/CallGraphSort.cpp
index d3e5312ce7fdd..709e69b24914b 100644
--- a/lld/COFF/CallGraphSort.cpp
+++ b/lld/COFF/CallGraphSort.cpp
@@ -12,6 +12,7 @@
//===----------------------------------------------------------------------===//
#include "CallGraphSort.h"
+#include "COFFLinkerContext.h"
#include "InputFiles.h"
#include "SymbolTable.h"
#include "Symbols.h"
@@ -48,7 +49,7 @@ struct Cluster {
class CallGraphSort {
public:
- CallGraphSort();
+ CallGraphSort(const COFFLinkerContext &ctx);
DenseMap<const SectionChunk *, int> run();
@@ -70,7 +71,7 @@ using SectionPair = std::pair<const SectionChunk *, const SectionChunk *>;
// Take the edge list in Config->CallGraphProfile, resolve symbol names to
// Symbols, and generate a graph between InputSections with the provided
// weights.
-CallGraphSort::CallGraphSort() {
+CallGraphSort::CallGraphSort(const COFFLinkerContext &ctx) {
MapVector<SectionPair, uint64_t> &profile = config->callGraphProfile;
DenseMap<const SectionChunk *, int> secToCluster;
@@ -95,7 +96,7 @@ CallGraphSort::CallGraphSort() {
// output. This messes with the cluster size and density calculations. We
// would also end up moving input sections in other output sections without
// moving them closer to what calls them.
- if (fromSec->getOutputSection() != toSec->getOutputSection())
+ if (ctx.getOutputSection(fromSec) != ctx.getOutputSection(toSec))
continue;
int from = getOrCreateNode(fromSec);
@@ -240,6 +241,7 @@ DenseMap<const SectionChunk *, int> CallGraphSort::run() {
// This first builds a call graph based on the profile data then merges sections
// according to the C³ heuristic. All clusters are then sorted by a density
// metric to further improve locality.
-DenseMap<const SectionChunk *, int> coff::computeCallGraphProfileOrder() {
- return CallGraphSort().run();
+DenseMap<const SectionChunk *, int>
+coff::computeCallGraphProfileOrder(const COFFLinkerContext &ctx) {
+ return CallGraphSort(ctx).run();
}
diff --git a/lld/COFF/CallGraphSort.h b/lld/COFF/CallGraphSort.h
index e4f372137448c..99f35d6b62762 100644
--- a/lld/COFF/CallGraphSort.h
+++ b/lld/COFF/CallGraphSort.h
@@ -14,8 +14,10 @@
namespace lld {
namespace coff {
class SectionChunk;
+class COFFLinkerContext;
-llvm::DenseMap<const SectionChunk *, int> computeCallGraphProfileOrder();
+llvm::DenseMap<const SectionChunk *, int>
+computeCallGraphProfileOrder(const COFFLinkerContext &ctx);
} // namespace coff
} // namespace lld
diff --git a/lld/COFF/Chunks.cpp b/lld/COFF/Chunks.cpp
index 36d5f371326fe..9f6dbd1725096 100644
--- a/lld/COFF/Chunks.cpp
+++ b/lld/COFF/Chunks.cpp
@@ -7,10 +7,11 @@
//===----------------------------------------------------------------------===//
#include "Chunks.h"
+#include "COFFLinkerContext.h"
#include "InputFiles.h"
+#include "SymbolTable.h"
#include "Symbols.h"
#include "Writer.h"
-#include "SymbolTable.h"
#include "lld/Common/ErrorHandler.h"
#include "llvm/ADT/Twine.h"
#include "llvm/BinaryFormat/COFF.h"
@@ -385,7 +386,7 @@ void SectionChunk::applyRelocation(uint8_t *off,
// section is needed to compute SECREL and SECTION relocations used in debug
// info.
Chunk *c = sym ? sym->getChunk() : nullptr;
- OutputSection *os = c ? c->getOutputSection() : nullptr;
+ OutputSection *os = c ? file->ctx.getOutputSection(c) : nullptr;
// Skip the relocation if it refers to a discarded section, and diagnose it
// as an error if appropriate. If a symbol was discarded early, it may be
@@ -938,18 +939,16 @@ uint8_t Baserel::getDefaultType() {
}
}
-MergeChunk *MergeChunk::instances[Log2MaxSectionAlignment + 1] = {};
-
MergeChunk::MergeChunk(uint32_t alignment)
: builder(StringTableBuilder::RAW, alignment) {
setAlignment(alignment);
}
-void MergeChunk::addSection(SectionChunk *c) {
+void MergeChunk::addSection(COFFLinkerContext &ctx, SectionChunk *c) {
assert(isPowerOf2_32(c->getAlignment()));
uint8_t p2Align = llvm::Log2_32(c->getAlignment());
- assert(p2Align < array_lengthof(instances));
- auto *&mc = instances[p2Align];
+ assert(p2Align < array_lengthof(ctx.mergeChunkInstances));
+ auto *&mc = ctx.mergeChunkInstances[p2Align];
if (!mc)
mc = make<MergeChunk>(c->getAlignment());
mc->sections.push_back(c);
diff --git a/lld/COFF/Chunks.h b/lld/COFF/Chunks.h
index bdd3faa179a8a..daaa043ffaceb 100644
--- a/lld/COFF/Chunks.h
+++ b/lld/COFF/Chunks.h
@@ -101,7 +101,6 @@ class Chunk {
// chunk has a back pointer to an output section.
void setOutputSectionIdx(uint16_t o) { osidx = o; }
uint16_t getOutputSectionIdx() const { return osidx; }
- OutputSection *getOutputSection() const;
// Windows-specific.
// Collect all locations that contain absolute addresses for base relocations.
@@ -415,7 +414,7 @@ inline StringRef Chunk::getDebugName() const {
class MergeChunk : public NonSectionChunk {
public:
MergeChunk(uint32_t alignment);
- static void addSection(SectionChunk *c);
+ static void addSection(COFFLinkerContext &ctx, SectionChunk *c);
void finalizeContents();
void assignSubsectionRVAs();
@@ -424,7 +423,6 @@ class MergeChunk : public NonSectionChunk {
size_t getSize() const override;
void writeTo(uint8_t *buf) const override;
- static MergeChunk *instances[Log2MaxSectionAlignment + 1];
std::vector<SectionChunk *> sections;
private:
diff --git a/lld/COFF/DLL.cpp b/lld/COFF/DLL.cpp
index b9e12ef4b34dd..6fec9df5617db 100644
--- a/lld/COFF/DLL.cpp
+++ b/lld/COFF/DLL.cpp
@@ -18,6 +18,7 @@
//===----------------------------------------------------------------------===//
#include "DLL.h"
+#include "COFFLinkerContext.h"
#include "Chunks.h"
#include "SymbolTable.h"
#include "llvm/Object/COFF.h"
@@ -631,7 +632,7 @@ uint64_t DelayLoadContents::getDirSize() {
return dirs.size() * sizeof(delay_import_directory_table_entry);
}
-void DelayLoadContents::create(Defined *h) {
+void DelayLoadContents::create(COFFLinkerContext &ctx, Defined *h) {
helper = h;
std::vector<std::vector<DefinedImportData *>> v = binImports(imports);
@@ -660,13 +661,13 @@ void DelayLoadContents::create(Defined *h) {
// call targets for Control Flow Guard.
StringRef symName = saver.save("__imp_load_" + extName);
s->loadThunkSym =
- cast<DefinedSynthetic>(symtab->addSynthetic(symName, t));
+ cast<DefinedSynthetic>(ctx.symtab.addSynthetic(symName, t));
}
}
thunks.push_back(tm);
StringRef tmName =
saver.save("__tailMerge_" + syms[0]->getDLLName().lower());
- symtab->addSynthetic(tmName, tm);
+ ctx.symtab.addSynthetic(tmName, tm);
// Terminate with null values.
addresses.push_back(make<NullChunk>(8));
names.push_back(make<NullChunk>(8));
diff --git a/lld/COFF/DLL.h b/lld/COFF/DLL.h
index ce0ee01c4a3df..0d594e675bd23 100644
--- a/lld/COFF/DLL.h
+++ b/lld/COFF/DLL.h
@@ -40,7 +40,7 @@ class DelayLoadContents {
public:
void add(DefinedImportData *sym) { imports.push_back(sym); }
bool empty() { return imports.empty(); }
- void create(Defined *helper);
+ void create(COFFLinkerContext &ctx, Defined *helper);
std::vector<Chunk *> getChunks();
std::vector<Chunk *> getDataChunks();
ArrayRef<Chunk *> getCodeChunks() { return thunks; }
diff --git a/lld/COFF/DebugTypes.cpp b/lld/COFF/DebugTypes.cpp
index 97be5bc79ac34..548b7c6325e61 100644
--- a/lld/COFF/DebugTypes.cpp
+++ b/lld/COFF/DebugTypes.cpp
@@ -7,6 +7,7 @@
//===----------------------------------------------------------------------===//
#include "DebugTypes.h"
+#include "COFFLinkerContext.h"
#include "Chunks.h"
#include "Driver.h"
#include "InputFiles.h"
@@ -14,7 +15,6 @@
#include "TypeMerger.h"
#include "lld/Common/ErrorHandler.h"
#include "lld/Common/Memory.h"
-#include "lld/Common/Timer.h"
#include "llvm/DebugInfo/CodeView/TypeIndexDiscovery.h"
#include "llvm/DebugInfo/CodeView/TypeRecord.h"
#include "llvm/DebugInfo/CodeView/TypeRecordHelpers.h"
@@ -46,8 +46,8 @@ class TypeServerIpiSource;
// before any dependent OBJ.
class TypeServerSource : public TpiSource {
public:
- explicit TypeServerSource(PDBInputFile *f)
- : TpiSource(PDB, nullptr), pdbInputFile(f) {
+ explicit TypeServerSource(COFFLinkerContext &ctx, PDBInputFile *f)
+ : TpiSource(ctx, PDB, nullptr), pdbInputFile(f) {
if (f->loadErr && *f->loadErr)
return;
pdb::PDBFile &file = f->session->getPDBFile();
@@ -55,7 +55,7 @@ class TypeServerSource : public TpiSource {
if (!expectedInfo)
return;
Guid = expectedInfo->getGuid();
- auto it = mappings.emplace(Guid, this);
+ auto it = ctx.typeServerSourceMappings.emplace(Guid, this);
assert(it.second);
(void)it;
}
@@ -74,8 +74,6 @@ class TypeServerSource : public TpiSource {
// The PDB signature GUID.
codeview::GUID Guid;
-
- static std::map<codeview::GUID, TypeServerSource *> mappings;
};
// Companion to TypeServerSource. Stores the index map for the IPI stream in the
@@ -83,7 +81,8 @@ class TypeServerSource : public TpiSource {
// invariant of one type index space per source.
class TypeServerIpiSource : public TpiSource {
public:
- explicit TypeServerIpiSource() : TpiSource(PDBIpi, nullptr) {}
+ explicit TypeServerIpiSource(COFFLinkerContext &ctx)
+ : TpiSource(ctx, PDBIpi, nullptr) {}
friend class TypeServerSource;
@@ -101,8 +100,8 @@ class UseTypeServerSource : public TpiSource {
Expected<TypeServerSource *> getTypeServerSource();
public:
- UseTypeServerSource(ObjFile *f, TypeServer2Record ts)
- : TpiSource(UsingPDB, f), typeServerDependency(ts) {}
+ UseTypeServerSource(COFFLinkerContext &ctx, ObjFile *f, TypeServer2Record ts)
+ : TpiSource(ctx, UsingPDB, f), typeServerDependency(ts) {}
Error mergeDebugT(TypeMerger *m) override;
@@ -121,11 +120,11 @@ class UseTypeServerSource : public TpiSource {
// such files, clang does not.
class PrecompSource : public TpiSource {
public:
- PrecompSource(ObjFile *f) : TpiSource(PCH, f) {
+ PrecompSource(COFFLinkerContext &ctx, ObjFile *f) : TpiSource(ctx, PCH, f) {
if (!f->pchSignature || !*f->pchSignature)
fatal(toString(f) +
" claims to be a PCH object, but does not have a valid signature");
- auto it = mappings.emplace(*f->pchSignature, this);
+ auto it = ctx.precompSourceMappings.emplace(*f->pchSignature, this);
if (!it.second)
fatal("a PCH object with the same signature has already been provided (" +
toString(it.first->second->file) + " and " + toString(file) + ")");
@@ -134,16 +133,14 @@ class PrecompSource : public TpiSource {
void loadGHashes() override;
bool isDependency() const override { return true; }
-
- static std::map<uint32_t, PrecompSource *> mappings;
};
// This class represents the debug type stream of an OBJ file that depends on a
// Microsoft precompiled headers OBJ (see PrecompSource).
class UsePrecompSource : public TpiSource {
public:
- UsePrecompSource(ObjFile *f, PrecompRecord precomp)
- : TpiSource(UsingPCH, f), precompDependency(precomp) {}
+ UsePrecompSource(COFFLinkerContext &ctx, ObjFile *f, PrecompRecord precomp)
+ : TpiSource(ctx, UsingPCH, f), precompDependency(precomp) {}
Error mergeDebugT(TypeMerger *m) override;
@@ -153,6 +150,10 @@ class UsePrecompSource : public TpiSource {
private:
Error mergeInPrecompHeaderObj();
+ PrecompSource *findObjByName(StringRef fileNameOnly);
+ PrecompSource *findPrecompSource(ObjFile *file, PrecompRecord &pr);
+ Expected<PrecompSource *> findPrecompMap(ObjFile *file, PrecompRecord &pr);
+
public:
// Information about the Precomp OBJ dependency, that needs to be loaded in
// before merging this OBJ.
@@ -160,13 +161,9 @@ class UsePrecompSource : public TpiSource {
};
} // namespace
-std::vector<TpiSource *> TpiSource::instances;
-ArrayRef<TpiSource *> TpiSource::dependencySources;
-ArrayRef<TpiSource *> TpiSource::objectSources;
-
-TpiSource::TpiSource(TpiKind k, ObjFile *f)
- : kind(k), tpiSrcIdx(instances.size()), file(f) {
- instances.push_back(this);
+TpiSource::TpiSource(COFFLinkerContext &ctx, TpiKind k, ObjFile *f)
+ : ctx(ctx), kind(k), tpiSrcIdx(ctx.tpiSourceList.size()), file(f) {
+ ctx.addTpiSource(this);
}
// Vtable key method.
@@ -175,52 +172,35 @@ TpiSource::~TpiSource() {
consumeError(std::move(typeMergingError));
}
-void TpiSource::sortDependencies() {
- // Order dependencies first, but preserve the existing order.
- std::vector<TpiSource *> deps;
- std::vector<TpiSource *> objs;
- for (TpiSource *s : instances)
- (s->isDependency() ? deps : objs).push_back(s);
- uint32_t numDeps = deps.size();
- uint32_t numObjs = objs.size();
- instances = std::move(deps);
- instances.insert(instances.end(), objs.begin(), objs.end());
- for (uint32_t i = 0, e = instances.size(); i < e; ++i)
- instances[i]->tpiSrcIdx = i;
- dependencySources = makeArrayRef(instances.data(), numDeps);
- objectSources = makeArrayRef(instances.data() + numDeps, numObjs);
-}
-
-TpiSource *lld::coff::makeTpiSource(ObjFile *file) {
- return make<TpiSource>(TpiSource::Regular, file);
+TpiSource *lld::coff::makeTpiSource(COFFLinkerContext &ctx, ObjFile *file) {
+ return make<TpiSource>(ctx, TpiSource::Regular, file);
}
-TpiSource *lld::coff::makeTypeServerSource(PDBInputFile *pdbInputFile) {
+TpiSource *lld::coff::makeTypeServerSource(COFFLinkerContext &ctx,
+ PDBInputFile *pdbInputFile) {
// Type server sources come in pairs: the TPI stream, and the IPI stream.
- auto *tpiSource = make<TypeServerSource>(pdbInputFile);
+ auto *tpiSource = make<TypeServerSource>(ctx, pdbInputFile);
if (pdbInputFile->session->getPDBFile().hasPDBIpiStream())
- tpiSource->ipiSrc = make<TypeServerIpiSource>();
+ tpiSource->ipiSrc = make<TypeServerIpiSource>(ctx);
return tpiSource;
}
-TpiSource *lld::coff::makeUseTypeServerSource(ObjFile *file,
+TpiSource *lld::coff::makeUseTypeServerSource(COFFLinkerContext &ctx,
+ ObjFile *file,
TypeServer2Record ts) {
- return make<UseTypeServerSource>(file, ts);
+ return make<UseTypeServerSource>(ctx, file, ts);
}
-TpiSource *lld::coff::makePrecompSource(ObjFile *file) {
- return make<PrecompSource>(file);
+TpiSource *lld::coff::makePrecompSource(COFFLinkerContext &ctx, ObjFile *file) {
+ return make<PrecompSource>(ctx, file);
}
-TpiSource *lld::coff::makeUsePrecompSource(ObjFile *file,
+TpiSource *lld::coff::makeUsePrecompSource(COFFLinkerContext &ctx,
+ ObjFile *file,
PrecompRecord precomp) {
- return make<UsePrecompSource>(file, precomp);
+ return make<UsePrecompSource>(ctx, file, precomp);
}
-std::map<codeview::GUID, TypeServerSource *> TypeServerSource::mappings;
-
-std::map<uint32_t, PrecompSource *> PrecompSource::mappings;
-
bool TpiSource::remapTypeIndex(TypeIndex &ti, TiRefKind refKind) const {
if (ti.isSimple())
return true;
@@ -419,12 +399,12 @@ Expected<TypeServerSource *> UseTypeServerSource::getTypeServerSource() {
StringRef tsPath = typeServerDependency.getName();
TypeServerSource *tsSrc;
- auto it = TypeServerSource::mappings.find(tsId);
- if (it != TypeServerSource::mappings.end()) {
- tsSrc = it->second;
+ auto it = ctx.typeServerSourceMappings.find(tsId);
+ if (it != ctx.typeServerSourceMappings.end()) {
+ tsSrc = (TypeServerSource *)it->second;
} else {
// The file failed to load, lookup by name
- PDBInputFile *pdb = PDBInputFile::findFromRecordPath(tsPath, file);
+ PDBInputFile *pdb = PDBInputFile::findFromRecordPath(ctx, tsPath, file);
if (!pdb)
return createFileError(tsPath, errorCodeToError(std::error_code(
ENOENT, std::generic_category())));
@@ -471,36 +451,37 @@ static bool equalsPath(StringRef path1, StringRef path2) {
}
// Find by name an OBJ provided on the command line
-static PrecompSource *findObjByName(StringRef fileNameOnly) {
+PrecompSource *UsePrecompSource::findObjByName(StringRef fileNameOnly) {
SmallString<128> currentPath;
- for (auto kv : PrecompSource::mappings) {
+ for (auto kv : ctx.precompSourceMappings) {
StringRef currentFileName = sys::path::filename(kv.second->file->getName(),
sys::path::Style::windows);
// Compare based solely on the file name (link.exe behavior)
if (equalsPath(currentFileName, fileNameOnly))
- return kv.second;
+ return (PrecompSource *)kv.second;
}
return nullptr;
}
-static PrecompSource *findPrecompSource(ObjFile *file, PrecompRecord &pr) {
+PrecompSource *UsePrecompSource::findPrecompSource(ObjFile *file,
+ PrecompRecord &pr) {
// Cross-compile warning: given that Clang doesn't generate LF_PRECOMP
// records, we assume the OBJ comes from a Windows build of cl.exe. Thusly,
// the paths embedded in the OBJs are in the Windows format.
SmallString<128> prFileName =
sys::path::filename(pr.getPrecompFilePath(), sys::path::Style::windows);
- auto it = PrecompSource::mappings.find(pr.getSignature());
- if (it != PrecompSource::mappings.end()) {
- return it->second;
+ auto it = ctx.precompSourceMappings.find(pr.getSignature());
+ if (it != ctx.precompSourceMappings.end()) {
+ return (PrecompSource *)it->second;
}
// Lookup by name
return findObjByName(prFileName);
}
-static Expected<PrecompSource *> findPrecompMap(ObjFile *file,
- PrecompRecord &pr) {
+Expected<PrecompSource *> UsePrecompSource::findPrecompMap(ObjFile *file,
+ PrecompRecord &pr) {
PrecompSource *precomp = findPrecompSource(file, pr);
if (!precomp)
@@ -555,22 +536,6 @@ Error UsePrecompSource::mergeDebugT(TypeMerger *m) {
return TpiSource::mergeDebugT(m);
}
-uint32_t TpiSource::countTypeServerPDBs() {
- return TypeServerSource::mappings.size();
-}
-
-uint32_t TpiSource::countPrecompObjs() {
- return PrecompSource::mappings.size();
-}
-
-void TpiSource::clear() {
- // Clean up any owned ghash allocations.
- clearGHashes();
- TpiSource::instances.clear();
- TypeServerSource::mappings.clear();
- PrecompSource::mappings.clear();
-}
-
//===----------------------------------------------------------------------===//
// Parellel GHash type merging implementation.
//===----------------------------------------------------------------------===//
@@ -926,7 +891,8 @@ struct GHashTable {
/// Insert the cell with the given ghash into the table. Return the insertion
/// position in the table. It is safe for the caller to store the insertion
/// position because the table cannot be resized.
- uint32_t insert(GloballyHashedType ghash, GHashCell newCell);
+ uint32_t insert(COFFLinkerContext &ctx, GloballyHashedType ghash,
+ GHashCell newCell);
};
/// A ghash table cell for deduplicating types from TpiSources.
@@ -965,8 +931,8 @@ class GHashCell {
bool isItem() const { return data & (1ULL << 63U); }
/// Get the ghash key for this cell.
- GloballyHashedType getGHash() const {
- return TpiSource::instances[getTpiSrcIdx()]->ghashes[getGHashIdx()];
+ GloballyHashedType getGHash(const COFFLinkerContext &ctx) const {
+ return ctx.tpiSourceList[getTpiSrcIdx()]->ghashes[getGHashIdx()];
}
/// The priority function for the cell. The data is stored such that lower
@@ -996,7 +962,8 @@ void GHashTable::init(uint32_t newTableSize) {
tableSize = newTableSize;
}
-uint32_t GHashTable::insert(GloballyHashedType ghash, GHashCell newCell) {
+uint32_t GHashTable::insert(COFFLinkerContext &ctx, GloballyHashedType ghash,
+ GHashCell newCell) {
assert(!newCell.isEmpty() && "cannot insert empty cell value");
// FIXME: The low bytes of SHA1 have low entropy for short records, which
@@ -1015,7 +982,7 @@ uint32_t GHashTable::insert(GloballyHashedType ghash, GHashCell newCell) {
// - cell has non-matching key: hash collision, probe next cell
auto *cellPtr = reinterpret_cast<std::atomic<GHashCell> *>(&table[idx]);
GHashCell oldCell(cellPtr->load());
- while (oldCell.isEmpty() || oldCell.getGHash() == ghash) {
+ while (oldCell.isEmpty() || oldCell.getGHash(ctx) == ghash) {
// Check if there is an existing ghash entry with a higher priority
// (earlier ordering). If so, this is a duplicate, we are done.
if (!oldCell.isEmpty() && oldCell < newCell)
@@ -1040,22 +1007,22 @@ uint32_t GHashTable::insert(GloballyHashedType ghash, GHashCell newCell) {
llvm_unreachable("left infloop");
}
-TypeMerger::TypeMerger(llvm::BumpPtrAllocator &alloc)
- : typeTable(alloc), idTable(alloc) {}
+TypeMerger::TypeMerger(COFFLinkerContext &c, llvm::BumpPtrAllocator &alloc)
+ : typeTable(alloc), idTable(alloc), ctx(c) {}
TypeMerger::~TypeMerger() = default;
void TypeMerger::mergeTypesWithGHash() {
// Load ghashes. Do type servers and PCH objects first.
{
- ScopedTimer t1(loadGHashTimer);
- parallelForEach(TpiSource::dependencySources,
+ ScopedTimer t1(ctx.loadGHashTimer);
+ parallelForEach(dependencySources,
[&](TpiSource *source) { source->loadGHashes(); });
- parallelForEach(TpiSource::objectSources,
+ parallelForEach(objectSources,
[&](TpiSource *source) { source->loadGHashes(); });
}
- ScopedTimer t2(mergeGHashTimer);
+ ScopedTimer t2(ctx.mergeGHashTimer);
GHashState ghashState;
// Estimate the size of hash table needed to deduplicate ghashes. This *must*
@@ -1066,7 +1033,7 @@ void TypeMerger::mergeTypesWithGHash() {
// small compared to total memory usage, at eight bytes per input type record,
// and most input type records are larger than eight bytes.
size_t tableSize = 0;
- for (TpiSource *source : TpiSource::instances)
+ for (TpiSource *source : ctx.tpiSourceList)
tableSize += source->ghashes.size();
// Cap the table size so that we can use 32-bit cell indices. Type indices are
@@ -1080,8 +1047,8 @@ void TypeMerger::mergeTypesWithGHash() {
// position. Because the table does not rehash, the position will not change
// under insertion. After insertion is done, the value of the cell can be read
// to retrieve the final PDB type index.
- parallelForEachN(0, TpiSource::instances.size(), [&](size_t tpiSrcIdx) {
- TpiSource *source = TpiSource::instances[tpiSrcIdx];
+ parallelForEachN(0, ctx.tpiSourceList.size(), [&](size_t tpiSrcIdx) {
+ TpiSource *source = ctx.tpiSourceList[tpiSrcIdx];
source->indexMapStorage.resize(source->ghashes.size());
for (uint32_t i = 0, e = source->ghashes.size(); i < e; i++) {
if (source->shouldOmitFromPdb(i)) {
@@ -1091,7 +1058,7 @@ void TypeMerger::mergeTypesWithGHash() {
GloballyHashedType ghash = source->ghashes[i];
bool isItem = source->isItemIndex.test(i);
uint32_t cellIdx =
- ghashState.table.insert(ghash, GHashCell(isItem, tpiSrcIdx, i));
+ ghashState.table.insert(ctx, ghash, GHashCell(isItem, tpiSrcIdx, i));
// Store the ghash cell index as a type index in indexMapStorage. Later
// we will replace it with the PDB type index.
@@ -1137,7 +1104,7 @@ void TypeMerger::mergeTypesWithGHash() {
for (uint32_t i = 0, e = entries.size(); i < e; ++i) {
auto &cell = entries[i];
uint32_t tpiSrcIdx = cell.getTpiSrcIdx();
- TpiSource *source = TpiSource::instances[tpiSrcIdx];
+ TpiSource *source = ctx.tpiSourceList[tpiSrcIdx];
source->uniqueTypes.push_back(cell.getGHashIdx());
// Update the ghash table to store the destination PDB type index in the
@@ -1150,21 +1117,37 @@ void TypeMerger::mergeTypesWithGHash() {
}
// In parallel, remap all types.
- for_each(TpiSource::dependencySources, [&](TpiSource *source) {
+ for_each(dependencySources, [&](TpiSource *source) {
source->remapTpiWithGHashes(&ghashState);
});
- parallelForEach(TpiSource::objectSources, [&](TpiSource *source) {
+ parallelForEach(objectSources, [&](TpiSource *source) {
source->remapTpiWithGHashes(&ghashState);
});
// Build a global map of from function ID to function type.
- for (TpiSource *source : TpiSource::instances) {
+ for (TpiSource *source : ctx.tpiSourceList) {
for (auto idToType : source->funcIdToType)
funcIdToType.insert(idToType);
source->funcIdToType.clear();
}
- TpiSource::clearGHashes();
+ ctx.clearGHashes();
+}
+
+void TypeMerger::sortDependencies() {
+ // Order dependencies first, but preserve the existing order.
+ std::vector<TpiSource *> deps;
+ std::vector<TpiSource *> objs;
+ for (TpiSource *s : ctx.tpiSourceList)
+ (s->isDependency() ? deps : objs).push_back(s);
+ uint32_t numDeps = deps.size();
+ uint32_t numObjs = objs.size();
+ ctx.tpiSourceList = std::move(deps);
+ ctx.tpiSourceList.insert(ctx.tpiSourceList.end(), objs.begin(), objs.end());
+ for (uint32_t i = 0, e = ctx.tpiSourceList.size(); i < e; ++i)
+ ctx.tpiSourceList[i]->tpiSrcIdx = i;
+ dependencySources = makeArrayRef(ctx.tpiSourceList.data(), numDeps);
+ objectSources = makeArrayRef(ctx.tpiSourceList.data() + numDeps, numObjs);
}
/// Given the index into the ghash table for a particular type, return the type
@@ -1187,13 +1170,3 @@ void TpiSource::fillMapFromGHashes(GHashState *g) {
loadPdbTypeIndexFromCell(g, fakeCellIndex.toArrayIndex());
}
}
-
-void TpiSource::clearGHashes() {
- for (TpiSource *src : TpiSource::instances) {
- if (src->ownedGHashes)
- delete[] src->ghashes.data();
- src->ghashes = {};
- src->isItemIndex.clear();
- src->uniqueTypes.clear();
- }
-}
diff --git a/lld/COFF/DebugTypes.h b/lld/COFF/DebugTypes.h
index faad30b141e92..b02b5b884cf7e 100644
--- a/lld/COFF/DebugTypes.h
+++ b/lld/COFF/DebugTypes.h
@@ -37,12 +37,13 @@ class ObjFile;
class PDBInputFile;
class TypeMerger;
struct GHashState;
+class COFFLinkerContext;
class TpiSource {
public:
enum TpiKind : uint8_t { Regular, PCH, UsingPCH, PDB, PDBIpi, UsingPDB };
- TpiSource(TpiKind k, ObjFile *f);
+ TpiSource(COFFLinkerContext &ctx, TpiKind k, ObjFile *f);
virtual ~TpiSource();
/// Produce a mapping from the type and item indices used in the object
@@ -93,6 +94,8 @@ class TpiSource {
// Walk over file->debugTypes and fill in the isItemIndex bit vector.
void fillIsItemIndexFromDebugT();
+ COFFLinkerContext &ctx;
+
public:
bool remapTypesInSymbolRecord(MutableArrayRef<uint8_t> rec);
@@ -109,29 +112,6 @@ class TpiSource {
return ghashIdx == endPrecompGHashIdx;
}
- /// All sources of type information in the program.
- static std::vector<TpiSource *> instances;
-
- /// Dependency type sources, such as type servers or PCH object files. These
- /// must be processed before objects that rely on them. Set by
- /// TpiSources::sortDependencies.
- static ArrayRef<TpiSource *> dependencySources;
-
- /// Object file sources. These must be processed after dependencySources.
- static ArrayRef<TpiSource *> objectSources;
-
- /// Sorts the dependencies and reassigns TpiSource indices.
- static void sortDependencies();
-
- static uint32_t countTypeServerPDBs();
- static uint32_t countPrecompObjs();
-
- /// Free heap allocated ghashes.
- static void clearGHashes();
-
- /// Clear global data structures for TpiSources.
- static void clear();
-
const TpiKind kind;
bool ownedGHashes = true;
uint32_t tpiSrcIdx = 0;
@@ -186,12 +166,13 @@ class TpiSource {
uint64_t nbTypeRecordsBytes = 0;
};
-TpiSource *makeTpiSource(ObjFile *file);
-TpiSource *makeTypeServerSource(PDBInputFile *pdbInputFile);
-TpiSource *makeUseTypeServerSource(ObjFile *file,
+TpiSource *makeTpiSource(COFFLinkerContext &ctx, ObjFile *f);
+TpiSource *makeTypeServerSource(COFFLinkerContext &ctx,
+ PDBInputFile *pdbInputFile);
+TpiSource *makeUseTypeServerSource(COFFLinkerContext &ctx, ObjFile *file,
llvm::codeview::TypeServer2Record ts);
-TpiSource *makePrecompSource(ObjFile *file);
-TpiSource *makeUsePrecompSource(ObjFile *file,
+TpiSource *makePrecompSource(COFFLinkerContext &ctx, ObjFile *file);
+TpiSource *makeUsePrecompSource(COFFLinkerContext &ctx, ObjFile *file,
llvm::codeview::PrecompRecord ts);
} // namespace coff
diff --git a/lld/COFF/Driver.cpp b/lld/COFF/Driver.cpp
index fd9ae7f47bf87..9ebd1c336c594 100644
--- a/lld/COFF/Driver.cpp
+++ b/lld/COFF/Driver.cpp
@@ -7,6 +7,7 @@
//===----------------------------------------------------------------------===//
#include "Driver.h"
+#include "COFFLinkerContext.h"
#include "Config.h"
#include "DebugTypes.h"
#include "ICF.h"
@@ -59,8 +60,6 @@ using namespace llvm::sys;
namespace lld {
namespace coff {
-static Timer inputFileTimer("Input File Reading", Timer::root());
-
Configuration *config;
LinkerDriver *driver;
@@ -70,14 +69,7 @@ bool link(ArrayRef<const char *> args, bool canExitEarly, raw_ostream &stdoutOS,
lld::stderrOS = &stderrOS;
errorHandler().cleanupCallback = []() {
- TpiSource::clear();
freeArena();
- ObjFile::instances.clear();
- PDBInputFile::instances.clear();
- ImportFile::instances.clear();
- BitcodeFile::instances.clear();
- memset(MergeChunk::instances, 0, sizeof(MergeChunk::instances));
- OutputSection::clear();
};
errorHandler().logName = args::getFilenameWithoutExe(args[0]);
@@ -87,9 +79,9 @@ bool link(ArrayRef<const char *> args, bool canExitEarly, raw_ostream &stdoutOS,
errorHandler().exitEarly = canExitEarly;
stderrOS.enable_colors(stderrOS.has_colors());
+ COFFLinkerContext ctx;
config = make<Configuration>();
- symtab = make<SymbolTable>();
- driver = make<LinkerDriver>();
+ driver = make<LinkerDriver>(ctx);
driver->linkerMain(args);
@@ -174,8 +166,8 @@ static StringRef mangle(StringRef sym) {
return sym;
}
-static bool findUnderscoreMangle(StringRef sym) {
- Symbol *s = symtab->findMangle(mangle(sym));
+bool LinkerDriver::findUnderscoreMangle(StringRef sym) {
+ Symbol *s = ctx.symtab.findMangle(mangle(sym));
return s && !isa<Undefined>(s);
}
@@ -213,30 +205,30 @@ void LinkerDriver::addBuffer(std::unique_ptr<MemoryBuffer> mb,
addArchiveBuffer(m, "<whole-archive>", filename, memberIndex++);
return;
}
- symtab->addFile(make<ArchiveFile>(mbref));
+ ctx.symtab.addFile(make<ArchiveFile>(ctx, mbref));
break;
case file_magic::bitcode:
if (lazy)
- symtab->addFile(make<LazyObjFile>(mbref));
+ ctx.symtab.addFile(make<LazyObjFile>(ctx, mbref));
else
- symtab->addFile(make<BitcodeFile>(mbref, "", 0));
+ ctx.symtab.addFile(make<BitcodeFile>(ctx, mbref, "", 0));
break;
case file_magic::coff_object:
case file_magic::coff_import_library:
if (lazy)
- symtab->addFile(make<LazyObjFile>(mbref));
+ ctx.symtab.addFile(make<LazyObjFile>(ctx, mbref));
else
- symtab->addFile(make<ObjFile>(mbref));
+ ctx.symtab.addFile(make<ObjFile>(ctx, mbref));
break;
case file_magic::pdb:
- symtab->addFile(make<PDBInputFile>(mbref));
+ ctx.symtab.addFile(make<PDBInputFile>(ctx, mbref));
break;
case file_magic::coff_cl_gl_object:
error(filename + ": is not a native COFF file. Recompile without /GL");
break;
case file_magic::pecoff_executable:
if (config->mingw) {
- symtab->addFile(make<DLLFile>(mbref));
+ ctx.symtab.addFile(make<DLLFile>(ctx, mbref));
break;
}
if (filename.endswith_insensitive(".dll")) {
@@ -280,24 +272,24 @@ void LinkerDriver::addArchiveBuffer(MemoryBufferRef mb, StringRef symName,
uint64_t offsetInArchive) {
file_magic magic = identify_magic(mb.getBuffer());
if (magic == file_magic::coff_import_library) {
- InputFile *imp = make<ImportFile>(mb);
+ InputFile *imp = make<ImportFile>(ctx, mb);
imp->parentName = parentName;
- symtab->addFile(imp);
+ ctx.symtab.addFile(imp);
return;
}
InputFile *obj;
if (magic == file_magic::coff_object) {
- obj = make<ObjFile>(mb);
+ obj = make<ObjFile>(ctx, mb);
} else if (magic == file_magic::bitcode) {
- obj = make<BitcodeFile>(mb, parentName, offsetInArchive);
+ obj = make<BitcodeFile>(ctx, mb, parentName, offsetInArchive);
} else {
error("unknown file type: " + mb.getBufferIdentifier());
return;
}
obj->parentName = parentName;
- symtab->addFile(obj);
+ ctx.symtab.addFile(obj);
log("Loaded " + toString(obj) + " for " + symName);
}
@@ -547,7 +539,7 @@ void LinkerDriver::addLibSearchPaths() {
}
Symbol *LinkerDriver::addUndefined(StringRef name) {
- Symbol *b = symtab->addUndefined(name);
+ Symbol *b = ctx.symtab.addUndefined(name);
if (!b->isGCRoot) {
b->isGCRoot = true;
config->gcroot.push_back(b);
@@ -562,14 +554,14 @@ StringRef LinkerDriver::mangleMaybe(Symbol *s) {
return "";
// Otherwise, see if a similar, mangled symbol exists in the symbol table.
- Symbol *mangled = symtab->findMangle(unmangled->getName());
+ Symbol *mangled = ctx.symtab.findMangle(unmangled->getName());
if (!mangled)
return "";
// If we find a similar mangled symbol, make this an alias to it and return
// its name.
log(unmangled->getName() + " aliased to " + mangled->getName());
- unmangled->weakAlias = symtab->addUndefined(mangled->getName());
+ unmangled->weakAlias = ctx.symtab.addUndefined(mangled->getName());
return mangled->getName();
}
@@ -939,7 +931,7 @@ void LinkerDriver::enqueueTask(std::function<void()> task) {
}
bool LinkerDriver::run() {
- ScopedTimer t(inputFileTimer);
+ ScopedTimer t(ctx.inputFileTimer);
bool didWork = !taskQueue.empty();
while (!taskQueue.empty()) {
@@ -952,7 +944,7 @@ bool LinkerDriver::run() {
// Parse an /order file. If an option is given, the linker places
// COMDAT sections in the same order as their names appear in the
// given file.
-static void parseOrderFile(StringRef arg) {
+static void parseOrderFile(COFFLinkerContext &ctx, StringRef arg) {
// For some reason, the MSVC linker requires a filename to be
// preceded by "@".
if (!arg.startswith("@")) {
@@ -962,7 +954,7 @@ static void parseOrderFile(StringRef arg) {
// Get a list of all comdat sections for error checking.
DenseSet<StringRef> set;
- for (Chunk *c : symtab->getChunks())
+ for (Chunk *c : ctx.symtab.getChunks())
if (auto *sec = dyn_cast<SectionChunk>(c))
if (sec->sym)
set.insert(sec->sym->getName());
@@ -996,7 +988,7 @@ static void parseOrderFile(StringRef arg) {
driver->takeBuffer(std::move(mb));
}
-static void parseCallGraphFile(StringRef path) {
+static void parseCallGraphFile(COFFLinkerContext &ctx, StringRef path) {
std::unique_ptr<MemoryBuffer> mb =
CHECK(MemoryBuffer::getFile(path, /*IsText=*/false,
/*RequiresNullTerminator=*/false,
@@ -1005,7 +997,7 @@ static void parseCallGraphFile(StringRef path) {
// Build a map from symbol name to section.
DenseMap<StringRef, Symbol *> map;
- for (ObjFile *file : ObjFile::instances)
+ for (ObjFile *file : ctx.objFileInstances)
for (Symbol *sym : file->getSymbols())
if (sym)
map[sym->getName()] = sym;
@@ -1042,8 +1034,8 @@ static void parseCallGraphFile(StringRef path) {
driver->takeBuffer(std::move(mb));
}
-static void readCallGraphsFromObjectFiles() {
- for (ObjFile *obj : ObjFile::instances) {
+static void readCallGraphsFromObjectFiles(COFFLinkerContext &ctx) {
+ for (ObjFile *obj : ctx.objFileInstances) {
if (obj->callgraphSec) {
ArrayRef<uint8_t> contents;
cantFail(
@@ -1077,7 +1069,7 @@ static void markAddrsig(Symbol *s) {
c->keepUnique = true;
}
-static void findKeepUniqueSections() {
+static void findKeepUniqueSections(COFFLinkerContext &ctx) {
// Exported symbols could be address-significant in other executables or DSOs,
// so we conservatively mark them as address-significant.
for (Export &r : config->exports)
@@ -1085,7 +1077,7 @@ static void findKeepUniqueSections() {
// Visit the address-significance table in each object file and mark each
// referenced symbol as address-significant.
- for (ObjFile *obj : ObjFile::instances) {
+ for (ObjFile *obj : ctx.objFileInstances) {
ArrayRef<Symbol *> syms = obj->getSymbols();
if (obj->addrsigSec) {
ArrayRef<uint8_t> contents;
@@ -1169,7 +1161,7 @@ static void parsePDBAltPath(StringRef altPath) {
void LinkerDriver::convertResources() {
std::vector<ObjFile *> resourceObjFiles;
- for (ObjFile *f : ObjFile::instances) {
+ for (ObjFile *f : ctx.objFileInstances) {
if (f->isResourceObjFile())
resourceObjFiles.push_back(f);
}
@@ -1191,8 +1183,9 @@ void LinkerDriver::convertResources() {
f->includeResourceChunks();
return;
}
- ObjFile *f = make<ObjFile>(convertResToCOFF(resources, resourceObjFiles));
- symtab->addFile(f);
+ ObjFile *f =
+ make<ObjFile>(ctx, convertResToCOFF(resources, resourceObjFiles));
+ ctx.symtab.addFile(f);
f->includeResourceChunks();
}
@@ -1219,9 +1212,9 @@ void LinkerDriver::maybeExportMinGWSymbols(const opt::InputArgList &args) {
if (Optional<StringRef> path = doFindFile(arg->getValue()))
exporter.addWholeArchive(*path);
- symtab->forEachSymbol([&](Symbol *s) {
+ ctx.symtab.forEachSymbol([&](Symbol *s) {
auto *def = dyn_cast<Defined>(s);
- if (!exporter.shouldExport(def))
+ if (!exporter.shouldExport(ctx, def))
return;
if (!def->isGCRoot) {
@@ -1266,7 +1259,7 @@ Optional<std::string> getReproduceFile(const opt::InputArgList &args) {
}
void LinkerDriver::linkerMain(ArrayRef<const char *> argsArr) {
- ScopedTimer rootTimer(Timer::root());
+ ScopedTimer rootTimer(ctx.rootTimer);
// Needed for LTO.
InitializeAllTargetInfos();
@@ -2018,32 +2011,32 @@ void LinkerDriver::linkerMain(ArrayRef<const char *> argsArr) {
if (config->imageBase == uint64_t(-1))
config->imageBase = getDefaultImageBase();
- symtab->addSynthetic(mangle("__ImageBase"), nullptr);
+ ctx.symtab.addSynthetic(mangle("__ImageBase"), nullptr);
if (config->machine == I386) {
- symtab->addAbsolute("___safe_se_handler_table", 0);
- symtab->addAbsolute("___safe_se_handler_count", 0);
+ ctx.symtab.addAbsolute("___safe_se_handler_table", 0);
+ ctx.symtab.addAbsolute("___safe_se_handler_count", 0);
}
- symtab->addAbsolute(mangle("__guard_fids_count"), 0);
- symtab->addAbsolute(mangle("__guard_fids_table"), 0);
- symtab->addAbsolute(mangle("__guard_flags"), 0);
- symtab->addAbsolute(mangle("__guard_iat_count"), 0);
- symtab->addAbsolute(mangle("__guard_iat_table"), 0);
- symtab->addAbsolute(mangle("__guard_longjmp_count"), 0);
- symtab->addAbsolute(mangle("__guard_longjmp_table"), 0);
+ ctx.symtab.addAbsolute(mangle("__guard_fids_count"), 0);
+ ctx.symtab.addAbsolute(mangle("__guard_fids_table"), 0);
+ ctx.symtab.addAbsolute(mangle("__guard_flags"), 0);
+ ctx.symtab.addAbsolute(mangle("__guard_iat_count"), 0);
+ ctx.symtab.addAbsolute(mangle("__guard_iat_table"), 0);
+ ctx.symtab.addAbsolute(mangle("__guard_longjmp_count"), 0);
+ ctx.symtab.addAbsolute(mangle("__guard_longjmp_table"), 0);
// Needed for MSVC 2017 15.5 CRT.
- symtab->addAbsolute(mangle("__enclave_config"), 0);
+ ctx.symtab.addAbsolute(mangle("__enclave_config"), 0);
// Needed for MSVC 2019 16.8 CRT.
- symtab->addAbsolute(mangle("__guard_eh_cont_count"), 0);
- symtab->addAbsolute(mangle("__guard_eh_cont_table"), 0);
+ ctx.symtab.addAbsolute(mangle("__guard_eh_cont_count"), 0);
+ ctx.symtab.addAbsolute(mangle("__guard_eh_cont_table"), 0);
if (config->pseudoRelocs) {
- symtab->addAbsolute(mangle("__RUNTIME_PSEUDO_RELOC_LIST__"), 0);
- symtab->addAbsolute(mangle("__RUNTIME_PSEUDO_RELOC_LIST_END__"), 0);
+ ctx.symtab.addAbsolute(mangle("__RUNTIME_PSEUDO_RELOC_LIST__"), 0);
+ ctx.symtab.addAbsolute(mangle("__RUNTIME_PSEUDO_RELOC_LIST_END__"), 0);
}
if (config->mingw) {
- symtab->addAbsolute(mangle("__CTOR_LIST__"), 0);
- symtab->addAbsolute(mangle("__DTOR_LIST__"), 0);
+ ctx.symtab.addAbsolute(mangle("__CTOR_LIST__"), 0);
+ ctx.symtab.addAbsolute(mangle("__DTOR_LIST__"), 0);
}
// This code may add new undefined symbols to the link, which may enqueue more
@@ -2069,12 +2062,12 @@ void LinkerDriver::linkerMain(ArrayRef<const char *> argsArr) {
for (auto pair : config->alternateNames) {
StringRef from = pair.first;
StringRef to = pair.second;
- Symbol *sym = symtab->find(from);
+ Symbol *sym = ctx.symtab.find(from);
if (!sym)
continue;
if (auto *u = dyn_cast<Undefined>(sym))
if (!u->weakAlias)
- u->weakAlias = symtab->addUndefined(to);
+ u->weakAlias = ctx.symtab.addUndefined(to);
}
// If any inputs are bitcode files, the LTO code generator may create
@@ -2082,25 +2075,25 @@ void LinkerDriver::linkerMain(ArrayRef<const char *> argsArr) {
// file's symbol table. If any of those library functions are defined in a
// bitcode file in an archive member, we need to arrange to use LTO to
// compile those archive members by adding them to the link beforehand.
- if (!BitcodeFile::instances.empty())
+ if (!ctx.bitcodeFileInstances.empty())
for (auto *s : lto::LTO::getRuntimeLibcallSymbols())
- symtab->addLibcall(s);
+ ctx.symtab.addLibcall(s);
// Windows specific -- if __load_config_used can be resolved, resolve it.
- if (symtab->findUnderscore("_load_config_used"))
+ if (ctx.symtab.findUnderscore("_load_config_used"))
addUndefined(mangle("_load_config_used"));
} while (run());
if (args.hasArg(OPT_include_optional)) {
// Handle /includeoptional
for (auto *arg : args.filtered(OPT_include_optional))
- if (dyn_cast_or_null<LazyArchive>(symtab->find(arg->getValue())))
+ if (dyn_cast_or_null<LazyArchive>(ctx.symtab.find(arg->getValue())))
addUndefined(arg->getValue());
while (run());
}
// Create wrapped symbols for -wrap option.
- std::vector<WrappedSymbol> wrapped = addWrappedSymbols(args);
+ std::vector<WrappedSymbol> wrapped = addWrappedSymbols(ctx, args);
// Load more object files that might be needed for wrapped symbols.
if (!wrapped.empty())
while (run());
@@ -2126,7 +2119,7 @@ void LinkerDriver::linkerMain(ArrayRef<const char *> argsArr) {
// If it ends up pulling in more object files from static libraries,
// (and maybe doing more stdcall fixups along the way), this would need
// to loop these two calls.
- symtab->loadMinGWSymbols();
+ ctx.symtab.loadMinGWSymbols();
run();
}
@@ -2134,8 +2127,8 @@ void LinkerDriver::linkerMain(ArrayRef<const char *> argsArr) {
// If we are going to do codegen for link-time optimization, check for
// unresolvable symbols first, so we don't spend time generating code that
// will fail to link anyway.
- if (!BitcodeFile::instances.empty() && !config->forceUnresolved)
- symtab->reportUnresolvable();
+ if (!ctx.bitcodeFileInstances.empty() && !config->forceUnresolved)
+ ctx.symtab.reportUnresolvable();
if (errorCount())
return;
@@ -2149,7 +2142,7 @@ void LinkerDriver::linkerMain(ArrayRef<const char *> argsArr) {
// Do LTO by compiling bitcode input files to a set of native COFF files then
// link those files (unless -thinlto-index-only was given, in which case we
// resolve symbols and write indices, but don't generate native code or link).
- symtab->addCombinedLTOObjects();
+ ctx.symtab.addCombinedLTOObjects();
// If -thinlto-index-only is given, we should create only "index
// files" and not object files. Index file creation is already done
@@ -2163,10 +2156,10 @@ void LinkerDriver::linkerMain(ArrayRef<const char *> argsArr) {
// Apply symbol renames for -wrap.
if (!wrapped.empty())
- wrapSymbols(wrapped);
+ wrapSymbols(ctx, wrapped);
// Resolve remaining undefined symbols and warn about imported locals.
- symtab->resolveRemainingUndefines();
+ ctx.symtab.resolveRemainingUndefines();
if (errorCount())
return;
@@ -2177,12 +2170,12 @@ void LinkerDriver::linkerMain(ArrayRef<const char *> argsArr) {
// order provided on the command line, while lld will pull in needed
// files from static libraries only after the last object file on the
// command line.
- for (auto i = ObjFile::instances.begin(), e = ObjFile::instances.end();
+ for (auto i = ctx.objFileInstances.begin(), e = ctx.objFileInstances.end();
i != e; i++) {
ObjFile *file = *i;
if (isCrtend(file->getName())) {
- ObjFile::instances.erase(i);
- ObjFile::instances.push_back(file);
+ ctx.objFileInstances.erase(i);
+ ctx.objFileInstances.push_back(file);
break;
}
}
@@ -2207,7 +2200,7 @@ void LinkerDriver::linkerMain(ArrayRef<const char *> argsArr) {
StringRef name = pair.first;
uint32_t alignment = pair.second;
- Symbol *sym = symtab->find(name);
+ Symbol *sym = ctx.symtab.find(name);
if (!sym) {
warn("/aligncomm symbol " + name + " not found");
continue;
@@ -2239,16 +2232,16 @@ void LinkerDriver::linkerMain(ArrayRef<const char *> argsArr) {
if (auto *arg = args.getLastArg(OPT_order)) {
if (args.hasArg(OPT_call_graph_ordering_file))
error("/order and /call-graph-order-file may not be used together");
- parseOrderFile(arg->getValue());
+ parseOrderFile(ctx, arg->getValue());
config->callGraphProfileSort = false;
}
// Handle /call-graph-ordering-file and /call-graph-profile-sort (default on).
if (config->callGraphProfileSort) {
if (auto *arg = args.getLastArg(OPT_call_graph_ordering_file)) {
- parseCallGraphFile(arg->getValue());
+ parseCallGraphFile(ctx, arg->getValue());
}
- readCallGraphsFromObjectFiles();
+ readCallGraphsFromObjectFiles(ctx);
}
// Handle /print-symbol-order.
@@ -2265,7 +2258,7 @@ void LinkerDriver::linkerMain(ArrayRef<const char *> argsArr) {
// functions. This doesn't bring in more object files, but only marks
// functions that already have been included to be retained.
for (const char *n : {"__gxx_personality_v0", "__gcc_personality_v0"}) {
- Defined *d = dyn_cast_or_null<Defined>(symtab->findUnderscore(n));
+ Defined *d = dyn_cast_or_null<Defined>(ctx.symtab.findUnderscore(n));
if (d && !d->isGCRoot) {
d->isGCRoot = true;
config->gcroot.push_back(d);
@@ -2273,7 +2266,7 @@ void LinkerDriver::linkerMain(ArrayRef<const char *> argsArr) {
}
}
- markLive(symtab->getChunks());
+ markLive(ctx);
}
// Needs to happen after the last call to addFile().
@@ -2281,17 +2274,17 @@ void LinkerDriver::linkerMain(ArrayRef<const char *> argsArr) {
// Identify identical COMDAT sections to merge them.
if (config->doICF != ICFLevel::None) {
- findKeepUniqueSections();
- doICF(symtab->getChunks(), config->doICF);
+ findKeepUniqueSections(ctx);
+ doICF(ctx, config->doICF);
}
// Write the result.
- writeResult();
+ writeResult(ctx);
// Stop early so we can print the results.
rootTimer.stop();
if (config->showTiming)
- Timer::root().print();
+ ctx.rootTimer.print();
}
} // namespace coff
diff --git a/lld/COFF/Driver.h b/lld/COFF/Driver.h
index 5729bed69528b..7c2fbe3c7d64c 100644
--- a/lld/COFF/Driver.h
+++ b/lld/COFF/Driver.h
@@ -9,6 +9,7 @@
#ifndef LLD_COFF_DRIVER_H
#define LLD_COFF_DRIVER_H
+#include "COFFLinkerContext.h"
#include "Config.h"
#include "SymbolTable.h"
#include "lld/Common/LLVM.h"
@@ -78,6 +79,8 @@ class ArgParser {
class LinkerDriver {
public:
+ LinkerDriver(COFFLinkerContext &c) : ctx(c) {}
+
void linkerMain(llvm::ArrayRef<const char *> args);
// Used by the resolver to parse .drectve section contents.
@@ -103,6 +106,8 @@ class LinkerDriver {
StringRef doFindLib(StringRef filename);
StringRef doFindLibMinGW(StringRef filename);
+ bool findUnderscoreMangle(StringRef sym);
+
// Parses LIB environment which contains a list of search paths.
void addLibSearchPaths();
@@ -148,6 +153,8 @@ class LinkerDriver {
std::vector<MemoryBufferRef> resources;
llvm::StringSet<> directivesExports;
+
+ COFFLinkerContext &ctx;
};
// Functions below this line are defined in DriverUtils.cpp.
diff --git a/lld/COFF/ICF.cpp b/lld/COFF/ICF.cpp
index 7326469672968..8323626623948 100644
--- a/lld/COFF/ICF.cpp
+++ b/lld/COFF/ICF.cpp
@@ -18,6 +18,7 @@
//===----------------------------------------------------------------------===//
#include "ICF.h"
+#include "COFFLinkerContext.h"
#include "Chunks.h"
#include "Symbols.h"
#include "lld/Common/ErrorHandler.h"
@@ -36,12 +37,10 @@ using namespace llvm;
namespace lld {
namespace coff {
-static Timer icfTimer("ICF", Timer::root());
-
class ICF {
public:
- ICF(ICFLevel icfLevel) : icfLevel(icfLevel){};
- void run(ArrayRef<Chunk *> v);
+ ICF(COFFLinkerContext &c, ICFLevel icfLevel) : icfLevel(icfLevel), ctx(c){};
+ void run();
private:
void segregate(size_t begin, size_t end, bool constant);
@@ -64,6 +63,8 @@ class ICF {
int cnt = 0;
std::atomic<bool> repeat = {false};
ICFLevel icfLevel = ICFLevel::All;
+
+ COFFLinkerContext &ctx;
};
// Returns true if section S is subject of ICF.
@@ -246,12 +247,12 @@ void ICF::forEachClass(std::function<void(size_t, size_t)> fn) {
// Merge identical COMDAT sections.
// Two sections are considered the same if their section headers,
// contents and relocations are all the same.
-void ICF::run(ArrayRef<Chunk *> vec) {
- ScopedTimer t(icfTimer);
+void ICF::run() {
+ ScopedTimer t(ctx.icfTimer);
// Collect only mergeable sections and group by hash value.
uint32_t nextId = 1;
- for (Chunk *c : vec) {
+ for (Chunk *c : ctx.symtab.getChunks()) {
if (auto *sc = dyn_cast<SectionChunk>(c)) {
if (isEligible(sc))
chunks.push_back(sc);
@@ -262,7 +263,7 @@ void ICF::run(ArrayRef<Chunk *> vec) {
// Make sure that ICF doesn't merge sections that are being handled by string
// tail merging.
- for (MergeChunk *mc : MergeChunk::instances)
+ for (MergeChunk *mc : ctx.mergeChunkInstances)
if (mc)
for (SectionChunk *sc : mc->sections)
sc->eqClass[0] = nextId++;
@@ -317,8 +318,8 @@ void ICF::run(ArrayRef<Chunk *> vec) {
}
// Entry point to ICF.
-void doICF(ArrayRef<Chunk *> chunks, ICFLevel icfLevel) {
- ICF(icfLevel).run(chunks);
+void doICF(COFFLinkerContext &ctx, ICFLevel icfLevel) {
+ ICF(ctx, icfLevel).run();
}
} // namespace coff
diff --git a/lld/COFF/ICF.h b/lld/COFF/ICF.h
index f8cc8071f9eb7..10e6792a5418f 100644
--- a/lld/COFF/ICF.h
+++ b/lld/COFF/ICF.h
@@ -17,8 +17,9 @@ namespace lld {
namespace coff {
class Chunk;
+class COFFLinkerContext;
-void doICF(ArrayRef<Chunk *> chunks, ICFLevel);
+void doICF(COFFLinkerContext &ctx, ICFLevel);
} // namespace coff
} // namespace lld
diff --git a/lld/COFF/InputFiles.cpp b/lld/COFF/InputFiles.cpp
index f32353ca4f94a..4b38e3d1a99bc 100644
--- a/lld/COFF/InputFiles.cpp
+++ b/lld/COFF/InputFiles.cpp
@@ -7,6 +7,7 @@
//===----------------------------------------------------------------------===//
#include "InputFiles.h"
+#include "COFFLinkerContext.h"
#include "Chunks.h"
#include "Config.h"
#include "DebugTypes.h"
@@ -69,11 +70,6 @@ std::string lld::toString(const coff::InputFile *file) {
.str();
}
-std::vector<ObjFile *> ObjFile::instances;
-std::map<std::string, PDBInputFile *> PDBInputFile::instances;
-std::vector<ImportFile *> ImportFile::instances;
-std::vector<BitcodeFile *> BitcodeFile::instances;
-
/// Checks that Source is compatible with being a weak alias to Target.
/// If Source is Undefined and has no weak alias set, makes it a weak
/// alias to Target.
@@ -98,7 +94,8 @@ static bool ignoredSymbolName(StringRef name) {
return name == "@feat.00" || name == "@comp.id";
}
-ArchiveFile::ArchiveFile(MemoryBufferRef m) : InputFile(ArchiveKind, m) {}
+ArchiveFile::ArchiveFile(COFFLinkerContext &ctx, MemoryBufferRef m)
+ : InputFile(ctx, ArchiveKind, m) {}
void ArchiveFile::parse() {
// Parse a MemoryBufferRef as an archive file.
@@ -106,7 +103,7 @@ void ArchiveFile::parse() {
// Read the symbol table to construct Lazy objects.
for (const Archive::Symbol &sym : file->symbols())
- symtab->addLazyArchive(this, sym);
+ ctx.symtab.addLazyArchive(this, sym);
}
// Returns a buffer pointing to a member file containing a given symbol.
@@ -144,11 +141,11 @@ void LazyObjFile::fetch() {
InputFile *file;
if (isBitcode(mb))
- file = make<BitcodeFile>(mb, "", 0, std::move(symbols));
+ file = make<BitcodeFile>(ctx, mb, "", 0, std::move(symbols));
else
- file = make<ObjFile>(mb, std::move(symbols));
+ file = make<ObjFile>(ctx, mb, std::move(symbols));
mb = {};
- symtab->addFile(file);
+ ctx.symtab.addFile(file);
}
void LazyObjFile::parse() {
@@ -158,7 +155,7 @@ void LazyObjFile::parse() {
CHECK(lto::InputFile::create(this->mb), this);
for (const lto::InputFile::Symbol &sym : obj->symbols()) {
if (!sym.isUndefined())
- symtab->addLazyObject(this, sym.getName());
+ ctx.symtab.addLazyObject(this, sym.getName());
}
return;
}
@@ -175,7 +172,7 @@ void LazyObjFile::parse() {
StringRef name = check(coffObj->getSymbolName(coffSym));
if (coffSym.isAbsolute() && ignoredSymbolName(name))
continue;
- symtab->addLazyObject(this, name);
+ ctx.symtab.addLazyObject(this, name);
i += coffSym.getNumberOfAuxSymbols();
}
}
@@ -293,7 +290,7 @@ SectionChunk *ObjFile::readSection(uint32_t sectionNumber,
// COFF sections that look like string literal sections (i.e. no
// relocations, in .rdata, leader symbol name matches the MSVC name mangling
// for string literals) are subject to string tail merging.
- MergeChunk::addSection(c);
+ MergeChunk::addSection(ctx, c);
else if (name == ".rsrc" || name.startswith(".rsrc$"))
resourceChunks.push_back(c);
else
@@ -387,8 +384,8 @@ Symbol *ObjFile::createRegular(COFFSymbolRef sym) {
if (sym.isExternal()) {
StringRef name = check(coffObj->getSymbolName(sym));
if (sc)
- return symtab->addRegular(this, name, sym.getGeneric(), sc,
- sym.getValue());
+ return ctx.symtab.addRegular(this, name, sym.getGeneric(), sc,
+ sym.getValue());
// For MinGW symbols named .weak.* that point to a discarded section,
// don't create an Undefined symbol. If nothing ever refers to the symbol,
// everything should be fine. If something actually refers to the symbol
@@ -396,7 +393,7 @@ Symbol *ObjFile::createRegular(COFFSymbolRef sym) {
// references at the end.
if (config->mingw && name.startswith(".weak."))
return nullptr;
- return symtab->addUndefined(name, this, false);
+ return ctx.symtab.addUndefined(name, this, false);
}
if (sc)
return make<DefinedRegular>(this, /*Name*/ "", /*IsCOMDAT*/ false,
@@ -464,7 +461,7 @@ void ObjFile::initializeSymbols() {
for (auto &kv : weakAliases) {
Symbol *sym = kv.first;
uint32_t idx = kv.second;
- checkAndSetWeakAlias(symtab, this, sym, symbols[idx]);
+ checkAndSetWeakAlias(&ctx.symtab, this, sym, symbols[idx]);
}
// Free the memory used by sparseChunks now that symbol loading is finished.
@@ -473,7 +470,7 @@ void ObjFile::initializeSymbols() {
Symbol *ObjFile::createUndefined(COFFSymbolRef sym) {
StringRef name = check(coffObj->getSymbolName(sym));
- return symtab->addUndefined(name, this, sym.isWeakExternal());
+ return ctx.symtab.addUndefined(name, this, sym.isWeakExternal());
}
static const coff_aux_section_definition *findSectionDef(COFFObjectFile *obj,
@@ -543,13 +540,13 @@ void ObjFile::handleComdatSelection(
Twine((int)leaderSelection) + " in " + toString(leader->getFile()) +
" and " + Twine((int)selection) + " in " + toString(this))
.str());
- symtab->reportDuplicate(leader, this);
+ ctx.symtab.reportDuplicate(leader, this);
return;
}
switch (selection) {
case IMAGE_COMDAT_SELECT_NODUPLICATES:
- symtab->reportDuplicate(leader, this);
+ ctx.symtab.reportDuplicate(leader, this);
break;
case IMAGE_COMDAT_SELECT_ANY:
@@ -559,14 +556,14 @@ void ObjFile::handleComdatSelection(
case IMAGE_COMDAT_SELECT_SAME_SIZE:
if (leaderChunk->getSize() != getSection(sym)->SizeOfRawData) {
if (!config->mingw) {
- symtab->reportDuplicate(leader, this);
+ ctx.symtab.reportDuplicate(leader, this);
} else {
const coff_aux_section_definition *leaderDef = nullptr;
if (leaderChunk->file)
leaderDef = findSectionDef(leaderChunk->file->getCOFFObj(),
leaderChunk->getSectionNumber());
if (!leaderDef || leaderDef->Length != def->Length)
- symtab->reportDuplicate(leader, this);
+ ctx.symtab.reportDuplicate(leader, this);
}
}
break;
@@ -577,7 +574,7 @@ void ObjFile::handleComdatSelection(
// if the two comdat sections have e.g.
diff erent alignment.
// Match that.
if (leaderChunk->getContents() != newChunk.getContents())
- symtab->reportDuplicate(leader, this, &newChunk, sym.getValue());
+ ctx.symtab.reportDuplicate(leader, this, &newChunk, sym.getValue());
break;
}
@@ -620,8 +617,8 @@ Optional<Symbol *> ObjFile::createDefined(
if (sym.isCommon()) {
auto *c = make<CommonChunk>(sym);
chunks.push_back(c);
- return symtab->addCommon(this, getName(), sym.getValue(), sym.getGeneric(),
- c);
+ return ctx.symtab.addCommon(this, getName(), sym.getValue(),
+ sym.getGeneric(), c);
}
if (sym.isAbsolute()) {
@@ -634,7 +631,7 @@ Optional<Symbol *> ObjFile::createDefined(
return nullptr;
if (sym.isExternal())
- return symtab->addAbsolute(name, sym);
+ return ctx.symtab.addAbsolute(name, sym);
return make<DefinedAbsolute>(name, sym);
}
@@ -667,7 +664,7 @@ Optional<Symbol *> ObjFile::createDefined(
if (sym.isExternal()) {
std::tie(leader, prevailing) =
- symtab->addComdat(this, getName(), sym.getGeneric());
+ ctx.symtab.addComdat(this, getName(), sym.getGeneric());
} else {
leader = make<DefinedRegular>(this, /*Name*/ "", /*IsCOMDAT*/ false,
/*IsExternal*/ false, sym.getGeneric());
@@ -789,12 +786,11 @@ void ObjFile::initializeDependencies() {
else
data = getDebugSection(".debug$T");
- // Don't make a TpiSource for objects with no debug info. If the object has
// symbols but no types, make a plain, empty TpiSource anyway, because it
// simplifies adding the symbols later.
if (data.empty()) {
if (!debugChunks.empty())
- debugTypesObj = makeTpiSource(this);
+ debugTypesObj = makeTpiSource(ctx, this);
return;
}
@@ -812,7 +808,7 @@ void ObjFile::initializeDependencies() {
// This object file is a PCH file that others will depend on.
if (isPCH) {
- debugTypesObj = makePrecompSource(this);
+ debugTypesObj = makePrecompSource(ctx, this);
return;
}
@@ -820,8 +816,8 @@ void ObjFile::initializeDependencies() {
if (firstType->kind() == LF_TYPESERVER2) {
TypeServer2Record ts = cantFail(
TypeDeserializer::deserializeAs<TypeServer2Record>(firstType->data()));
- debugTypesObj = makeUseTypeServerSource(this, ts);
- PDBInputFile::enqueue(ts.getName(), this);
+ debugTypesObj = makeUseTypeServerSource(ctx, this, ts);
+ enqueuePdbFile(ts.getName(), this);
return;
}
@@ -830,14 +826,14 @@ void ObjFile::initializeDependencies() {
if (firstType->kind() == LF_PRECOMP) {
PrecompRecord precomp = cantFail(
TypeDeserializer::deserializeAs<PrecompRecord>(firstType->data()));
- debugTypesObj = makeUsePrecompSource(this, precomp);
+ debugTypesObj = makeUsePrecompSource(ctx, this, precomp);
// Drop the LF_PRECOMP record from the input stream.
debugTypes = debugTypes.drop_front(firstType->RecordData.size());
return;
}
// This is a plain old object file.
- debugTypesObj = makeTpiSource(this);
+ debugTypesObj = makeTpiSource(ctx, this);
}
// Make a PDB path assuming the PDB is in the same folder as the OBJ
@@ -855,7 +851,7 @@ static std::string getPdbBaseName(ObjFile *file, StringRef tSPath) {
// The casing of the PDB path stamped in the OBJ can
diff er from the actual path
// on disk. With this, we ensure to always use lowercase as a key for the
-// PDBInputFile::instances map, at least on Windows.
+// pdbInputFileInstances map, at least on Windows.
static std::string normalizePdbPath(StringRef path) {
#if defined(_WIN32)
return path.lower();
@@ -879,33 +875,25 @@ static Optional<std::string> findPdbPath(StringRef pdbPath,
return None;
}
-PDBInputFile::PDBInputFile(MemoryBufferRef m) : InputFile(PDBKind, m) {}
+PDBInputFile::PDBInputFile(COFFLinkerContext &ctx, MemoryBufferRef m)
+ : InputFile(ctx, PDBKind, m) {}
PDBInputFile::~PDBInputFile() = default;
-PDBInputFile *PDBInputFile::findFromRecordPath(StringRef path,
+PDBInputFile *PDBInputFile::findFromRecordPath(const COFFLinkerContext &ctx,
+ StringRef path,
ObjFile *fromFile) {
auto p = findPdbPath(path.str(), fromFile);
if (!p)
return nullptr;
- auto it = PDBInputFile::instances.find(*p);
- if (it != PDBInputFile::instances.end())
+ auto it = ctx.pdbInputFileInstances.find(*p);
+ if (it != ctx.pdbInputFileInstances.end())
return it->second;
return nullptr;
}
-void PDBInputFile::enqueue(StringRef path, ObjFile *fromFile) {
- auto p = findPdbPath(path.str(), fromFile);
- if (!p)
- return;
- auto it = PDBInputFile::instances.emplace(*p, nullptr);
- if (!it.second)
- return; // already scheduled for load
- driver->enqueuePDB(*p);
-}
-
void PDBInputFile::parse() {
- PDBInputFile::instances[mb.getBufferIdentifier().str()] = this;
+ ctx.pdbInputFileInstances[mb.getBufferIdentifier().str()] = this;
std::unique_ptr<pdb::IPDBSession> thisSession;
loadErr.emplace(pdb::NativeSession::createFromPdb(
@@ -923,7 +911,7 @@ void PDBInputFile::parse() {
loadErr.emplace(expectedInfo.takeError());
return;
}
- debugTypesObj = makeTypeServerSource(this);
+ debugTypesObj = makeTypeServerSource(ctx, this);
}
// Used only for DWARF debug info, which is not common (except in MinGW
@@ -957,6 +945,16 @@ Optional<DILineInfo> ObjFile::getDILineInfo(uint32_t offset,
return dwarf->getDILineInfo(offset, sectionIndex);
}
+void ObjFile::enqueuePdbFile(StringRef path, ObjFile *fromFile) {
+ auto p = findPdbPath(path.str(), fromFile);
+ if (!p)
+ return;
+ auto it = ctx.pdbInputFileInstances.emplace(*p, nullptr);
+ if (!it.second)
+ return; // already scheduled for load
+ driver->enqueuePDB(*p);
+}
+
void ImportFile::parse() {
const char *buf = mb.getBufferStart();
const auto *hdr = reinterpret_cast<const coff_import_header *>(buf);
@@ -990,31 +988,31 @@ void ImportFile::parse() {
this->hdr = hdr;
externalName = extName;
- impSym = symtab->addImportData(impName, this);
+ impSym = ctx.symtab.addImportData(impName, this);
// If this was a duplicate, we logged an error but may continue;
// in this case, impSym is nullptr.
if (!impSym)
return;
if (hdr->getType() == llvm::COFF::IMPORT_CONST)
- static_cast<void>(symtab->addImportData(name, this));
+ static_cast<void>(ctx.symtab.addImportData(name, this));
// If type is function, we need to create a thunk which jump to an
// address pointed by the __imp_ symbol. (This allows you to call
// DLL functions just like regular non-DLL functions.)
if (hdr->getType() == llvm::COFF::IMPORT_CODE)
- thunkSym = symtab->addImportThunk(
+ thunkSym = ctx.symtab.addImportThunk(
name, cast_or_null<DefinedImportData>(impSym), hdr->Machine);
}
-BitcodeFile::BitcodeFile(MemoryBufferRef mb, StringRef archiveName,
- uint64_t offsetInArchive)
- : BitcodeFile(mb, archiveName, offsetInArchive, {}) {}
+BitcodeFile::BitcodeFile(COFFLinkerContext &ctx, MemoryBufferRef mb,
+ StringRef archiveName, uint64_t offsetInArchive)
+ : BitcodeFile(ctx, mb, archiveName, offsetInArchive, {}) {}
-BitcodeFile::BitcodeFile(MemoryBufferRef mb, StringRef archiveName,
- uint64_t offsetInArchive,
+BitcodeFile::BitcodeFile(COFFLinkerContext &ctx, MemoryBufferRef mb,
+ StringRef archiveName, uint64_t offsetInArchive,
std::vector<Symbol *> &&symbols)
- : InputFile(BitcodeKind, mb), symbols(std::move(symbols)) {
+ : InputFile(ctx, BitcodeKind, mb), symbols(std::move(symbols)) {
std::string path = mb.getBufferIdentifier().str();
if (config->thinLTOIndexOnly)
path = replaceThinLTOSuffix(mb.getBufferIdentifier());
@@ -1069,7 +1067,7 @@ void BitcodeFile::parse() {
for (size_t i = 0; i != obj->getComdatTable().size(); ++i)
// FIXME: Check nodeduplicate
comdat[i] =
- symtab->addComdat(this, saver.save(obj->getComdatTable()[i].first));
+ ctx.symtab.addComdat(this, saver.save(obj->getComdatTable()[i].first));
for (const lto::InputFile::Symbol &objSym : obj->symbols()) {
StringRef symName = saver.save(objSym.getName());
int comdatIndex = objSym.getComdatIndex();
@@ -1080,27 +1078,27 @@ void BitcodeFile::parse() {
else
fakeSC = <oDataSectionChunk.chunk;
if (objSym.isUndefined()) {
- sym = symtab->addUndefined(symName, this, false);
+ sym = ctx.symtab.addUndefined(symName, this, false);
} else if (objSym.isCommon()) {
- sym = symtab->addCommon(this, symName, objSym.getCommonSize());
+ sym = ctx.symtab.addCommon(this, symName, objSym.getCommonSize());
} else if (objSym.isWeak() && objSym.isIndirect()) {
// Weak external.
- sym = symtab->addUndefined(symName, this, true);
+ sym = ctx.symtab.addUndefined(symName, this, true);
std::string fallback = std::string(objSym.getCOFFWeakExternalFallback());
- Symbol *alias = symtab->addUndefined(saver.save(fallback));
- checkAndSetWeakAlias(symtab, this, sym, alias);
+ Symbol *alias = ctx.symtab.addUndefined(saver.save(fallback));
+ checkAndSetWeakAlias(&ctx.symtab, this, sym, alias);
} else if (comdatIndex != -1) {
if (symName == obj->getComdatTable()[comdatIndex].first) {
sym = comdat[comdatIndex].first;
if (cast<DefinedRegular>(sym)->data == nullptr)
cast<DefinedRegular>(sym)->data = &fakeSC->repl;
} else if (comdat[comdatIndex].second) {
- sym = symtab->addRegular(this, symName, nullptr, fakeSC);
+ sym = ctx.symtab.addRegular(this, symName, nullptr, fakeSC);
} else {
- sym = symtab->addUndefined(symName, this, false);
+ sym = ctx.symtab.addUndefined(symName, this, false);
}
} else {
- sym = symtab->addRegular(this, symName, nullptr, fakeSC);
+ sym = ctx.symtab.addRegular(this, symName, nullptr, fakeSC);
}
symbols.push_back(sym);
if (objSym.isUsed())
@@ -1185,9 +1183,9 @@ void DLLFile::parse() {
}
StringRef impName = saver.save("__imp_" + symbolName);
- symtab->addLazyDLLSymbol(this, s, impName);
+ ctx.symtab.addLazyDLLSymbol(this, s, impName);
if (code)
- symtab->addLazyDLLSymbol(this, s, symbolName);
+ ctx.symtab.addLazyDLLSymbol(this, s, symbolName);
}
}
@@ -1219,6 +1217,6 @@ void DLLFile::makeImport(DLLFile::Symbol *s) {
p += s->symbolName.size() + 1;
memcpy(p, s->dllName.data(), s->dllName.size());
MemoryBufferRef mbref = MemoryBufferRef(StringRef(buf, size), s->dllName);
- ImportFile *impFile = make<ImportFile>(mbref);
- symtab->addFile(impFile);
+ ImportFile *impFile = make<ImportFile>(ctx, mbref);
+ ctx.symtab.addFile(impFile);
}
diff --git a/lld/COFF/InputFiles.h b/lld/COFF/InputFiles.h
index 47b5c588c5af7..801c668d3ae45 100644
--- a/lld/COFF/InputFiles.h
+++ b/lld/COFF/InputFiles.h
@@ -38,6 +38,7 @@ namespace lld {
class DWARFCache;
namespace coff {
+class COFFLinkerContext;
std::vector<MemoryBufferRef> getArchiveMembers(llvm::object::Archive *file);
@@ -91,8 +92,11 @@ class InputFile {
// Returns .drectve section contents if exist.
StringRef getDirectives() { return directives; }
+ COFFLinkerContext &ctx;
+
protected:
- InputFile(Kind k, MemoryBufferRef m) : mb(m), fileKind(k) {}
+ InputFile(COFFLinkerContext &c, Kind k, MemoryBufferRef m)
+ : mb(m), ctx(c), fileKind(k) {}
StringRef directives;
@@ -103,7 +107,7 @@ class InputFile {
// .lib or .a file.
class ArchiveFile : public InputFile {
public:
- explicit ArchiveFile(MemoryBufferRef m);
+ explicit ArchiveFile(COFFLinkerContext &ctx, MemoryBufferRef m);
static bool classof(const InputFile *f) { return f->kind() == ArchiveKind; }
void parse() override;
@@ -120,7 +124,8 @@ class ArchiveFile : public InputFile {
// .obj or .o file between -start-lib and -end-lib.
class LazyObjFile : public InputFile {
public:
- explicit LazyObjFile(MemoryBufferRef m) : InputFile(LazyObjectKind, m) {}
+ explicit LazyObjFile(COFFLinkerContext &ctx, MemoryBufferRef m)
+ : InputFile(ctx, LazyObjectKind, m) {}
static bool classof(const InputFile *f) {
return f->kind() == LazyObjectKind;
}
@@ -136,9 +141,11 @@ class LazyObjFile : public InputFile {
// .obj or .o file. This may be a member of an archive file.
class ObjFile : public InputFile {
public:
- explicit ObjFile(MemoryBufferRef m) : InputFile(ObjectKind, m) {}
- explicit ObjFile(MemoryBufferRef m, std::vector<Symbol *> &&symbols)
- : InputFile(ObjectKind, m), symbols(std::move(symbols)) {}
+ explicit ObjFile(COFFLinkerContext &ctx, MemoryBufferRef m)
+ : InputFile(ctx, ObjectKind, m) {}
+ explicit ObjFile(COFFLinkerContext &ctx, MemoryBufferRef m,
+ std::vector<Symbol *> &&symbols)
+ : InputFile(ctx, ObjectKind, m), symbols(std::move(symbols)) {}
static bool classof(const InputFile *f) { return f->kind() == ObjectKind; }
void parse() override;
MachineTypes getMachineType() override;
@@ -175,8 +182,6 @@ class ObjFile : public InputFile {
bool isResourceObjFile() const { return !resourceChunks.empty(); }
- static std::vector<ObjFile *> instances;
-
// Flags in the absolute @feat.00 symbol if it is present. These usually
// indicate if an object was compiled with certain security features enabled
// like stack guard, safeseh, /guard:cf, or other things.
@@ -228,6 +233,8 @@ class ObjFile : public InputFile {
return getSection(sym.getSectionNumber());
}
+ void enqueuePdbFile(StringRef path, ObjFile *fromFile);
+
void initializeChunks();
void initializeSymbols();
void initializeFlags();
@@ -318,16 +325,13 @@ class ObjFile : public InputFile {
// stream.
class PDBInputFile : public InputFile {
public:
- explicit PDBInputFile(MemoryBufferRef m);
+ explicit PDBInputFile(COFFLinkerContext &ctx, MemoryBufferRef m);
~PDBInputFile();
static bool classof(const InputFile *f) { return f->kind() == PDBKind; }
void parse() override;
- static void enqueue(StringRef path, ObjFile *fromFile);
-
- static PDBInputFile *findFromRecordPath(StringRef path, ObjFile *fromFile);
-
- static std::map<std::string, PDBInputFile *> instances;
+ static PDBInputFile *findFromRecordPath(const COFFLinkerContext &ctx,
+ StringRef path, ObjFile *fromFile);
// Record possible errors while opening the PDB file
llvm::Optional<Error> loadErr;
@@ -344,12 +348,11 @@ class PDBInputFile : public InputFile {
// for details about the format.
class ImportFile : public InputFile {
public:
- explicit ImportFile(MemoryBufferRef m) : InputFile(ImportKind, m) {}
+ explicit ImportFile(COFFLinkerContext &ctx, MemoryBufferRef m)
+ : InputFile(ctx, ImportKind, m) {}
static bool classof(const InputFile *f) { return f->kind() == ImportKind; }
- static std::vector<ImportFile *> instances;
-
Symbol *impSym = nullptr;
Symbol *thunkSym = nullptr;
std::string dllName;
@@ -377,16 +380,15 @@ class ImportFile : public InputFile {
// Used for LTO.
class BitcodeFile : public InputFile {
public:
- BitcodeFile(MemoryBufferRef mb, StringRef archiveName,
+ BitcodeFile(COFFLinkerContext &ctx, MemoryBufferRef mb, StringRef archiveName,
uint64_t offsetInArchive);
- explicit BitcodeFile(MemoryBufferRef m, StringRef archiveName,
- uint64_t offsetInArchive,
+ explicit BitcodeFile(COFFLinkerContext &ctx, MemoryBufferRef m,
+ StringRef archiveName, uint64_t offsetInArchive,
std::vector<Symbol *> &&symbols);
~BitcodeFile();
static bool classof(const InputFile *f) { return f->kind() == BitcodeKind; }
ArrayRef<Symbol *> getSymbols() { return symbols; }
MachineTypes getMachineType() override;
- static std::vector<BitcodeFile *> instances;
std::unique_ptr<llvm::lto::InputFile> obj;
private:
@@ -398,7 +400,8 @@ class BitcodeFile : public InputFile {
// .dll file. MinGW only.
class DLLFile : public InputFile {
public:
- explicit DLLFile(MemoryBufferRef m) : InputFile(DLLKind, m) {}
+ explicit DLLFile(COFFLinkerContext &ctx, MemoryBufferRef m)
+ : InputFile(ctx, DLLKind, m) {}
static bool classof(const InputFile *f) { return f->kind() == DLLKind; }
void parse() override;
MachineTypes getMachineType() override;
diff --git a/lld/COFF/LLDMapFile.cpp b/lld/COFF/LLDMapFile.cpp
index 79df33a3535fd..639b186dbb6f9 100644
--- a/lld/COFF/LLDMapFile.cpp
+++ b/lld/COFF/LLDMapFile.cpp
@@ -19,6 +19,7 @@
//===----------------------------------------------------------------------===//
#include "LLDMapFile.h"
+#include "COFFLinkerContext.h"
#include "SymbolTable.h"
#include "Symbols.h"
#include "Writer.h"
@@ -44,9 +45,9 @@ static void writeHeader(raw_ostream &os, uint64_t addr, uint64_t size,
}
// Returns a list of all symbols that we want to print out.
-static std::vector<DefinedRegular *> getSymbols() {
+static std::vector<DefinedRegular *> getSymbols(const COFFLinkerContext &ctx) {
std::vector<DefinedRegular *> v;
- for (ObjFile *file : ObjFile::instances)
+ for (ObjFile *file : ctx.objFileInstances)
for (Symbol *b : file->getSymbols())
if (auto *sym = dyn_cast_or_null<DefinedRegular>(b))
if (sym && !sym->getCOFFSymbol().isSectionDefinition())
@@ -86,7 +87,7 @@ getSymbolStrings(ArrayRef<DefinedRegular *> syms) {
return ret;
}
-void lld::coff::writeLLDMapFile(ArrayRef<OutputSection *> outputSections) {
+void lld::coff::writeLLDMapFile(const COFFLinkerContext &ctx) {
if (config->lldmapFile.empty())
return;
@@ -96,7 +97,7 @@ void lld::coff::writeLLDMapFile(ArrayRef<OutputSection *> outputSections) {
fatal("cannot open " + config->lldmapFile + ": " + ec.message());
// Collect symbol info that we want to print out.
- std::vector<DefinedRegular *> syms = getSymbols();
+ std::vector<DefinedRegular *> syms = getSymbols(ctx);
SymbolMapTy sectionSyms = getSectionSyms(syms);
DenseMap<DefinedRegular *, std::string> symStr = getSymbolStrings(syms);
@@ -104,7 +105,7 @@ void lld::coff::writeLLDMapFile(ArrayRef<OutputSection *> outputSections) {
os << "Address Size Align Out In Symbol\n";
// Print out file contents.
- for (OutputSection *sec : outputSections) {
+ for (OutputSection *sec : ctx.outputSections) {
writeHeader(os, sec->getRVA(), sec->getVirtualSize(), /*align=*/pageSize);
os << sec->name << '\n';
diff --git a/lld/COFF/LLDMapFile.h b/lld/COFF/LLDMapFile.h
index b731293a8625d..72e999a61900a 100644
--- a/lld/COFF/LLDMapFile.h
+++ b/lld/COFF/LLDMapFile.h
@@ -9,12 +9,10 @@
#ifndef LLD_COFF_LLDMAPFILE_H
#define LLD_COFF_LLDMAPFILE_H
-#include "llvm/ADT/ArrayRef.h"
-
namespace lld {
namespace coff {
-class OutputSection;
-void writeLLDMapFile(llvm::ArrayRef<OutputSection *> outputSections);
+class COFFLinkerContext;
+void writeLLDMapFile(const COFFLinkerContext &ctx);
}
}
diff --git a/lld/COFF/LTO.cpp b/lld/COFF/LTO.cpp
index 6e38f53f21362..ce9c4fd0d51b2 100644
--- a/lld/COFF/LTO.cpp
+++ b/lld/COFF/LTO.cpp
@@ -156,7 +156,7 @@ void BitcodeCompiler::add(BitcodeFile &f) {
// Merge all the bitcode files we have seen, codegen the result
// and return the resulting objects.
-std::vector<InputFile *> BitcodeCompiler::compile() {
+std::vector<InputFile *> BitcodeCompiler::compile(COFFLinkerContext &ctx) {
unsigned maxTasks = ltoObj->getMaxTasks();
buf.resize(maxTasks);
files.resize(maxTasks);
@@ -224,7 +224,7 @@ std::vector<InputFile *> BitcodeCompiler::compile() {
if (config->saveTemps)
saveBuffer(buf[i], ltoObjName);
- ret.push_back(make<ObjFile>(MemoryBufferRef(objBuf, ltoObjName)));
+ ret.push_back(make<ObjFile>(ctx, MemoryBufferRef(objBuf, ltoObjName)));
}
return ret;
diff --git a/lld/COFF/LTO.h b/lld/COFF/LTO.h
index a2b321df7901b..b05befc7146aa 100644
--- a/lld/COFF/LTO.h
+++ b/lld/COFF/LTO.h
@@ -38,6 +38,7 @@ namespace coff {
class BitcodeFile;
class InputFile;
+class COFFLinkerContext;
class BitcodeCompiler {
public:
@@ -45,7 +46,7 @@ class BitcodeCompiler {
~BitcodeCompiler();
void add(BitcodeFile &f);
- std::vector<InputFile *> compile();
+ std::vector<InputFile *> compile(COFFLinkerContext &ctx);
private:
std::unique_ptr<llvm::lto::LTO> ltoObj;
diff --git a/lld/COFF/MapFile.cpp b/lld/COFF/MapFile.cpp
index 41e169ef56e22..d7b7de43f3f64 100644
--- a/lld/COFF/MapFile.cpp
+++ b/lld/COFF/MapFile.cpp
@@ -28,6 +28,7 @@
//===----------------------------------------------------------------------===//
#include "MapFile.h"
+#include "COFFLinkerContext.h"
#include "SymbolTable.h"
#include "Symbols.h"
#include "Writer.h"
@@ -42,11 +43,6 @@ using namespace llvm::object;
using namespace lld;
using namespace lld::coff;
-static Timer totalMapTimer("MAP emission (Cumulative)", Timer::root());
-static Timer symbolGatherTimer("Gather symbols", totalMapTimer);
-static Timer symbolStringsTimer("Build symbol strings", totalMapTimer);
-static Timer writeTimer("Write to file", totalMapTimer);
-
// Print out the first two columns of a line.
static void writeHeader(raw_ostream &os, uint32_t sec, uint64_t addr) {
os << format(" %04x:%08llx", sec, addr);
@@ -99,9 +95,10 @@ static void sortUniqueSymbols(std::vector<Defined *> &syms) {
// Returns the lists of all symbols that we want to print out.
static void getSymbols(std::vector<Defined *> &syms,
- std::vector<Defined *> &staticSyms) {
+ std::vector<Defined *> &staticSyms,
+ const COFFLinkerContext &ctx) {
- for (ObjFile *file : ObjFile::instances)
+ for (ObjFile *file : ctx.objFileInstances)
for (Symbol *b : file->getSymbols()) {
if (!b || !b->isLive())
continue;
@@ -119,7 +116,7 @@ static void getSymbols(std::vector<Defined *> &syms,
}
}
- for (ImportFile *file : ImportFile::instances) {
+ for (ImportFile *file : ctx.importFileInstances) {
if (!file->live)
continue;
@@ -142,7 +139,7 @@ static void getSymbols(std::vector<Defined *> &syms,
// Construct a map from symbols to their stringified representations.
static DenseMap<Defined *, std::string>
-getSymbolStrings(ArrayRef<Defined *> syms) {
+getSymbolStrings(const COFFLinkerContext &ctx, ArrayRef<Defined *> syms) {
std::vector<std::string> str(syms.size());
parallelForEachN((size_t)0, syms.size(), [&](size_t i) {
raw_string_ostream os(str[i]);
@@ -161,7 +158,7 @@ getSymbolStrings(ArrayRef<Defined *> syms) {
fileDescr = "<common>";
} else if (Chunk *chunk = sym->getChunk()) {
address = sym->getRVA();
- if (OutputSection *sec = chunk->getOutputSection())
+ if (OutputSection *sec = ctx.getOutputSection(chunk))
address -= sec->header.VirtualAddress;
sectionIdx = chunk->getOutputSectionIdx();
@@ -201,7 +198,7 @@ getSymbolStrings(ArrayRef<Defined *> syms) {
return ret;
}
-void lld::coff::writeMapFile(ArrayRef<OutputSection *> outputSections) {
+void lld::coff::writeMapFile(COFFLinkerContext &ctx) {
if (config->mapFile.empty())
return;
@@ -210,21 +207,22 @@ void lld::coff::writeMapFile(ArrayRef<OutputSection *> outputSections) {
if (ec)
fatal("cannot open " + config->mapFile + ": " + ec.message());
- ScopedTimer t1(totalMapTimer);
+ ScopedTimer t1(ctx.totalMapTimer);
// Collect symbol info that we want to print out.
- ScopedTimer t2(symbolGatherTimer);
+ ScopedTimer t2(ctx.symbolGatherTimer);
std::vector<Defined *> syms;
std::vector<Defined *> staticSyms;
- getSymbols(syms, staticSyms);
+ getSymbols(syms, staticSyms, ctx);
t2.stop();
- ScopedTimer t3(symbolStringsTimer);
- DenseMap<Defined *, std::string> symStr = getSymbolStrings(syms);
- DenseMap<Defined *, std::string> staticSymStr = getSymbolStrings(staticSyms);
+ ScopedTimer t3(ctx.symbolStringsTimer);
+ DenseMap<Defined *, std::string> symStr = getSymbolStrings(ctx, syms);
+ DenseMap<Defined *, std::string> staticSymStr =
+ getSymbolStrings(ctx, staticSyms);
t3.stop();
- ScopedTimer t4(writeTimer);
+ ScopedTimer t4(ctx.writeTimer);
SmallString<128> AppName = sys::path::filename(config->outputFile);
sys::path::replace_extension(AppName, "");
@@ -248,7 +246,7 @@ void lld::coff::writeMapFile(ArrayRef<OutputSection *> outputSections) {
// Print out section table.
os << " Start Length Name Class\n";
- for (OutputSection *sec : outputSections) {
+ for (OutputSection *sec : ctx.outputSections) {
// Merge display of chunks with same sectionName
std::vector<std::pair<SectionChunk *, SectionChunk *>> ChunkRanges;
for (Chunk *c : sec->chunks) {
@@ -303,7 +301,7 @@ void lld::coff::writeMapFile(ArrayRef<OutputSection *> outputSections) {
Chunk *chunk = entry->getChunk();
entrySecIndex = chunk->getOutputSectionIdx();
entryAddress =
- entry->getRVA() - chunk->getOutputSection()->header.VirtualAddress;
+ entry->getRVA() - ctx.getOutputSection(chunk)->header.VirtualAddress;
}
}
os << " entry point at ";
diff --git a/lld/COFF/MapFile.h b/lld/COFF/MapFile.h
index 2bf01bd072856..d4572332b8b82 100644
--- a/lld/COFF/MapFile.h
+++ b/lld/COFF/MapFile.h
@@ -9,12 +9,10 @@
#ifndef LLD_COFF_MAPFILE_H
#define LLD_COFF_MAPFILE_H
-#include "llvm/ADT/ArrayRef.h"
-
namespace lld {
namespace coff {
-class OutputSection;
-void writeMapFile(llvm::ArrayRef<OutputSection *> outputSections);
+class COFFLinkerContext;
+void writeMapFile(COFFLinkerContext &ctx);
}
}
diff --git a/lld/COFF/MarkLive.cpp b/lld/COFF/MarkLive.cpp
index 0afa615a1933e..f53005278e222 100644
--- a/lld/COFF/MarkLive.cpp
+++ b/lld/COFF/MarkLive.cpp
@@ -6,6 +6,7 @@
//
//===----------------------------------------------------------------------===//
+#include "COFFLinkerContext.h"
#include "Chunks.h"
#include "Symbols.h"
#include "lld/Common/Timer.h"
@@ -15,13 +16,11 @@
namespace lld {
namespace coff {
-static Timer gctimer("GC", Timer::root());
-
// Set live bit on for each reachable chunk. Unmarked (unreachable)
// COMDAT chunks will be ignored by Writer, so they will be excluded
// from the final output.
-void markLive(ArrayRef<Chunk *> chunks) {
- ScopedTimer t(gctimer);
+void markLive(COFFLinkerContext &ctx) {
+ ScopedTimer t(ctx.gcTimer);
// We build up a worklist of sections which have been marked as live. We only
// push into the worklist when we discover an unmarked section, and we mark
@@ -31,7 +30,7 @@ void markLive(ArrayRef<Chunk *> chunks) {
// COMDAT section chunks are dead by default. Add non-COMDAT chunks. Do not
// traverse DWARF sections. They are live, but they should not keep other
// sections alive.
- for (Chunk *c : chunks)
+ for (Chunk *c : ctx.symtab.getChunks())
if (auto *sc = dyn_cast<SectionChunk>(c))
if (sc->live && !sc->isDWARF())
worklist.push_back(sc);
@@ -70,6 +69,5 @@ void markLive(ArrayRef<Chunk *> chunks) {
enqueue(&c);
}
}
-
}
}
diff --git a/lld/COFF/MarkLive.h b/lld/COFF/MarkLive.h
index e4e4c31c7c796..6f211487236cc 100644
--- a/lld/COFF/MarkLive.h
+++ b/lld/COFF/MarkLive.h
@@ -10,14 +10,13 @@
#define LLD_COFF_MARKLIVE_H
#include "lld/Common/LLVM.h"
-#include "llvm/ADT/ArrayRef.h"
namespace lld {
namespace coff {
-class Chunk;
+class COFFLinkerContext;
-void markLive(ArrayRef<Chunk *> chunks);
+void markLive(COFFLinkerContext &ctx);
} // namespace coff
} // namespace lld
diff --git a/lld/COFF/MinGW.cpp b/lld/COFF/MinGW.cpp
index 7c1891e67d45e..148ebe5eea66d 100644
--- a/lld/COFF/MinGW.cpp
+++ b/lld/COFF/MinGW.cpp
@@ -7,6 +7,7 @@
//===----------------------------------------------------------------------===//
#include "MinGW.h"
+#include "COFFLinkerContext.h"
#include "Driver.h"
#include "InputFiles.h"
#include "SymbolTable.h"
@@ -122,7 +123,8 @@ void AutoExporter::addWholeArchive(StringRef path) {
excludeLibs.erase(libName);
}
-bool AutoExporter::shouldExport(Defined *sym) const {
+bool AutoExporter::shouldExport(const COFFLinkerContext &ctx,
+ Defined *sym) const {
if (!sym || !sym->getChunk())
return false;
@@ -141,7 +143,7 @@ bool AutoExporter::shouldExport(Defined *sym) const {
return false;
// If a corresponding __imp_ symbol exists and is defined, don't export it.
- if (symtab->find(("__imp_" + sym->getName()).str()))
+ if (ctx.symtab.find(("__imp_" + sym->getName()).str()))
return false;
// Check that file is non-null before dereferencing it, symbols not
@@ -192,7 +194,7 @@ static StringRef mangle(Twine sym) {
// like they are not being used at all, so we explicitly set some flags so
// that LTO won't eliminate them.
std::vector<WrappedSymbol>
-lld::coff::addWrappedSymbols(opt::InputArgList &args) {
+lld::coff::addWrappedSymbols(COFFLinkerContext &ctx, opt::InputArgList &args) {
std::vector<WrappedSymbol> v;
DenseSet<StringRef> seen;
@@ -201,18 +203,18 @@ lld::coff::addWrappedSymbols(opt::InputArgList &args) {
if (!seen.insert(name).second)
continue;
- Symbol *sym = symtab->findUnderscore(name);
+ Symbol *sym = ctx.symtab.findUnderscore(name);
if (!sym)
continue;
- Symbol *real = symtab->addUndefined(mangle("__real_" + name));
- Symbol *wrap = symtab->addUndefined(mangle("__wrap_" + name));
+ Symbol *real = ctx.symtab.addUndefined(mangle("__real_" + name));
+ Symbol *wrap = ctx.symtab.addUndefined(mangle("__wrap_" + name));
v.push_back({sym, real, wrap});
// These symbols may seem undefined initially, but don't bail out
- // at symtab->reportUnresolvable() due to them, but let wrapSymbols
+ // at symtab.reportUnresolvable() due to them, but let wrapSymbols
// below sort things out before checking finally with
- // symtab->resolveRemainingUndefines().
+ // symtab.resolveRemainingUndefines().
sym->deferUndefined = true;
real->deferUndefined = true;
// We want to tell LTO not to inline symbols to be overwritten
@@ -233,13 +235,14 @@ lld::coff::addWrappedSymbols(opt::InputArgList &args) {
// When this function is executed, only InputFiles and symbol table
// contain pointers to symbol objects. We visit them to replace pointers,
// so that wrapped symbols are swapped as instructed by the command line.
-void lld::coff::wrapSymbols(ArrayRef<WrappedSymbol> wrapped) {
+void lld::coff::wrapSymbols(COFFLinkerContext &ctx,
+ ArrayRef<WrappedSymbol> wrapped) {
DenseMap<Symbol *, Symbol *> map;
for (const WrappedSymbol &w : wrapped) {
map[w.sym] = w.wrap;
map[w.real] = w.sym;
if (Defined *d = dyn_cast<Defined>(w.wrap)) {
- Symbol *imp = symtab->find(("__imp_" + w.sym->getName()).str());
+ Symbol *imp = ctx.symtab.find(("__imp_" + w.sym->getName()).str());
// Create a new defined local import for the wrap symbol. If
// no imp prefixed symbol existed, there's no need for it.
// (We can't easily distinguish whether any object file actually
@@ -247,14 +250,14 @@ void lld::coff::wrapSymbols(ArrayRef<WrappedSymbol> wrapped) {
if (imp) {
DefinedLocalImport *wrapimp = make<DefinedLocalImport>(
saver.save("__imp_" + w.wrap->getName()), d);
- symtab->localImportChunks.push_back(wrapimp->getChunk());
+ ctx.symtab.localImportChunks.push_back(wrapimp->getChunk());
map[imp] = wrapimp;
}
}
}
// Update pointers in input files.
- parallelForEach(ObjFile::instances, [&](ObjFile *file) {
+ parallelForEach(ctx.objFileInstances, [&](ObjFile *file) {
MutableArrayRef<Symbol *> syms = file->getMutableSymbols();
for (size_t i = 0, e = syms.size(); i != e; ++i)
if (Symbol *s = map.lookup(syms[i]))
diff --git a/lld/COFF/MinGW.h b/lld/COFF/MinGW.h
index 2f2bd119c33d2..8f9343784fa07 100644
--- a/lld/COFF/MinGW.h
+++ b/lld/COFF/MinGW.h
@@ -19,6 +19,7 @@
namespace lld {
namespace coff {
+class COFFLinkerContext;
// Logic for deciding what symbols to export, when exporting all
// symbols for MinGW.
@@ -34,7 +35,7 @@ class AutoExporter {
llvm::StringSet<> excludeLibs;
llvm::StringSet<> excludeObjects;
- bool shouldExport(Defined *sym) const;
+ bool shouldExport(const COFFLinkerContext &ctx, Defined *sym) const;
};
void writeDefFile(StringRef name);
@@ -53,9 +54,10 @@ struct WrappedSymbol {
Symbol *wrap;
};
-std::vector<WrappedSymbol> addWrappedSymbols(llvm::opt::InputArgList &args);
+std::vector<WrappedSymbol> addWrappedSymbols(COFFLinkerContext &ctx,
+ llvm::opt::InputArgList &args);
-void wrapSymbols(ArrayRef<WrappedSymbol> wrapped);
+void wrapSymbols(COFFLinkerContext &ctx, ArrayRef<WrappedSymbol> wrapped);
} // namespace coff
} // namespace lld
diff --git a/lld/COFF/PDB.cpp b/lld/COFF/PDB.cpp
index 189bf6038c7d3..73feddaa202d8 100644
--- a/lld/COFF/PDB.cpp
+++ b/lld/COFF/PDB.cpp
@@ -7,6 +7,7 @@
//===----------------------------------------------------------------------===//
#include "PDB.h"
+#include "COFFLinkerContext.h"
#include "Chunks.h"
#include "Config.h"
#include "DebugTypes.h"
@@ -66,16 +67,6 @@ using llvm::pdb::StringTableFixup;
static ExitOnError exitOnErr;
-static Timer totalPdbLinkTimer("PDB Emission (Cumulative)", Timer::root());
-static Timer addObjectsTimer("Add Objects", totalPdbLinkTimer);
-Timer lld::coff::loadGHashTimer("Global Type Hashing", addObjectsTimer);
-Timer lld::coff::mergeGHashTimer("GHash Type Merging", addObjectsTimer);
-static Timer typeMergingTimer("Type Merging", addObjectsTimer);
-static Timer symbolMergingTimer("Symbol Merging", addObjectsTimer);
-static Timer publicsLayoutTimer("Publics Stream Layout", totalPdbLinkTimer);
-static Timer tpiStreamLayoutTimer("TPI Stream Layout", totalPdbLinkTimer);
-static Timer diskCommitTimer("Commit to Disk", totalPdbLinkTimer);
-
namespace {
class DebugSHandler;
@@ -83,8 +74,8 @@ class PDBLinker {
friend DebugSHandler;
public:
- PDBLinker(SymbolTable *symtab)
- : symtab(symtab), builder(bAlloc), tMerger(bAlloc) {
+ PDBLinker(COFFLinkerContext &ctx)
+ : builder(bAlloc), tMerger(ctx, bAlloc), ctx(ctx) {
// This isn't strictly necessary, but link.exe usually puts an empty string
// as the first "valid" string in the string table, so we do the same in
// order to maintain as much byte-for-byte compatibility as possible.
@@ -107,7 +98,7 @@ class PDBLinker {
void addPublicsToPDB();
/// Link info for each import file in the symbol table into the PDB.
- void addImportFilesToPDB(ArrayRef<OutputSection *> outputSections);
+ void addImportFilesToPDB();
void createModuleDBI(ObjFile *file);
@@ -144,8 +135,7 @@ class PDBLinker {
std::vector<uint8_t> &storage);
/// Add the section map and section contributions to the PDB.
- void addSections(ArrayRef<OutputSection *> outputSections,
- ArrayRef<uint8_t> sectionTable);
+ void addSections(ArrayRef<uint8_t> sectionTable);
/// Write the PDB to disk and store the Guid generated for it in *Guid.
void commit(codeview::GUID *guid);
@@ -154,12 +144,13 @@ class PDBLinker {
void printStats();
private:
- SymbolTable *symtab;
pdb::PDBFileBuilder builder;
TypeMerger tMerger;
+ COFFLinkerContext &ctx;
+
/// PDBs use a single global string table for filenames in the file checksum
/// table.
DebugStringTableSubsection pdbStrTab;
@@ -299,11 +290,12 @@ static void addTypeInfo(pdb::TpiStreamBuilder &tpiBuilder,
});
}
-static void addGHashTypeInfo(pdb::PDBFileBuilder &builder) {
+static void addGHashTypeInfo(COFFLinkerContext &ctx,
+ pdb::PDBFileBuilder &builder) {
// Start the TPI or IPI stream header.
builder.getTpiBuilder().setVersionHeader(pdb::PdbTpiV80);
builder.getIpiBuilder().setVersionHeader(pdb::PdbTpiV80);
- for_each(TpiSource::instances, [&](TpiSource *source) {
+ for_each(ctx.tpiSourceList, [&](TpiSource *source) {
builder.getTpiBuilder().addTypeRecords(source->mergedTpi.recs,
source->mergedTpi.recSizes,
source->mergedTpi.recHashes);
@@ -719,8 +711,9 @@ Error PDBLinker::commitSymbolsForObject(void *ctx, void *obj,
static_cast<ObjFile *>(obj), writer);
}
-static pdb::SectionContrib createSectionContrib(const Chunk *c, uint32_t modi) {
- OutputSection *os = c ? c->getOutputSection() : nullptr;
+static pdb::SectionContrib createSectionContrib(COFFLinkerContext &ctx,
+ const Chunk *c, uint32_t modi) {
+ OutputSection *os = c ? ctx.getOutputSection(c) : nullptr;
pdb::SectionContrib sc;
memset(&sc, 0, sizeof(sc));
sc.ISect = os ? os->sectionIndex : llvm::pdb::kInvalidStreamIndex;
@@ -1023,7 +1016,7 @@ void PDBLinker::addDebugSymbols(TpiSource *source) {
if (!source->file)
return;
- ScopedTimer t(symbolMergingTimer);
+ ScopedTimer t(ctx.symbolMergingTimer);
pdb::DbiStreamBuilder &dbiBuilder = builder.getDbiBuilder();
DebugSHandler dsh(*this, *source->file, source);
// Now do all live .debug$S and .debug$F sections.
@@ -1082,7 +1075,7 @@ void PDBLinker::createModuleDBI(ObjFile *file) {
auto *secChunk = dyn_cast<SectionChunk>(c);
if (!secChunk || !secChunk->live)
continue;
- pdb::SectionContrib sc = createSectionContrib(secChunk, modi);
+ pdb::SectionContrib sc = createSectionContrib(ctx, secChunk, modi);
file->moduleDBI->setFirstSectionContrib(sc);
break;
}
@@ -1095,7 +1088,7 @@ void PDBLinker::addDebug(TpiSource *source) {
// indices to PDB type and item indices. If we are using ghashes, types have
// already been merged.
if (!config->debugGHashes) {
- ScopedTimer t(typeMergingTimer);
+ ScopedTimer t(ctx.typeMergingTimer);
if (Error e = source->mergeDebugT(&tMerger)) {
// If type merging failed, ignore the symbols.
warnUnusable(source->file, std::move(e));
@@ -1113,7 +1106,7 @@ void PDBLinker::addDebug(TpiSource *source) {
addDebugSymbols(source);
}
-static pdb::BulkPublic createPublic(Defined *def) {
+static pdb::BulkPublic createPublic(COFFLinkerContext &ctx, Defined *def) {
pdb::BulkPublic pub;
pub.Name = def->getName().data();
pub.NameLen = def->getName().size();
@@ -1127,7 +1120,7 @@ static pdb::BulkPublic createPublic(Defined *def) {
}
pub.setFlags(flags);
- OutputSection *os = def->getChunk()->getOutputSection();
+ OutputSection *os = ctx.getOutputSection(def->getChunk());
assert(os && "all publics should be in final image");
pub.Offset = def->getRVA() - os->getRVA();
pub.Segment = os->sectionIndex;
@@ -1137,32 +1130,31 @@ static pdb::BulkPublic createPublic(Defined *def) {
// Add all object files to the PDB. Merge .debug$T sections into IpiData and
// TpiData.
void PDBLinker::addObjectsToPDB() {
- ScopedTimer t1(addObjectsTimer);
+ ScopedTimer t1(ctx.addObjectsTimer);
// Create module descriptors
- for_each(ObjFile::instances, [&](ObjFile *obj) { createModuleDBI(obj); });
+ for_each(ctx.objFileInstances, [&](ObjFile *obj) { createModuleDBI(obj); });
// Reorder dependency type sources to come first.
- TpiSource::sortDependencies();
+ tMerger.sortDependencies();
// Merge type information from input files using global type hashing.
if (config->debugGHashes)
tMerger.mergeTypesWithGHash();
// Merge dependencies and then regular objects.
- for_each(TpiSource::dependencySources,
- [&](TpiSource *source) { addDebug(source); });
- for_each(TpiSource::objectSources,
+ for_each(tMerger.dependencySources,
[&](TpiSource *source) { addDebug(source); });
+ for_each(tMerger.objectSources, [&](TpiSource *source) { addDebug(source); });
builder.getStringTableBuilder().setStrings(pdbStrTab);
t1.stop();
// Construct TPI and IPI stream contents.
- ScopedTimer t2(tpiStreamLayoutTimer);
+ ScopedTimer t2(ctx.tpiStreamLayoutTimer);
// Collect all the merged types.
if (config->debugGHashes) {
- addGHashTypeInfo(builder);
+ addGHashTypeInfo(ctx, builder);
} else {
addTypeInfo(builder.getTpiBuilder(), tMerger.getTypeTable());
addTypeInfo(builder.getIpiBuilder(), tMerger.getIDTable());
@@ -1170,7 +1162,7 @@ void PDBLinker::addObjectsToPDB() {
t2.stop();
if (config->showSummary) {
- for_each(TpiSource::instances, [&](TpiSource *source) {
+ for_each(ctx.tpiSourceList, [&](TpiSource *source) {
nbTypeRecords += source->nbTypeRecords;
nbTypeRecordsBytes += source->nbTypeRecordsBytes;
});
@@ -1178,11 +1170,11 @@ void PDBLinker::addObjectsToPDB() {
}
void PDBLinker::addPublicsToPDB() {
- ScopedTimer t3(publicsLayoutTimer);
+ ScopedTimer t3(ctx.publicsLayoutTimer);
// Compute the public symbols.
auto &gsiBuilder = builder.getGsiBuilder();
std::vector<pdb::BulkPublic> publics;
- symtab->forEachSymbol([&publics](Symbol *s) {
+ ctx.symtab.forEachSymbol([&publics, this](Symbol *s) {
// Only emit external, defined, live symbols that have a chunk. Static,
// non-external symbols do not appear in the symbol table.
auto *def = dyn_cast<Defined>(s);
@@ -1203,7 +1195,7 @@ void PDBLinker::addPublicsToPDB() {
return;
}
}
- publics.push_back(createPublic(def));
+ publics.push_back(createPublic(ctx, def));
}
});
@@ -1227,10 +1219,10 @@ void PDBLinker::printStats() {
stream << format_decimal(v, 15) << " " << s << '\n';
};
- print(ObjFile::instances.size(),
+ print(ctx.objFileInstances.size(),
"Input OBJ files (expanded from all cmd-line inputs)");
- print(TpiSource::countTypeServerPDBs(), "PDB type server dependencies");
- print(TpiSource::countPrecompObjs(), "Precomp OBJ dependencies");
+ print(ctx.typeServerSourceMappings.size(), "PDB type server dependencies");
+ print(ctx.precompSourceMappings.size(), "Precomp OBJ dependencies");
print(nbTypeRecords, "Input type records");
print(nbTypeRecordsBytes, "Input type records bytes");
print(builder.getTpiBuilder().getRecordCount(), "Merged TPI records");
@@ -1483,13 +1475,13 @@ static void addLinkerModuleSectionSymbol(pdb::DbiModuleDescriptorBuilder &mod,
}
// Add all import files as modules to the PDB.
-void PDBLinker::addImportFilesToPDB(ArrayRef<OutputSection *> outputSections) {
- if (ImportFile::instances.empty())
+void PDBLinker::addImportFilesToPDB() {
+ if (ctx.importFileInstances.empty())
return;
std::map<std::string, llvm::pdb::DbiModuleDescriptorBuilder *> dllToModuleDbi;
- for (ImportFile *file : ImportFile::instances) {
+ for (ImportFile *file : ctx.importFileInstances) {
if (!file->live)
continue;
@@ -1513,7 +1505,7 @@ void PDBLinker::addImportFilesToPDB(ArrayRef<OutputSection *> outputSections) {
exitOnErr(dbiBuilder.addModuleInfo(file->dllName));
firstMod.setObjFileName(libPath);
pdb::SectionContrib sc =
- createSectionContrib(nullptr, llvm::pdb::kInvalidStreamIndex);
+ createSectionContrib(ctx, nullptr, llvm::pdb::kInvalidStreamIndex);
firstMod.setFirstSectionContrib(sc);
// The second module is where the import stream goes.
@@ -1523,7 +1515,7 @@ void PDBLinker::addImportFilesToPDB(ArrayRef<OutputSection *> outputSections) {
DefinedImportThunk *thunk = cast<DefinedImportThunk>(file->thunkSym);
Chunk *thunkChunk = thunk->getChunk();
- OutputSection *thunkOS = thunkChunk->getOutputSection();
+ OutputSection *thunkOS = ctx.getOutputSection(thunkChunk);
ObjNameSym ons(SymbolRecordKind::ObjNameSym);
Compile3Sym cs(SymbolRecordKind::Compile3Sym);
@@ -1565,28 +1557,27 @@ void PDBLinker::addImportFilesToPDB(ArrayRef<OutputSection *> outputSections) {
mod->addSymbol(newSym);
pdb::SectionContrib sc =
- createSectionContrib(thunk->getChunk(), mod->getModuleIndex());
+ createSectionContrib(ctx, thunk->getChunk(), mod->getModuleIndex());
mod->setFirstSectionContrib(sc);
}
}
// Creates a PDB file.
-void lld::coff::createPDB(SymbolTable *symtab,
- ArrayRef<OutputSection *> outputSections,
+void lld::coff::createPDB(COFFLinkerContext &ctx,
ArrayRef<uint8_t> sectionTable,
llvm::codeview::DebugInfo *buildId) {
- ScopedTimer t1(totalPdbLinkTimer);
- PDBLinker pdb(symtab);
+ ScopedTimer t1(ctx.totalPdbLinkTimer);
+ PDBLinker pdb(ctx);
pdb.initialize(buildId);
pdb.addObjectsToPDB();
- pdb.addImportFilesToPDB(outputSections);
- pdb.addSections(outputSections, sectionTable);
+ pdb.addImportFilesToPDB();
+ pdb.addSections(sectionTable);
pdb.addNatvisFiles();
pdb.addNamedStreams();
pdb.addPublicsToPDB();
- ScopedTimer t2(diskCommitTimer);
+ ScopedTimer t2(ctx.diskCommitTimer);
codeview::GUID guid;
pdb.commit(&guid);
memcpy(&buildId->PDB70.Signature, &guid, 16);
@@ -1626,8 +1617,7 @@ void PDBLinker::initialize(llvm::codeview::DebugInfo *buildId) {
dbiBuilder.setBuildNumber(14, 11);
}
-void PDBLinker::addSections(ArrayRef<OutputSection *> outputSections,
- ArrayRef<uint8_t> sectionTable) {
+void PDBLinker::addSections(ArrayRef<uint8_t> sectionTable) {
// It's not entirely clear what this is, but the * Linker * module uses it.
pdb::DbiStreamBuilder &dbiBuilder = builder.getDbiBuilder();
nativePath = config->pdbPath;
@@ -1638,11 +1628,11 @@ void PDBLinker::addSections(ArrayRef<OutputSection *> outputSections,
addCommonLinkerModuleSymbols(nativePath, linkerModule);
// Add section contributions. They must be ordered by ascending RVA.
- for (OutputSection *os : outputSections) {
+ for (OutputSection *os : ctx.outputSections) {
addLinkerModuleSectionSymbol(linkerModule, *os);
for (Chunk *c : os->chunks) {
pdb::SectionContrib sc =
- createSectionContrib(c, linkerModule.getModuleIndex());
+ createSectionContrib(ctx, c, linkerModule.getModuleIndex());
builder.getDbiBuilder().addSectionContrib(sc);
}
}
@@ -1651,7 +1641,7 @@ void PDBLinker::addSections(ArrayRef<OutputSection *> outputSections,
// to provide trampolines thunks for incremental function patching. Set this
// as "unused" because LLD doesn't support /INCREMENTAL link.
pdb::SectionContrib sc =
- createSectionContrib(nullptr, llvm::pdb::kInvalidStreamIndex);
+ createSectionContrib(ctx, nullptr, llvm::pdb::kInvalidStreamIndex);
linkerModule.setFirstSectionContrib(sc);
// Add Section Map stream.
diff --git a/lld/COFF/PDB.h b/lld/COFF/PDB.h
index 53506d40baef4..8381374dcc8a6 100644
--- a/lld/COFF/PDB.h
+++ b/lld/COFF/PDB.h
@@ -23,21 +23,15 @@ namespace lld {
class Timer;
namespace coff {
-class OutputSection;
class SectionChunk;
-class SymbolTable;
+class COFFLinkerContext;
-void createPDB(SymbolTable *symtab,
- llvm::ArrayRef<OutputSection *> outputSections,
- llvm::ArrayRef<uint8_t> sectionTable,
+void createPDB(COFFLinkerContext &ctx, llvm::ArrayRef<uint8_t> sectionTable,
llvm::codeview::DebugInfo *buildId);
llvm::Optional<std::pair<llvm::StringRef, uint32_t>>
getFileLineCodeView(const SectionChunk *c, uint32_t addr);
-extern Timer loadGHashTimer;
-extern Timer mergeGHashTimer;
-
} // namespace coff
} // namespace lld
diff --git a/lld/COFF/SymbolTable.cpp b/lld/COFF/SymbolTable.cpp
index 536f343507243..47b339b981fd6 100644
--- a/lld/COFF/SymbolTable.cpp
+++ b/lld/COFF/SymbolTable.cpp
@@ -7,6 +7,7 @@
//===----------------------------------------------------------------------===//
#include "SymbolTable.h"
+#include "COFFLinkerContext.h"
#include "Config.h"
#include "Driver.h"
#include "LTO.h"
@@ -34,10 +35,6 @@ StringRef ltrim1(StringRef s, const char *chars) {
return s;
}
-static Timer ltoTimer("LTO", Timer::root());
-
-SymbolTable *symtab;
-
void SymbolTable::addFile(InputFile *file) {
log("Reading " + toString(file));
file->parse();
@@ -52,11 +49,11 @@ void SymbolTable::addFile(InputFile *file) {
}
if (auto *f = dyn_cast<ObjFile>(file)) {
- ObjFile::instances.push_back(f);
+ ctx.objFileInstances.push_back(f);
} else if (auto *f = dyn_cast<BitcodeFile>(file)) {
- BitcodeFile::instances.push_back(f);
+ ctx.bitcodeFileInstances.push_back(f);
} else if (auto *f = dyn_cast<ImportFile>(file)) {
- ImportFile::instances.push_back(f);
+ ctx.importFileInstances.push_back(f);
}
driver->parseDirectives(file);
@@ -372,12 +369,9 @@ bool SymbolTable::handleMinGWAutomaticImport(Symbol *sym, StringRef name) {
/// defined symbol imported" diagnostic for symbols in localImports.
/// objFiles and bitcodeFiles (if not nullptr) are used to report where
/// undefined symbols are referenced.
-static void
-reportProblemSymbols(const SmallPtrSetImpl<Symbol *> &undefs,
- const DenseMap<Symbol *, Symbol *> *localImports,
- const std::vector<ObjFile *> objFiles,
- const std::vector<BitcodeFile *> *bitcodeFiles) {
-
+static void reportProblemSymbols(
+ const COFFLinkerContext &ctx, const SmallPtrSetImpl<Symbol *> &undefs,
+ const DenseMap<Symbol *, Symbol *> *localImports, bool needBitcodeFiles) {
// Return early if there is nothing to report (which should be
// the common case).
if (undefs.empty() && (!localImports || localImports->empty()))
@@ -418,11 +412,11 @@ reportProblemSymbols(const SmallPtrSetImpl<Symbol *> &undefs,
}
};
- for (ObjFile *file : objFiles)
+ for (ObjFile *file : ctx.objFileInstances)
processFile(file, file->getSymbols());
- if (bitcodeFiles)
- for (BitcodeFile *file : *bitcodeFiles)
+ if (needBitcodeFiles)
+ for (BitcodeFile *file : ctx.bitcodeFileInstances)
processFile(file, file->getSymbols());
for (const UndefinedDiag &undefDiag : undefDiags)
@@ -451,9 +445,8 @@ void SymbolTable::reportUnresolvable() {
undefs.insert(sym);
}
- reportProblemSymbols(undefs,
- /* localImports */ nullptr, ObjFile::instances,
- &BitcodeFile::instances);
+ reportProblemSymbols(ctx, undefs,
+ /* localImports */ nullptr, true);
}
void SymbolTable::resolveRemainingUndefines() {
@@ -515,8 +508,8 @@ void SymbolTable::resolveRemainingUndefines() {
}
reportProblemSymbols(
- undefs, config->warnLocallyDefinedImported ? &localImports : nullptr,
- ObjFile::instances, /* bitcode files no longer needed */ nullptr);
+ ctx, undefs, config->warnLocallyDefinedImported ? &localImports : nullptr,
+ false);
}
std::pair<Symbol *, bool> SymbolTable::insert(StringRef name) {
@@ -797,20 +790,20 @@ void SymbolTable::addLibcall(StringRef name) {
}
}
-std::vector<Chunk *> SymbolTable::getChunks() {
+std::vector<Chunk *> SymbolTable::getChunks() const {
std::vector<Chunk *> res;
- for (ObjFile *file : ObjFile::instances) {
+ for (ObjFile *file : ctx.objFileInstances) {
ArrayRef<Chunk *> v = file->getChunks();
res.insert(res.end(), v.begin(), v.end());
}
return res;
}
-Symbol *SymbolTable::find(StringRef name) {
+Symbol *SymbolTable::find(StringRef name) const {
return symMap.lookup(CachedHashStringRef(name));
}
-Symbol *SymbolTable::findUnderscore(StringRef name) {
+Symbol *SymbolTable::findUnderscore(StringRef name) const {
if (config->machine == I386)
return find(("_" + name).str());
return find(name);
@@ -873,17 +866,17 @@ Symbol *SymbolTable::addUndefined(StringRef name) {
}
void SymbolTable::addCombinedLTOObjects() {
- if (BitcodeFile::instances.empty())
+ if (ctx.bitcodeFileInstances.empty())
return;
- ScopedTimer t(ltoTimer);
- lto.reset(new BitcodeCompiler);
- for (BitcodeFile *f : BitcodeFile::instances)
+ ScopedTimer t(ctx.ltoTimer);
+ lto.reset(new BitcodeCompiler());
+ for (BitcodeFile *f : ctx.bitcodeFileInstances)
lto->add(*f);
- for (InputFile *newObj : lto->compile()) {
+ for (InputFile *newObj : lto->compile(ctx)) {
ObjFile *obj = cast<ObjFile>(newObj);
obj->parse();
- ObjFile::instances.push_back(obj);
+ ctx.objFileInstances.push_back(obj);
}
}
diff --git a/lld/COFF/SymbolTable.h b/lld/COFF/SymbolTable.h
index e88002c883101..03bc7f90e82ec 100644
--- a/lld/COFF/SymbolTable.h
+++ b/lld/COFF/SymbolTable.h
@@ -25,6 +25,7 @@ namespace coff {
class Chunk;
class CommonChunk;
+class COFFLinkerContext;
class Defined;
class DefinedAbsolute;
class DefinedRegular;
@@ -47,6 +48,8 @@ class Symbol;
// There is one add* function per symbol type.
class SymbolTable {
public:
+ SymbolTable(COFFLinkerContext &ctx) : ctx(ctx) {}
+
void addFile(InputFile *file);
// Emit errors for symbols that cannot be resolved.
@@ -63,11 +66,11 @@ class SymbolTable {
bool handleMinGWAutomaticImport(Symbol *sym, StringRef name);
// Returns a list of chunks of selected symbols.
- std::vector<Chunk *> getChunks();
+ std::vector<Chunk *> getChunks() const;
// Returns a symbol for a given name. Returns a nullptr if not found.
- Symbol *find(StringRef name);
- Symbol *findUnderscore(StringRef name);
+ Symbol *find(StringRef name) const;
+ Symbol *findUnderscore(StringRef name) const;
// Occasionally we have to resolve an undefined symbol to its
// mangled symbol. This function tries to find a mangled name
@@ -131,9 +134,9 @@ class SymbolTable {
llvm::DenseMap<llvm::CachedHashStringRef, Symbol *> symMap;
std::unique_ptr<BitcodeCompiler> lto;
-};
-extern SymbolTable *symtab;
+ COFFLinkerContext &ctx;
+};
std::vector<std::string> getSymbolLocations(ObjFile *file, uint32_t symIndex);
diff --git a/lld/COFF/TypeMerger.h b/lld/COFF/TypeMerger.h
index 72fd5fc72b011..8cb9433c4bf6b 100644
--- a/lld/COFF/TypeMerger.h
+++ b/lld/COFF/TypeMerger.h
@@ -10,6 +10,8 @@
#define LLD_COFF_TYPEMERGER_H
#include "Config.h"
+#include "DebugTypes.h"
+#include "lld/Common/Timer.h"
#include "llvm/DebugInfo/CodeView/MergingTypeTableBuilder.h"
#include "llvm/DebugInfo/CodeView/TypeHashing.h"
#include "llvm/Support/Allocator.h"
@@ -25,7 +27,7 @@ struct GHashState;
class TypeMerger {
public:
- TypeMerger(llvm::BumpPtrAllocator &alloc);
+ TypeMerger(COFFLinkerContext &ctx, llvm::BumpPtrAllocator &alloc);
~TypeMerger();
@@ -59,6 +61,20 @@ class TypeMerger {
// keyed by type index.
SmallVector<uint32_t, 0> tpiCounts;
SmallVector<uint32_t, 0> ipiCounts;
+
+ /// Dependency type sources, such as type servers or PCH object files. These
+ /// must be processed before objects that rely on them. Set by
+ /// sortDependencies.
+ ArrayRef<TpiSource *> dependencySources;
+
+ /// Object file sources. These must be processed after dependencySources.
+ ArrayRef<TpiSource *> objectSources;
+
+ /// Sorts the dependencies and reassigns TpiSource indices.
+ void sortDependencies();
+
+private:
+ COFFLinkerContext &ctx;
};
} // namespace coff
diff --git a/lld/COFF/Writer.cpp b/lld/COFF/Writer.cpp
index 37cbe2bb96a80..6641db119064f 100644
--- a/lld/COFF/Writer.cpp
+++ b/lld/COFF/Writer.cpp
@@ -7,6 +7,7 @@
//===----------------------------------------------------------------------===//
#include "Writer.h"
+#include "COFFLinkerContext.h"
#include "CallGraphSort.h"
#include "Config.h"
#include "DLL.h"
@@ -80,23 +81,14 @@ static_assert(dosStubSize % 8 == 0, "DOSStub size must be multiple of 8");
static const int numberOfDataDirectory = 16;
-// Global vector of all output sections. After output sections are finalized,
-// this can be indexed by Chunk::getOutputSection.
-static std::vector<OutputSection *> outputSections;
-
-OutputSection *Chunk::getOutputSection() const {
- return osidx == 0 ? nullptr : outputSections[osidx - 1];
-}
-
-void OutputSection::clear() { outputSections.clear(); }
-
namespace {
class DebugDirectoryChunk : public NonSectionChunk {
public:
- DebugDirectoryChunk(const std::vector<std::pair<COFF::DebugType, Chunk *>> &r,
+ DebugDirectoryChunk(COFFLinkerContext &c,
+ const std::vector<std::pair<COFF::DebugType, Chunk *>> &r,
bool writeRepro)
- : records(r), writeRepro(writeRepro) {}
+ : records(r), writeRepro(writeRepro), ctx(c) {}
size_t getSize() const override {
return (records.size() + int(writeRepro)) * sizeof(debug_directory);
@@ -107,7 +99,7 @@ class DebugDirectoryChunk : public NonSectionChunk {
for (const std::pair<COFF::DebugType, Chunk *>& record : records) {
Chunk *c = record.second;
- OutputSection *os = c->getOutputSection();
+ OutputSection *os = ctx.getOutputSection(c);
uint64_t offs = os->getFileOff() + (c->getRVA() - os->getRVA());
fillEntry(d, record.first, c->getSize(), c->getRVA(), offs);
++d;
@@ -146,6 +138,8 @@ class DebugDirectoryChunk : public NonSectionChunk {
mutable std::vector<support::ulittle32_t *> timeDateStamps;
const std::vector<std::pair<COFF::DebugType, Chunk *>> &records;
bool writeRepro;
+
+ COFFLinkerContext &ctx;
};
class CVDebugRecordChunk : public NonSectionChunk {
@@ -201,7 +195,7 @@ class PartialSectionKey {
// The writer writes a SymbolTable result to a file.
class Writer {
public:
- Writer() : buffer(errorHandler().outputBuffer) {}
+ Writer(COFFLinkerContext &c) : buffer(errorHandler().outputBuffer), ctx(c) {}
void run();
private:
@@ -304,13 +298,12 @@ class Writer {
// files, so we need to keep track of them separately.
Chunk *firstPdata = nullptr;
Chunk *lastPdata;
+
+ COFFLinkerContext &ctx;
};
} // anonymous namespace
-static Timer codeLayoutTimer("Code Layout", Timer::root());
-static Timer diskCommitTimer("Commit Output File", Timer::root());
-
-void lld::coff::writeResult() { Writer().run(); }
+void lld::coff::writeResult(COFFLinkerContext &ctx) { Writer(ctx).run(); }
void OutputSection::addChunk(Chunk *c) {
chunks.push_back(c);
@@ -549,7 +542,7 @@ void Writer::finalizeAddresses() {
return;
size_t origNumChunks = 0;
- for (OutputSection *sec : outputSections) {
+ for (OutputSection *sec : ctx.outputSections) {
sec->origChunks = sec->chunks;
origNumChunks += sec->chunks.size();
}
@@ -561,7 +554,7 @@ void Writer::finalizeAddresses() {
// adding them turned out ok.
bool rangesOk = true;
size_t numChunks = 0;
- for (OutputSection *sec : outputSections) {
+ for (OutputSection *sec : ctx.outputSections) {
if (!verifyRanges(sec->chunks)) {
rangesOk = false;
break;
@@ -582,7 +575,7 @@ void Writer::finalizeAddresses() {
// If the previous pass didn't work out, reset everything back to the
// original conditions before retrying with a wider margin. This should
// ideally never happen under real circumstances.
- for (OutputSection *sec : outputSections)
+ for (OutputSection *sec : ctx.outputSections)
sec->chunks = sec->origChunks;
margin *= 2;
}
@@ -590,7 +583,7 @@ void Writer::finalizeAddresses() {
// Try adding thunks everywhere where it is needed, with a margin
// to avoid things going out of range due to the added thunks.
bool addressesChanged = false;
- for (OutputSection *sec : outputSections)
+ for (OutputSection *sec : ctx.outputSections)
addressesChanged |= createThunks(sec, margin);
// If the verification above thought we needed thunks, we should have
// added some.
@@ -607,7 +600,7 @@ void Writer::finalizeAddresses() {
// The main function of the writer.
void Writer::run() {
- ScopedTimer t1(codeLayoutTimer);
+ ScopedTimer t1(ctx.codeLayoutTimer);
createImportTables();
createSections();
@@ -645,17 +638,17 @@ void Writer::run() {
if (!config->pdbPath.empty() && config->debug) {
assert(buildId);
- createPDB(symtab, outputSections, sectionTable, buildId->buildId);
+ createPDB(ctx, sectionTable, buildId->buildId);
}
writeBuildId();
- writeLLDMapFile(outputSections);
- writeMapFile(outputSections);
+ writeLLDMapFile(ctx);
+ writeMapFile(ctx);
if (errorCount())
return;
- ScopedTimer t2(diskCommitTimer);
+ ScopedTimer t2(ctx.outputCommitTimer);
if (auto e = buffer->commit())
fatal("failed to write the output file: " + toString(std::move(e)));
}
@@ -816,7 +809,8 @@ static bool shouldStripSectionSuffix(SectionChunk *sc, StringRef name) {
void Writer::sortSections() {
if (!config->callGraphProfile.empty()) {
- DenseMap<const SectionChunk *, int> order = computeCallGraphProfileOrder();
+ DenseMap<const SectionChunk *, int> order =
+ computeCallGraphProfileOrder(ctx);
for (auto it : order) {
if (DefinedRegular *sym = it.first->sym)
config->order[sym->getName()] = it.second;
@@ -843,7 +837,7 @@ void Writer::createSections() {
OutputSection *&sec = sections[{name, outChars}];
if (!sec) {
sec = make<OutputSection>(name, outChars);
- outputSections.push_back(sec);
+ ctx.outputSections.push_back(sec);
}
return sec;
};
@@ -864,7 +858,7 @@ void Writer::createSections() {
dtorsSec = createSection(".dtors", data | r | w);
// Then bin chunks by name and output characteristics.
- for (Chunk *c : symtab->getChunks()) {
+ for (Chunk *c : ctx.symtab.getChunks()) {
auto *sc = dyn_cast<SectionChunk>(c);
if (sc && !sc->live) {
if (config->verbose)
@@ -941,14 +935,14 @@ void Writer::createSections() {
return 1;
return 0;
};
- llvm::stable_sort(outputSections,
+ llvm::stable_sort(ctx.outputSections,
[&](const OutputSection *s, const OutputSection *t) {
return sectionOrder(s) < sectionOrder(t);
});
}
void Writer::createMiscChunks() {
- for (MergeChunk *p : MergeChunk::instances) {
+ for (MergeChunk *p : ctx.mergeChunkInstances) {
if (p) {
p->finalizeContents();
rdataSec->addChunk(p);
@@ -956,15 +950,16 @@ void Writer::createMiscChunks() {
}
// Create thunks for locally-dllimported symbols.
- if (!symtab->localImportChunks.empty()) {
- for (Chunk *c : symtab->localImportChunks)
+ if (!ctx.symtab.localImportChunks.empty()) {
+ for (Chunk *c : ctx.symtab.localImportChunks)
rdataSec->addChunk(c);
}
// Create Debug Information Chunks
OutputSection *debugInfoSec = config->mingw ? buildidSec : rdataSec;
if (config->debug || config->repro || config->cetCompat) {
- debugDirectory = make<DebugDirectoryChunk>(debugRecords, config->repro);
+ debugDirectory =
+ make<DebugDirectoryChunk>(ctx, debugRecords, config->repro);
debugDirectory->setAlignment(4);
debugInfoSec->addChunk(debugDirectory);
}
@@ -1013,7 +1008,7 @@ void Writer::createImportTables() {
// Initialize DLLOrder so that import entries are ordered in
// the same order as in the command line. (That affects DLL
// initialization order, and this ordering is MSVC-compatible.)
- for (ImportFile *file : ImportFile::instances) {
+ for (ImportFile *file : ctx.importFileInstances) {
if (!file->live)
continue;
@@ -1036,10 +1031,10 @@ void Writer::createImportTables() {
}
void Writer::appendImportThunks() {
- if (ImportFile::instances.empty())
+ if (ctx.importFileInstances.empty())
return;
- for (ImportFile *file : ImportFile::instances) {
+ for (ImportFile *file : ctx.importFileInstances) {
if (!file->live)
continue;
@@ -1055,7 +1050,7 @@ void Writer::appendImportThunks() {
if (!delayIdata.empty()) {
Defined *helper = cast<Defined>(config->delayLoadHelper);
- delayIdata.create(helper);
+ delayIdata.create(ctx, helper);
for (Chunk *c : delayIdata.getChunks())
didatSec->addChunk(c);
for (Chunk *c : delayIdata.getDataChunks())
@@ -1095,25 +1090,25 @@ void Writer::removeUnusedSections() {
// later. Only remove sections that have no Chunks at all.
return s->chunks.empty();
};
- outputSections.erase(
- std::remove_if(outputSections.begin(), outputSections.end(), isUnused),
- outputSections.end());
+ ctx.outputSections.erase(std::remove_if(ctx.outputSections.begin(),
+ ctx.outputSections.end(), isUnused),
+ ctx.outputSections.end());
}
// The Windows loader doesn't seem to like empty sections,
// so we remove them if any.
void Writer::removeEmptySections() {
auto isEmpty = [](OutputSection *s) { return s->getVirtualSize() == 0; };
- outputSections.erase(
- std::remove_if(outputSections.begin(), outputSections.end(), isEmpty),
- outputSections.end());
+ ctx.outputSections.erase(std::remove_if(ctx.outputSections.begin(),
+ ctx.outputSections.end(), isEmpty),
+ ctx.outputSections.end());
}
void Writer::assignOutputSectionIndices() {
// Assign final output section indices, and assign each chunk to its output
// section.
uint32_t idx = 1;
- for (OutputSection *os : outputSections) {
+ for (OutputSection *os : ctx.outputSections) {
os->sectionIndex = idx;
for (Chunk *c : os->chunks)
c->setOutputSectionIdx(idx);
@@ -1122,7 +1117,7 @@ void Writer::assignOutputSectionIndices() {
// Merge chunks are containers of chunks, so assign those an output section
// too.
- for (MergeChunk *mc : MergeChunk::instances)
+ for (MergeChunk *mc : ctx.mergeChunkInstances)
if (mc)
for (SectionChunk *sc : mc->sections)
if (sc && sc->live)
@@ -1153,7 +1148,7 @@ Optional<coff_symbol16> Writer::createSymbol(Defined *def) {
Chunk *c = def->getChunk();
if (!c)
return None;
- OutputSection *os = c->getOutputSection();
+ OutputSection *os = ctx.getOutputSection(c);
if (!os)
return None;
@@ -1200,7 +1195,7 @@ void Writer::createSymbolAndStringTable() {
// solution where discardable sections have long names preserved and
// non-discardable sections have their names truncated, to ensure that any
// section which is mapped at runtime also has its name mapped at runtime.
- for (OutputSection *sec : outputSections) {
+ for (OutputSection *sec : ctx.outputSections) {
if (sec->name.size() <= COFF::NameSize)
continue;
if ((sec->header.Characteristics & IMAGE_SCN_MEM_DISCARDABLE) == 0)
@@ -1214,7 +1209,7 @@ void Writer::createSymbolAndStringTable() {
}
if (config->debugDwarf || config->debugSymtab) {
- for (ObjFile *file : ObjFile::instances) {
+ for (ObjFile *file : ctx.objFileInstances) {
for (Symbol *b : file->getSymbols()) {
auto *d = dyn_cast_or_null<Defined>(b);
if (!d || d->writtenToSymtab)
@@ -1274,7 +1269,7 @@ void Writer::mergeSections() {
void Writer::assignAddresses() {
sizeOfHeaders = dosStubSize + sizeof(PEMagic) + sizeof(coff_file_header) +
sizeof(data_directory) * numberOfDataDirectory +
- sizeof(coff_section) * outputSections.size();
+ sizeof(coff_section) * ctx.outputSections.size();
sizeOfHeaders +=
config->is64() ? sizeof(pe32plus_header) : sizeof(pe32_header);
sizeOfHeaders = alignTo(sizeOfHeaders, config->fileAlign);
@@ -1283,7 +1278,7 @@ void Writer::assignAddresses() {
// The first page is kept unmapped.
uint64_t rva = alignTo(sizeOfHeaders, config->align);
- for (OutputSection *sec : outputSections) {
+ for (OutputSection *sec : ctx.outputSections) {
if (sec == relocSec)
addBaserels();
uint64_t rawSize = 0, virtualSize = 0;
@@ -1318,7 +1313,7 @@ void Writer::assignAddresses() {
sizeOfImage = alignTo(rva, config->align);
// Assign addresses to sections in MergeChunks.
- for (MergeChunk *mc : MergeChunk::instances)
+ for (MergeChunk *mc : ctx.mergeChunkInstances)
if (mc)
mc->assignSubsectionRVAs();
}
@@ -1353,7 +1348,7 @@ template <typename PEHeaderTy> void Writer::writeHeader() {
auto *coff = reinterpret_cast<coff_file_header *>(buf);
buf += sizeof(*coff);
coff->Machine = config->machine;
- coff->NumberOfSections = outputSections.size();
+ coff->NumberOfSections = ctx.outputSections.size();
coff->Characteristics = IMAGE_FILE_EXECUTABLE_IMAGE;
if (config->largeAddressAware)
coff->Characteristics |= IMAGE_FILE_LARGE_ADDRESS_AWARE;
@@ -1466,7 +1461,7 @@ template <typename PEHeaderTy> void Writer::writeHeader() {
dir[BASE_RELOCATION_TABLE].RelativeVirtualAddress = relocSec->getRVA();
dir[BASE_RELOCATION_TABLE].Size = relocSec->getVirtualSize();
}
- if (Symbol *sym = symtab->findUnderscore("_tls_used")) {
+ if (Symbol *sym = ctx.symtab.findUnderscore("_tls_used")) {
if (Defined *b = dyn_cast<Defined>(sym)) {
dir[TLS_TABLE].RelativeVirtualAddress = b->getRVA();
dir[TLS_TABLE].Size = config->is64()
@@ -1478,7 +1473,7 @@ template <typename PEHeaderTy> void Writer::writeHeader() {
dir[DEBUG_DIRECTORY].RelativeVirtualAddress = debugDirectory->getRVA();
dir[DEBUG_DIRECTORY].Size = debugDirectory->getSize();
}
- if (Symbol *sym = symtab->findUnderscore("_load_config_used")) {
+ if (Symbol *sym = ctx.symtab.findUnderscore("_load_config_used")) {
if (auto *b = dyn_cast<DefinedRegular>(sym)) {
SectionChunk *sc = b->getChunk();
assert(b->getRVA() >= sc->getRVA());
@@ -1502,12 +1497,12 @@ template <typename PEHeaderTy> void Writer::writeHeader() {
}
// Write section table
- for (OutputSection *sec : outputSections) {
+ for (OutputSection *sec : ctx.outputSections) {
sec->writeHeaderTo(buf);
buf += sizeof(coff_section);
}
sectionTable = ArrayRef<uint8_t>(
- buf - outputSections.size() * sizeof(coff_section), buf);
+ buf - ctx.outputSections.size() * sizeof(coff_section), buf);
if (outputSymtab.empty() && strtab.empty())
return;
@@ -1535,7 +1530,7 @@ void Writer::openFile(StringRef path) {
void Writer::createSEHTable() {
SymbolRVASet handlers;
- for (ObjFile *file : ObjFile::instances) {
+ for (ObjFile *file : ctx.objFileInstances) {
if (!file->hasSafeSEH())
error("/safeseh: " + file->getName() + " is not compatible with SEH");
markSymbolsForRVATable(file, file->getSXDataChunks(), handlers);
@@ -1544,7 +1539,7 @@ void Writer::createSEHTable() {
// Set the "no SEH" characteristic if there really were no handlers, or if
// there is no load config object to point to the table of handlers.
setNoSEHCharacteristic =
- handlers.empty() || !symtab->findUnderscore("_load_config_used");
+ handlers.empty() || !ctx.symtab.findUnderscore("_load_config_used");
maybeAddRVATable(std::move(handlers), "__safe_se_handler_table",
"__safe_se_handler_count");
@@ -1642,7 +1637,7 @@ void Writer::createGuardCFTables() {
std::vector<Symbol *> giatsSymbols;
SymbolRVASet longJmpTargets;
SymbolRVASet ehContTargets;
- for (ObjFile *file : ObjFile::instances) {
+ for (ObjFile *file : ctx.objFileInstances) {
// If the object was compiled with /guard:cf, the address taken symbols
// are in .gfids$y sections, the longjmp targets are in .gljmp$y sections,
// and ehcont targets are in .gehcont$y sections. If the object was not
@@ -1708,7 +1703,7 @@ void Writer::createGuardCFTables() {
guardFlags |= uint32_t(coff_guard_flags::HasLongJmpTable);
if (config->guardCF & GuardCFLevel::EHCont)
guardFlags |= uint32_t(coff_guard_flags::HasEHContTable);
- Symbol *flagSym = symtab->findUnderscore("__guard_flags");
+ Symbol *flagSym = ctx.symtab.findUnderscore("__guard_flags");
cast<DefinedAbsolute>(flagSym)->setVA(guardFlags);
}
@@ -1780,8 +1775,8 @@ void Writer::maybeAddRVATable(SymbolRVASet tableSymbols, StringRef tableSym,
tableChunk = make<RVATableChunk>(std::move(tableSymbols));
rdataSec->addChunk(tableChunk);
- Symbol *t = symtab->findUnderscore(tableSym);
- Symbol *c = symtab->findUnderscore(countSym);
+ Symbol *t = ctx.symtab.findUnderscore(tableSym);
+ Symbol *c = ctx.symtab.findUnderscore(countSym);
replaceSymbol<DefinedSynthetic>(t, t->getName(), tableChunk);
cast<DefinedAbsolute>(c)->setVA(tableChunk->getSize() / (hasFlag ? 5 : 4));
}
@@ -1793,7 +1788,7 @@ void Writer::maybeAddRVATable(SymbolRVASet tableSymbols, StringRef tableSym,
void Writer::createRuntimePseudoRelocs() {
std::vector<RuntimePseudoReloc> rels;
- for (Chunk *c : symtab->getChunks()) {
+ for (Chunk *c : ctx.symtab.getChunks()) {
auto *sc = dyn_cast<SectionChunk>(c);
if (!sc || !sc->live)
continue;
@@ -1816,8 +1811,9 @@ void Writer::createRuntimePseudoRelocs() {
EmptyChunk *endOfList = make<EmptyChunk>();
rdataSec->addChunk(endOfList);
- Symbol *headSym = symtab->findUnderscore("__RUNTIME_PSEUDO_RELOC_LIST__");
- Symbol *endSym = symtab->findUnderscore("__RUNTIME_PSEUDO_RELOC_LIST_END__");
+ Symbol *headSym = ctx.symtab.findUnderscore("__RUNTIME_PSEUDO_RELOC_LIST__");
+ Symbol *endSym =
+ ctx.symtab.findUnderscore("__RUNTIME_PSEUDO_RELOC_LIST_END__");
replaceSymbol<DefinedSynthetic>(headSym, headSym->getName(), table);
replaceSymbol<DefinedSynthetic>(endSym, endSym->getName(), endOfList);
}
@@ -1837,8 +1833,8 @@ void Writer::insertCtorDtorSymbols() {
dtorsSec->insertChunkAtStart(dtorListHead);
dtorsSec->addChunk(dtorListEnd);
- Symbol *ctorListSym = symtab->findUnderscore("__CTOR_LIST__");
- Symbol *dtorListSym = symtab->findUnderscore("__DTOR_LIST__");
+ Symbol *ctorListSym = ctx.symtab.findUnderscore("__CTOR_LIST__");
+ Symbol *dtorListSym = ctx.symtab.findUnderscore("__DTOR_LIST__");
replaceSymbol<DefinedSynthetic>(ctorListSym, ctorListSym->getName(),
ctorListHead);
replaceSymbol<DefinedSynthetic>(dtorListSym, dtorListSym->getName(),
@@ -1851,7 +1847,7 @@ void Writer::setSectionPermissions() {
for (auto &p : config->section) {
StringRef name = p.first;
uint32_t perm = p.second;
- for (OutputSection *sec : outputSections)
+ for (OutputSection *sec : ctx.outputSections)
if (sec->name == name)
sec->setPermissions(perm);
}
@@ -1861,10 +1857,10 @@ void Writer::setSectionPermissions() {
void Writer::writeSections() {
// Record the number of sections to apply section index relocations
// against absolute symbols. See applySecIdx in Chunks.cpp..
- DefinedAbsolute::numOutputSections = outputSections.size();
+ DefinedAbsolute::numOutputSections = ctx.outputSections.size();
uint8_t *buf = buffer->getBufferStart();
- for (OutputSection *sec : outputSections) {
+ for (OutputSection *sec : ctx.outputSections) {
uint8_t *secBuf = buf + sec->getFileOff();
// Fill gaps between functions in .text with INT3 instructions
// instead of leaving as NUL bytes (which can be interpreted as
@@ -1934,7 +1930,7 @@ void Writer::sortExceptionTable() {
return;
// We assume .pdata contains function table entries only.
auto bufAddr = [&](Chunk *c) {
- OutputSection *os = c->getOutputSection();
+ OutputSection *os = ctx.getOutputSection(c);
return buffer->getBufferStart() + os->getFileOff() + c->getRVA() -
os->getRVA();
};
@@ -2002,7 +1998,7 @@ void Writer::sortCRTSectionChunks(std::vector<Chunk *> &chunks) {
}
OutputSection *Writer::findSection(StringRef name) {
- for (OutputSection *sec : outputSections)
+ for (OutputSection *sec : ctx.outputSections)
if (sec->name == name)
return sec;
return nullptr;
@@ -2010,7 +2006,7 @@ OutputSection *Writer::findSection(StringRef name) {
uint32_t Writer::getSizeOfInitializedData() {
uint32_t res = 0;
- for (OutputSection *s : outputSections)
+ for (OutputSection *s : ctx.outputSections)
if (s->header.Characteristics & IMAGE_SCN_CNT_INITIALIZED_DATA)
res += s->getRawSize();
return res;
@@ -2022,7 +2018,7 @@ void Writer::addBaserels() {
return;
relocSec->chunks.clear();
std::vector<Baserel> v;
- for (OutputSection *sec : outputSections) {
+ for (OutputSection *sec : ctx.outputSections) {
if (sec->header.Characteristics & IMAGE_SCN_MEM_DISCARDABLE)
continue;
// Collect all locations for base relocations.
@@ -2071,11 +2067,11 @@ PartialSection *Writer::findPartialSection(StringRef name, uint32_t outChars) {
void Writer::fixTlsAlignment() {
Defined *tlsSym =
- dyn_cast_or_null<Defined>(symtab->findUnderscore("_tls_used"));
+ dyn_cast_or_null<Defined>(ctx.symtab.findUnderscore("_tls_used"));
if (!tlsSym)
return;
- OutputSection *sec = tlsSym->getChunk()->getOutputSection();
+ OutputSection *sec = ctx.getOutputSection(tlsSym->getChunk());
assert(sec && tlsSym->getRVA() >= sec->getRVA() &&
"no output section for _tls_used");
diff --git a/lld/COFF/Writer.h b/lld/COFF/Writer.h
index 2bb26da7d428a..d2b3b4b81d3cf 100644
--- a/lld/COFF/Writer.h
+++ b/lld/COFF/Writer.h
@@ -19,8 +19,9 @@
namespace lld {
namespace coff {
static const int pageSize = 4096;
+class COFFLinkerContext;
-void writeResult();
+void writeResult(COFFLinkerContext &ctx);
class PartialSection {
public:
@@ -50,9 +51,6 @@ class OutputSection {
void writeHeaderTo(uint8_t *buf);
void addContributingPartialSection(PartialSection *sec);
- // Clear the output sections static container.
- static void clear();
-
// Returns the size of this section in an executable memory image.
// This may be smaller than the raw size (the raw size is multiple
// of disk sector size, so there may be padding at end), or may be
diff --git a/lld/Common/Timer.cpp b/lld/Common/Timer.cpp
index 16c518e4bf841..a61f000e8c070 100644
--- a/lld/Common/Timer.cpp
+++ b/lld/Common/Timer.cpp
@@ -31,13 +31,8 @@ Timer::Timer(llvm::StringRef name, Timer &parent) : name(std::string(name)) {
parent.children.push_back(this);
}
-Timer &Timer::root() {
- static Timer rootTimer("Total Link Time");
- return rootTimer;
-}
-
void Timer::print() {
- double totalDuration = static_cast<double>(root().millis());
+ double totalDuration = static_cast<double>(millis());
// We want to print the grand total under all the intermediate phases, so we
// print all children first, then print the total under that.
@@ -47,7 +42,7 @@ void Timer::print() {
message(std::string(50, '-'));
- root().print(0, root().millis(), false);
+ print(0, millis(), false);
}
double Timer::millis() const {
diff --git a/lld/include/lld/Common/Timer.h b/lld/include/lld/Common/Timer.h
index b37388cd38c43..7aca966f663c0 100644
--- a/lld/include/lld/Common/Timer.h
+++ b/lld/include/lld/Common/Timer.h
@@ -38,7 +38,8 @@ class Timer {
public:
Timer(llvm::StringRef name, Timer &parent);
- static Timer &root();
+ // Creates the root timer.
+ explicit Timer(llvm::StringRef name);
void addToTotal(std::chrono::nanoseconds time) { total += time.count(); }
void print();
@@ -46,7 +47,6 @@ class Timer {
double millis() const;
private:
- explicit Timer(llvm::StringRef name);
void print(int depth, double totalDuration, bool recurse = true) const;
std::atomic<std::chrono::nanoseconds::rep> total;
diff --git a/llvm/utils/gn/secondary/lld/COFF/BUILD.gn b/llvm/utils/gn/secondary/lld/COFF/BUILD.gn
index 0f19a77741b03..78c79844bb2a7 100644
--- a/llvm/utils/gn/secondary/lld/COFF/BUILD.gn
+++ b/llvm/utils/gn/secondary/lld/COFF/BUILD.gn
@@ -29,6 +29,7 @@ static_library("COFF") {
sources = [
"CallGraphSort.cpp",
"Chunks.cpp",
+ "COFFLinkerContext.cpp",
"DLL.cpp",
"DebugTypes.cpp",
"Driver.cpp",
More information about the llvm-commits
mailing list