[lld] 7370ff6 - [LLD] Remove global state in lld/COFF
Alexandre Ganea via llvm-commits
llvm-commits at lists.llvm.org
Sun Jan 8 15:57:45 PST 2023
Author: Amy Huang
Date: 2023-01-08T18:43:13-05:00
New Revision: 7370ff624d217b0f8f7512ca5b651a9b8095a411
URL: https://github.com/llvm/llvm-project/commit/7370ff624d217b0f8f7512ca5b651a9b8095a411
DIFF: https://github.com/llvm/llvm-project/commit/7370ff624d217b0f8f7512ca5b651a9b8095a411.diff
LOG: [LLD] Remove global state in lld/COFF
Remove globals from the lldCOFF library, by moving globals into a context class.
This patch mostly moves the config object into COFFLinkerContext.
See https://lists.llvm.org/pipermail/llvm-dev/2021-June/151184.html for
context about removing globals from LLD.
Reviewed By: aganea
Differential Revision: https://reviews.llvm.org/D110450
Added:
Modified:
lld/COFF/COFFLinkerContext.cpp
lld/COFF/COFFLinkerContext.h
lld/COFF/CallGraphSort.cpp
lld/COFF/Chunks.cpp
lld/COFF/Chunks.h
lld/COFF/Config.h
lld/COFF/DLL.cpp
lld/COFF/DLL.h
lld/COFF/DebugTypes.cpp
lld/COFF/Driver.cpp
lld/COFF/Driver.h
lld/COFF/DriverUtils.cpp
lld/COFF/ICF.cpp
lld/COFF/ICF.h
lld/COFF/InputFiles.cpp
lld/COFF/InputFiles.h
lld/COFF/LLDMapFile.cpp
lld/COFF/LTO.cpp
lld/COFF/LTO.h
lld/COFF/MapFile.cpp
lld/COFF/MarkLive.cpp
lld/COFF/MinGW.cpp
lld/COFF/MinGW.h
lld/COFF/PDB.cpp
lld/COFF/SymbolTable.cpp
lld/COFF/SymbolTable.h
lld/COFF/Symbols.cpp
lld/COFF/Symbols.h
lld/COFF/TypeMerger.h
lld/COFF/Writer.cpp
lld/COFF/Writer.h
Removed:
################################################################################
diff --git a/lld/COFF/COFFLinkerContext.cpp b/lld/COFF/COFFLinkerContext.cpp
index cd497903f183..4f1c7afb5a6b 100644
--- a/lld/COFF/COFFLinkerContext.cpp
+++ b/lld/COFF/COFFLinkerContext.cpp
@@ -10,13 +10,15 @@
//===----------------------------------------------------------------------===//
#include "COFFLinkerContext.h"
+#include "Symbols.h"
#include "lld/Common/Memory.h"
+#include "llvm/BinaryFormat/COFF.h"
#include "llvm/DebugInfo/CodeView/TypeHashing.h"
+#include "llvm/Demangle/Demangle.h"
namespace lld::coff {
-
COFFLinkerContext::COFFLinkerContext()
- : symtab(*this), rootTimer("Total Linking Time"),
+ : driver(*this), symtab(*this), rootTimer("Total Linking Time"),
inputFileTimer("Input File Reading", rootTimer),
ltoTimer("LTO", rootTimer), gcTimer("GC", rootTimer),
icfTimer("ICF", rootTimer), codeLayoutTimer("Code Layout", rootTimer),
@@ -33,6 +35,10 @@ COFFLinkerContext::COFFLinkerContext()
symbolMergingTimer("Symbol Merging", addObjectsTimer),
publicsLayoutTimer("Publics Stream Layout", totalPdbLinkTimer),
tpiStreamLayoutTimer("TPI Stream Layout", totalPdbLinkTimer),
- diskCommitTimer("Commit to Disk", totalPdbLinkTimer) {}
-
+ diskCommitTimer("Commit to Disk", totalPdbLinkTimer) {
+ FakeSection ltoTextSection(llvm::COFF::IMAGE_SCN_MEM_EXECUTE);
+ FakeSection ltoDataSection(llvm::COFF::IMAGE_SCN_CNT_INITIALIZED_DATA);
+ ltoTextSectionChunk = make<FakeSectionChunk>(<oTextSection.section);
+ ltoDataSectionChunk = make<FakeSectionChunk>(<oDataSection.section);
+}
} // namespace lld::coff
diff --git a/lld/COFF/COFFLinkerContext.h b/lld/COFF/COFFLinkerContext.h
index 96b4de436398..8814efbd9099 100644
--- a/lld/COFF/COFFLinkerContext.h
+++ b/lld/COFF/COFFLinkerContext.h
@@ -6,12 +6,13 @@
//
//===----------------------------------------------------------------------===//
-#ifndef LLD_COFF_COFFLinkerContext_H
-#define LLD_COFF_COFFLinkerContext_H
+#ifndef LLD_COFF_COFFLINKERCONTEXT_H
+#define LLD_COFF_COFFLINKERCONTEXT_H
#include "Chunks.h"
#include "Config.h"
#include "DebugTypes.h"
+#include "Driver.h"
#include "InputFiles.h"
#include "SymbolTable.h"
#include "Writer.h"
@@ -27,9 +28,9 @@ class COFFLinkerContext : public CommonLinkerContext {
COFFLinkerContext &operator=(const COFFLinkerContext &) = delete;
~COFFLinkerContext() = default;
- void addTpiSource(TpiSource *tpi) { tpiSourceList.push_back(tpi); }
-
+ LinkerDriver driver;
SymbolTable symtab;
+ COFFOptTable optTable;
std::vector<ObjFile *> objFileInstances;
std::map<std::string, PDBInputFile *> pdbInputFileInstances;
@@ -41,6 +42,8 @@ class COFFLinkerContext : public CommonLinkerContext {
/// All sources of type information in the program.
std::vector<TpiSource *> tpiSourceList;
+ void addTpiSource(TpiSource *tpi) { tpiSourceList.push_back(tpi); }
+
std::map<llvm::codeview::GUID, TpiSource *> typeServerSourceMappings;
std::map<uint32_t, TpiSource *> precompSourceMappings;
@@ -52,6 +55,10 @@ class COFFLinkerContext : public CommonLinkerContext {
return c->osidx == 0 ? nullptr : outputSections[c->osidx - 1];
}
+ // Fake sections for parsing bitcode files.
+ FakeSectionChunk *ltoTextSectionChunk;
+ FakeSectionChunk *ltoDataSectionChunk;
+
// All timers used in the COFF linker.
Timer rootTimer;
Timer inputFileTimer;
@@ -77,6 +84,8 @@ class COFFLinkerContext : public CommonLinkerContext {
Timer publicsLayoutTimer;
Timer tpiStreamLayoutTimer;
Timer diskCommitTimer;
+
+ Configuration config;
};
} // namespace lld::coff
diff --git a/lld/COFF/CallGraphSort.cpp b/lld/COFF/CallGraphSort.cpp
index 709e69b24914..e83996b035f6 100644
--- a/lld/COFF/CallGraphSort.cpp
+++ b/lld/COFF/CallGraphSort.cpp
@@ -56,6 +56,8 @@ class CallGraphSort {
private:
std::vector<Cluster> clusters;
std::vector<const SectionChunk *> sections;
+
+ const COFFLinkerContext &ctx;
};
// Maximum amount the combined cluster density can be worse than the original
@@ -71,8 +73,8 @@ 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(const COFFLinkerContext &ctx) {
- MapVector<SectionPair, uint64_t> &profile = config->callGraphProfile;
+CallGraphSort::CallGraphSort(const COFFLinkerContext &ctx) : ctx(ctx) {
+ const MapVector<SectionPair, uint64_t> &profile = ctx.config.callGraphProfile;
DenseMap<const SectionChunk *, int> secToCluster;
auto getOrCreateNode = [&](const SectionChunk *isec) -> int {
@@ -85,7 +87,7 @@ CallGraphSort::CallGraphSort(const COFFLinkerContext &ctx) {
};
// Create the graph.
- for (std::pair<SectionPair, uint64_t> &c : profile) {
+ for (const std::pair<SectionPair, uint64_t> &c : profile) {
const auto *fromSec = cast<SectionChunk>(c.first.first->repl);
const auto *toSec = cast<SectionChunk>(c.first.second->repl);
uint64_t weight = c.second;
@@ -205,11 +207,11 @@ DenseMap<const SectionChunk *, int> CallGraphSort::run() {
break;
}
}
- if (!config->printSymbolOrder.empty()) {
+ if (!ctx.config.printSymbolOrder.empty()) {
std::error_code ec;
- raw_fd_ostream os(config->printSymbolOrder, ec, sys::fs::OF_None);
+ raw_fd_ostream os(ctx.config.printSymbolOrder, ec, sys::fs::OF_None);
if (ec) {
- error("cannot open " + config->printSymbolOrder + ": " + ec.message());
+ error("cannot open " + ctx.config.printSymbolOrder + ": " + ec.message());
return orderMap;
}
// Print the symbols ordered by C3, in the order of increasing curOrder
diff --git a/lld/COFF/Chunks.cpp b/lld/COFF/Chunks.cpp
index f626458fea95..880bfc34727e 100644
--- a/lld/COFF/Chunks.cpp
+++ b/lld/COFF/Chunks.cpp
@@ -53,8 +53,8 @@ SectionChunk::SectionChunk(ObjFile *f, const coff_section *h)
// enabled, treat non-comdat sections as roots. Generally optimized object
// files will be built with -ffunction-sections or /Gy, so most things worth
// stripping will be in a comdat.
- if (config)
- live = !config->doGC || !isCOMDAT();
+ if (file)
+ live = !file->ctx.config.doGC || !isCOMDAT();
else
live = true;
}
@@ -94,21 +94,32 @@ static void applySecRel(const SectionChunk *sec, uint8_t *off,
add32(off, secRel);
}
-static void applySecIdx(uint8_t *off, OutputSection *os) {
+static void applySecIdx(uint8_t *off, OutputSection *os,
+ unsigned numOutputSections) {
+ // numOutputSections is the largest valid section index. Make sure that
+ // it fits in 16 bits.
+ assert(sizeof(numOutputSections) <= 0xffff &&
+ "size of outputSections is too big");
+
// Absolute symbol doesn't have section index, but section index relocation
// against absolute symbol should be resolved to one plus the last output
// section index. This is required for compatibility with MSVC.
if (os)
add16(off, os->sectionIndex);
else
- add16(off, DefinedAbsolute::numOutputSections + 1);
+ add16(off, numOutputSections + 1);
}
void SectionChunk::applyRelX64(uint8_t *off, uint16_t type, OutputSection *os,
- uint64_t s, uint64_t p) const {
+ uint64_t s, uint64_t p,
+ uint64_t imageBase) const {
switch (type) {
- case IMAGE_REL_AMD64_ADDR32: add32(off, s + config->imageBase); break;
- case IMAGE_REL_AMD64_ADDR64: add64(off, s + config->imageBase); break;
+ case IMAGE_REL_AMD64_ADDR32:
+ add32(off, s + imageBase);
+ break;
+ case IMAGE_REL_AMD64_ADDR64:
+ add64(off, s + imageBase);
+ break;
case IMAGE_REL_AMD64_ADDR32NB: add32(off, s); break;
case IMAGE_REL_AMD64_REL32: add32(off, s - p - 4); break;
case IMAGE_REL_AMD64_REL32_1: add32(off, s - p - 5); break;
@@ -116,7 +127,9 @@ void SectionChunk::applyRelX64(uint8_t *off, uint16_t type, OutputSection *os,
case IMAGE_REL_AMD64_REL32_3: add32(off, s - p - 7); break;
case IMAGE_REL_AMD64_REL32_4: add32(off, s - p - 8); break;
case IMAGE_REL_AMD64_REL32_5: add32(off, s - p - 9); break;
- case IMAGE_REL_AMD64_SECTION: applySecIdx(off, os); break;
+ case IMAGE_REL_AMD64_SECTION:
+ applySecIdx(off, os, file->ctx.outputSections.size());
+ break;
case IMAGE_REL_AMD64_SECREL: applySecRel(this, off, os, s); break;
default:
error("unsupported relocation type 0x" + Twine::utohexstr(type) + " in " +
@@ -125,13 +138,18 @@ void SectionChunk::applyRelX64(uint8_t *off, uint16_t type, OutputSection *os,
}
void SectionChunk::applyRelX86(uint8_t *off, uint16_t type, OutputSection *os,
- uint64_t s, uint64_t p) const {
+ uint64_t s, uint64_t p,
+ uint64_t imageBase) const {
switch (type) {
case IMAGE_REL_I386_ABSOLUTE: break;
- case IMAGE_REL_I386_DIR32: add32(off, s + config->imageBase); break;
+ case IMAGE_REL_I386_DIR32:
+ add32(off, s + imageBase);
+ break;
case IMAGE_REL_I386_DIR32NB: add32(off, s); break;
case IMAGE_REL_I386_REL32: add32(off, s - p - 4); break;
- case IMAGE_REL_I386_SECTION: applySecIdx(off, os); break;
+ case IMAGE_REL_I386_SECTION:
+ applySecIdx(off, os, file->ctx.outputSections.size());
+ break;
case IMAGE_REL_I386_SECREL: applySecRel(this, off, os, s); break;
default:
error("unsupported relocation type 0x" + Twine::utohexstr(type) + " in " +
@@ -188,19 +206,26 @@ void applyBranch24T(uint8_t *off, int32_t v) {
}
void SectionChunk::applyRelARM(uint8_t *off, uint16_t type, OutputSection *os,
- uint64_t s, uint64_t p) const {
+ uint64_t s, uint64_t p,
+ uint64_t imageBase) const {
// Pointer to thumb code must have the LSB set.
uint64_t sx = s;
if (os && (os->header.Characteristics & IMAGE_SCN_MEM_EXECUTE))
sx |= 1;
switch (type) {
- case IMAGE_REL_ARM_ADDR32: add32(off, sx + config->imageBase); break;
+ case IMAGE_REL_ARM_ADDR32:
+ add32(off, sx + imageBase);
+ break;
case IMAGE_REL_ARM_ADDR32NB: add32(off, sx); break;
- case IMAGE_REL_ARM_MOV32T: applyMOV32T(off, sx + config->imageBase); break;
+ case IMAGE_REL_ARM_MOV32T:
+ applyMOV32T(off, sx + imageBase);
+ break;
case IMAGE_REL_ARM_BRANCH20T: applyBranch20T(off, sx - p - 4); break;
case IMAGE_REL_ARM_BRANCH24T: applyBranch24T(off, sx - p - 4); break;
case IMAGE_REL_ARM_BLX23T: applyBranch24T(off, sx - p - 4); break;
- case IMAGE_REL_ARM_SECTION: applySecIdx(off, os); break;
+ case IMAGE_REL_ARM_SECTION:
+ applySecIdx(off, os, file->ctx.outputSections.size());
+ break;
case IMAGE_REL_ARM_SECREL: applySecRel(this, off, os, s); break;
case IMAGE_REL_ARM_REL32: add32(off, sx - p - 4); break;
default:
@@ -298,7 +323,8 @@ static void applyArm64Branch14(uint8_t *off, int64_t v) {
}
void SectionChunk::applyRelARM64(uint8_t *off, uint16_t type, OutputSection *os,
- uint64_t s, uint64_t p) const {
+ uint64_t s, uint64_t p,
+ uint64_t imageBase) const {
switch (type) {
case IMAGE_REL_ARM64_PAGEBASE_REL21: applyArm64Addr(off, s, p, 12); break;
case IMAGE_REL_ARM64_REL21: applyArm64Addr(off, s, p, 0); break;
@@ -307,14 +333,20 @@ void SectionChunk::applyRelARM64(uint8_t *off, uint16_t type, OutputSection *os,
case IMAGE_REL_ARM64_BRANCH26: applyArm64Branch26(off, s - p); break;
case IMAGE_REL_ARM64_BRANCH19: applyArm64Branch19(off, s - p); break;
case IMAGE_REL_ARM64_BRANCH14: applyArm64Branch14(off, s - p); break;
- case IMAGE_REL_ARM64_ADDR32: add32(off, s + config->imageBase); break;
+ case IMAGE_REL_ARM64_ADDR32:
+ add32(off, s + imageBase);
+ break;
case IMAGE_REL_ARM64_ADDR32NB: add32(off, s); break;
- case IMAGE_REL_ARM64_ADDR64: add64(off, s + config->imageBase); break;
+ case IMAGE_REL_ARM64_ADDR64:
+ add64(off, s + imageBase);
+ break;
case IMAGE_REL_ARM64_SECREL: applySecRel(this, off, os, s); break;
case IMAGE_REL_ARM64_SECREL_LOW12A: applySecRelLow12A(this, off, os, s); break;
case IMAGE_REL_ARM64_SECREL_HIGH12A: applySecRelHigh12A(this, off, os, s); break;
case IMAGE_REL_ARM64_SECREL_LOW12L: applySecRelLdr(this, off, os, s); break;
- case IMAGE_REL_ARM64_SECTION: applySecIdx(off, os); break;
+ case IMAGE_REL_ARM64_SECTION:
+ applySecIdx(off, os, file->ctx.outputSections.size());
+ break;
case IMAGE_REL_ARM64_REL32: add32(off, s - p - 4); break;
default:
error("unsupported relocation type 0x" + Twine::utohexstr(type) + " in " +
@@ -324,12 +356,13 @@ void SectionChunk::applyRelARM64(uint8_t *off, uint16_t type, OutputSection *os,
static void maybeReportRelocationToDiscarded(const SectionChunk *fromChunk,
Defined *sym,
- const coff_relocation &rel) {
+ const coff_relocation &rel,
+ bool isMinGW) {
// Don't report these errors when the relocation comes from a debug info
// section or in mingw mode. MinGW mode object files (built by GCC) can
// have leftover sections with relocations against discarded comdat
// sections. Such sections are left as is, with relocations untouched.
- if (fromChunk->isCodeView() || fromChunk->isDWARF() || config->mingw)
+ if (fromChunk->isCodeView() || fromChunk->isDWARF() || isMinGW)
return;
// Get the name of the symbol. If it's null, it was discarded early, so we
@@ -395,7 +428,7 @@ void SectionChunk::applyRelocation(uint8_t *off,
// it was an absolute or synthetic symbol.
if (!sym ||
(!os && !isa<DefinedAbsolute>(sym) && !isa<DefinedSynthetic>(sym))) {
- maybeReportRelocationToDiscarded(this, sym, rel);
+ maybeReportRelocationToDiscarded(this, sym, rel, file->ctx.config.mingw);
return;
}
@@ -403,18 +436,19 @@ void SectionChunk::applyRelocation(uint8_t *off,
// Compute the RVA of the relocation for relative relocations.
uint64_t p = rva + rel.VirtualAddress;
- switch (config->machine) {
+ uint64_t imageBase = file->ctx.config.imageBase;
+ switch (file->ctx.config.machine) {
case AMD64:
- applyRelX64(off, rel.Type, os, s, p);
+ applyRelX64(off, rel.Type, os, s, p, imageBase);
break;
case I386:
- applyRelX86(off, rel.Type, os, s, p);
+ applyRelX86(off, rel.Type, os, s, p, imageBase);
break;
case ARMNT:
- applyRelARM(off, rel.Type, os, s, p);
+ applyRelARM(off, rel.Type, os, s, p, imageBase);
break;
case ARM64:
- applyRelARM64(off, rel.Type, os, s, p);
+ applyRelARM64(off, rel.Type, os, s, p, imageBase);
break;
default:
llvm_unreachable("unknown machine type");
@@ -479,8 +513,9 @@ void SectionChunk::addAssociative(SectionChunk *child) {
child->assocChildren = next;
}
-static uint8_t getBaserelType(const coff_relocation &rel) {
- switch (config->machine) {
+static uint8_t getBaserelType(const coff_relocation &rel,
+ llvm::COFF::MachineTypes machine) {
+ switch (machine) {
case AMD64:
if (rel.Type == IMAGE_REL_AMD64_ADDR64)
return IMAGE_REL_BASED_DIR64;
@@ -512,7 +547,7 @@ static uint8_t getBaserelType(const coff_relocation &rel) {
// Only called when base relocation is enabled.
void SectionChunk::getBaserels(std::vector<Baserel> *res) {
for (const coff_relocation &rel : getRelocs()) {
- uint8_t ty = getBaserelType(rel);
+ uint8_t ty = getBaserelType(rel, file->ctx.config.machine);
if (ty == IMAGE_REL_BASED_ABSOLUTE)
continue;
Symbol *target = file->getSymbol(rel.SymbolTableIndex);
@@ -529,7 +564,8 @@ void SectionChunk::getBaserels(std::vector<Baserel> *res) {
// another DLL) This returns the size the relocation is supposed to update,
// in bits, or 0 if the relocation cannot be handled as a runtime pseudo
// relocation.
-static int getRuntimePseudoRelocSize(uint16_t type) {
+static int getRuntimePseudoRelocSize(uint16_t type,
+ llvm::COFF::MachineTypes machine) {
// Relocations that either contain an absolute address, or a plain
// relative offset, since the runtime pseudo reloc implementation
// adds 8/16/32/64 bit values to a memory address.
@@ -555,7 +591,7 @@ static int getRuntimePseudoRelocSize(uint16_t type) {
// the image, or temporarily changed at runtime with VirtualProtect.
// Since this only operates on direct address values, it doesn't work for
// ARM/ARM64 relocations, other than the plain ADDR32/ADDR64 relocations.
- switch (config->machine) {
+ switch (machine) {
case AMD64:
switch (type) {
case IMAGE_REL_AMD64_ADDR64:
@@ -612,7 +648,8 @@ void SectionChunk::getRuntimePseudoRelocs(
dyn_cast_or_null<Defined>(file->getSymbol(rel.SymbolTableIndex));
if (!target || !target->isRuntimePseudoReloc)
continue;
- int sizeInBits = getRuntimePseudoRelocSize(rel.Type);
+ int sizeInBits =
+ getRuntimePseudoRelocSize(rel.Type, file->ctx.config.machine);
if (sizeInBits == 0) {
error("unable to automatically import from " + target->getName() +
" with relocation type " +
@@ -718,7 +755,8 @@ void StringChunk::writeTo(uint8_t *buf) const {
buf[str.size()] = '\0';
}
-ImportThunkChunkX64::ImportThunkChunkX64(Defined *s) : ImportThunkChunk(s) {
+ImportThunkChunkX64::ImportThunkChunkX64(COFFLinkerContext &ctx, Defined *s)
+ : ImportThunkChunk(ctx, s) {
// Intel Optimization Manual says that all branch targets
// should be 16-byte aligned. MSVC linker does this too.
setAlignment(16);
@@ -731,14 +769,13 @@ void ImportThunkChunkX64::writeTo(uint8_t *buf) const {
}
void ImportThunkChunkX86::getBaserels(std::vector<Baserel> *res) {
- res->emplace_back(getRVA() + 2);
+ res->emplace_back(getRVA() + 2, ctx.config.machine);
}
void ImportThunkChunkX86::writeTo(uint8_t *buf) const {
memcpy(buf, importThunkX86, sizeof(importThunkX86));
// The first two bytes is a JMP instruction. Fill its operand.
- write32le(buf + 2,
- impSymbol->getRVA() + config->imageBase);
+ write32le(buf + 2, impSymbol->getRVA() + ctx.config.imageBase);
}
void ImportThunkChunkARM::getBaserels(std::vector<Baserel> *res) {
@@ -748,7 +785,7 @@ void ImportThunkChunkARM::getBaserels(std::vector<Baserel> *res) {
void ImportThunkChunkARM::writeTo(uint8_t *buf) const {
memcpy(buf, importThunkARM, sizeof(importThunkARM));
// Fix mov.w and mov.t operands.
- applyMOV32T(buf, impSymbol->getRVA() + config->imageBase);
+ applyMOV32T(buf, impSymbol->getRVA() + ctx.config.imageBase);
}
void ImportThunkChunkARM64::writeTo(uint8_t *buf) const {
@@ -766,12 +803,12 @@ const uint8_t armThunk[] = {
};
size_t RangeExtensionThunkARM::getSize() const {
- assert(config->machine == ARMNT);
+ assert(ctx.config.machine == ARMNT);
return sizeof(armThunk);
}
void RangeExtensionThunkARM::writeTo(uint8_t *buf) const {
- assert(config->machine == ARMNT);
+ assert(ctx.config.machine == ARMNT);
uint64_t offset = target->getRVA() - rva - 12;
memcpy(buf, armThunk, sizeof(armThunk));
applyMOV32T(buf, uint32_t(offset));
@@ -786,28 +823,33 @@ const uint8_t arm64Thunk[] = {
};
size_t RangeExtensionThunkARM64::getSize() const {
- assert(config->machine == ARM64);
+ assert(ctx.config.machine == ARM64);
return sizeof(arm64Thunk);
}
void RangeExtensionThunkARM64::writeTo(uint8_t *buf) const {
- assert(config->machine == ARM64);
+ assert(ctx.config.machine == ARM64);
memcpy(buf, arm64Thunk, sizeof(arm64Thunk));
applyArm64Addr(buf + 0, target->getRVA(), rva, 12);
applyArm64Imm(buf + 4, target->getRVA() & 0xfff, 0);
}
+LocalImportChunk::LocalImportChunk(COFFLinkerContext &c, Defined *s)
+ : sym(s), ctx(c) {
+ setAlignment(ctx.config.wordsize);
+}
+
void LocalImportChunk::getBaserels(std::vector<Baserel> *res) {
- res->emplace_back(getRVA());
+ res->emplace_back(getRVA(), ctx.config.machine);
}
-size_t LocalImportChunk::getSize() const { return config->wordsize; }
+size_t LocalImportChunk::getSize() const { return ctx.config.wordsize; }
void LocalImportChunk::writeTo(uint8_t *buf) const {
- if (config->is64()) {
- write64le(buf, sym->getRVA() + config->imageBase);
+ if (ctx.config.is64()) {
+ write64le(buf, sym->getRVA() + ctx.config.imageBase);
} else {
- write32le(buf, sym->getRVA() + config->imageBase);
+ write32le(buf, sym->getRVA() + ctx.config.imageBase);
}
}
@@ -927,8 +969,8 @@ void BaserelChunk::writeTo(uint8_t *buf) const {
memcpy(buf, data.data(), data.size());
}
-uint8_t Baserel::getDefaultType() {
- switch (config->machine) {
+uint8_t Baserel::getDefaultType(llvm::COFF::MachineTypes machine) {
+ switch (machine) {
case AMD64:
case ARM64:
return IMAGE_REL_BASED_DIR64;
@@ -986,10 +1028,10 @@ void MergeChunk::writeTo(uint8_t *buf) const {
}
// MinGW specific.
-size_t AbsolutePointerChunk::getSize() const { return config->wordsize; }
+size_t AbsolutePointerChunk::getSize() const { return ctx.config.wordsize; }
void AbsolutePointerChunk::writeTo(uint8_t *buf) const {
- if (config->is64()) {
+ if (ctx.config.is64()) {
write64le(buf, value);
} else {
write32le(buf, value);
diff --git a/lld/COFF/Chunks.h b/lld/COFF/Chunks.h
index ba2f0d43b726..e08531ed4066 100644
--- a/lld/COFF/Chunks.h
+++ b/lld/COFF/Chunks.h
@@ -238,13 +238,13 @@ class SectionChunk final : public Chunk {
bool isCOMDAT() const;
void applyRelocation(uint8_t *off, const coff_relocation &rel) const;
void applyRelX64(uint8_t *off, uint16_t type, OutputSection *os, uint64_t s,
- uint64_t p) const;
+ uint64_t p, uint64_t imageBase) const;
void applyRelX86(uint8_t *off, uint16_t type, OutputSection *os, uint64_t s,
- uint64_t p) const;
+ uint64_t p, uint64_t imageBase) const;
void applyRelARM(uint8_t *off, uint16_t type, OutputSection *os, uint64_t s,
- uint64_t p) const;
+ uint64_t p, uint64_t imageBase) const;
void applyRelARM64(uint8_t *off, uint16_t type, OutputSection *os, uint64_t s,
- uint64_t p) const;
+ uint64_t p, uint64_t imageBase) const;
void getRuntimePseudoRelocs(std::vector<RuntimePseudoReloc> &res);
@@ -490,24 +490,26 @@ static const uint8_t importThunkARM64[] = {
// contents will be a JMP instruction to some __imp_ symbol.
class ImportThunkChunk : public NonSectionChunk {
public:
- ImportThunkChunk(Defined *s)
- : NonSectionChunk(ImportThunkKind), impSymbol(s) {}
+ ImportThunkChunk(COFFLinkerContext &ctx, Defined *s)
+ : NonSectionChunk(ImportThunkKind), impSymbol(s), ctx(ctx) {}
static bool classof(const Chunk *c) { return c->kind() == ImportThunkKind; }
protected:
Defined *impSymbol;
+ COFFLinkerContext &ctx;
};
class ImportThunkChunkX64 : public ImportThunkChunk {
public:
- explicit ImportThunkChunkX64(Defined *s);
+ explicit ImportThunkChunkX64(COFFLinkerContext &ctx, Defined *s);
size_t getSize() const override { return sizeof(importThunkX86); }
void writeTo(uint8_t *buf) const override;
};
class ImportThunkChunkX86 : public ImportThunkChunk {
public:
- explicit ImportThunkChunkX86(Defined *s) : ImportThunkChunk(s) {}
+ explicit ImportThunkChunkX86(COFFLinkerContext &ctx, Defined *s)
+ : ImportThunkChunk(ctx, s) {}
size_t getSize() const override { return sizeof(importThunkX86); }
void getBaserels(std::vector<Baserel> *res) override;
void writeTo(uint8_t *buf) const override;
@@ -515,7 +517,8 @@ class ImportThunkChunkX86 : public ImportThunkChunk {
class ImportThunkChunkARM : public ImportThunkChunk {
public:
- explicit ImportThunkChunkARM(Defined *s) : ImportThunkChunk(s) {
+ explicit ImportThunkChunkARM(COFFLinkerContext &ctx, Defined *s)
+ : ImportThunkChunk(ctx, s) {
setAlignment(2);
}
size_t getSize() const override { return sizeof(importThunkARM); }
@@ -525,7 +528,8 @@ class ImportThunkChunkARM : public ImportThunkChunk {
class ImportThunkChunkARM64 : public ImportThunkChunk {
public:
- explicit ImportThunkChunkARM64(Defined *s) : ImportThunkChunk(s) {
+ explicit ImportThunkChunkARM64(COFFLinkerContext &ctx, Defined *s)
+ : ImportThunkChunk(ctx, s) {
setAlignment(4);
}
size_t getSize() const override { return sizeof(importThunkARM64); }
@@ -534,35 +538,46 @@ class ImportThunkChunkARM64 : public ImportThunkChunk {
class RangeExtensionThunkARM : public NonSectionChunk {
public:
- explicit RangeExtensionThunkARM(Defined *t) : target(t) { setAlignment(2); }
+ explicit RangeExtensionThunkARM(COFFLinkerContext &ctx, Defined *t)
+ : target(t), ctx(ctx) {
+ setAlignment(2);
+ }
size_t getSize() const override;
void writeTo(uint8_t *buf) const override;
Defined *target;
+
+private:
+ COFFLinkerContext &ctx;
};
class RangeExtensionThunkARM64 : public NonSectionChunk {
public:
- explicit RangeExtensionThunkARM64(Defined *t) : target(t) { setAlignment(4); }
+ explicit RangeExtensionThunkARM64(COFFLinkerContext &ctx, Defined *t)
+ : target(t), ctx(ctx) {
+ setAlignment(4);
+ }
size_t getSize() const override;
void writeTo(uint8_t *buf) const override;
Defined *target;
+
+private:
+ COFFLinkerContext &ctx;
};
// Windows-specific.
// See comments for DefinedLocalImport class.
class LocalImportChunk : public NonSectionChunk {
public:
- explicit LocalImportChunk(Defined *s) : sym(s) {
- setAlignment(config->wordsize);
- }
+ explicit LocalImportChunk(COFFLinkerContext &ctx, Defined *s);
size_t getSize() const override;
void getBaserels(std::vector<Baserel> *res) override;
void writeTo(uint8_t *buf) const override;
private:
Defined *sym;
+ COFFLinkerContext &ctx;
};
// Duplicate RVAs are not allowed in RVA tables, so unique symbols by chunk and
@@ -629,8 +644,9 @@ class BaserelChunk : public NonSectionChunk {
class Baserel {
public:
Baserel(uint32_t v, uint8_t ty) : rva(v), type(ty) {}
- explicit Baserel(uint32_t v) : Baserel(v, getDefaultType()) {}
- uint8_t getDefaultType();
+ explicit Baserel(uint32_t v, llvm::COFF::MachineTypes machine)
+ : Baserel(v, getDefaultType(machine)) {}
+ uint8_t getDefaultType(llvm::COFF::MachineTypes machine);
uint32_t rva;
uint8_t type;
@@ -669,7 +685,8 @@ class PseudoRelocTableChunk : public NonSectionChunk {
// MinGW specific. A Chunk that contains one pointer-sized absolute value.
class AbsolutePointerChunk : public NonSectionChunk {
public:
- AbsolutePointerChunk(uint64_t value) : value(value) {
+ AbsolutePointerChunk(COFFLinkerContext &ctx, uint64_t value)
+ : value(value), ctx(ctx) {
setAlignment(getSize());
}
size_t getSize() const override;
@@ -677,6 +694,7 @@ class AbsolutePointerChunk : public NonSectionChunk {
private:
uint64_t value;
+ COFFLinkerContext &ctx;
};
// Return true if this file has the hotpatch flag set to true in the S_COMPILE3
@@ -697,6 +715,19 @@ void applyArm64Addr(uint8_t *off, uint64_t s, uint64_t p, int shift);
void applyArm64Imm(uint8_t *off, uint64_t imm, uint32_t rangeLimit);
void applyArm64Branch26(uint8_t *off, int64_t v);
+// Convenience class for initializing a SectionChunk with specific flags.
+class FakeSectionChunk {
+public:
+ FakeSectionChunk(const coff_section *section) : chunk(nullptr, section) {
+ // Comdats from LTO files can't be fully treated as regular comdats
+ // at this point; we don't know what size or contents they are going to
+ // have, so we can't do proper checking of such aspects of them.
+ chunk.selection = llvm::COFF::IMAGE_COMDAT_SELECT_ANY;
+ }
+
+ SectionChunk chunk;
+};
+
} // namespace lld::coff
namespace llvm {
diff --git a/lld/COFF/Config.h b/lld/COFF/Config.h
index c7f10f253b8a..4711573a5b76 100644
--- a/lld/COFF/Config.h
+++ b/lld/COFF/Config.h
@@ -96,7 +96,7 @@ enum class ICFLevel {
// Global configuration.
struct Configuration {
enum ManifestKind { Default, SideBySide, Embed, No };
- bool is64() { return machine == AMD64 || machine == ARM64; }
+ bool is64() const { return machine == AMD64 || machine == ARM64; }
llvm::COFF::MachineTypes machine = IMAGE_FILE_MACHINE_UNKNOWN;
size_t wordsize;
@@ -292,8 +292,6 @@ struct Configuration {
bool writeCheckSum = false;
};
-extern std::unique_ptr<Configuration> config;
-
} // namespace lld::coff
#endif
diff --git a/lld/COFF/DLL.cpp b/lld/COFF/DLL.cpp
index 58c3eff4a72c..b6e91ea1c197 100644
--- a/lld/COFF/DLL.cpp
+++ b/lld/COFF/DLL.cpp
@@ -61,19 +61,23 @@ class HintNameChunk : public NonSectionChunk {
// A chunk for the import descriptor table.
class LookupChunk : public NonSectionChunk {
public:
- explicit LookupChunk(Chunk *c) : hintName(c) {
- setAlignment(config->wordsize);
+ explicit LookupChunk(COFFLinkerContext &ctx, Chunk *c)
+ : hintName(c), ctx(ctx) {
+ setAlignment(ctx.config.wordsize);
}
- size_t getSize() const override { return config->wordsize; }
+ size_t getSize() const override { return ctx.config.wordsize; }
void writeTo(uint8_t *buf) const override {
- if (config->is64())
+ if (ctx.config.is64())
write64le(buf, hintName->getRVA());
else
write32le(buf, hintName->getRVA());
}
Chunk *hintName;
+
+private:
+ COFFLinkerContext &ctx;
};
// A chunk for the import descriptor table.
@@ -81,15 +85,16 @@ class LookupChunk : public NonSectionChunk {
// See Microsoft PE/COFF spec 7.1. Import Header for details.
class OrdinalOnlyChunk : public NonSectionChunk {
public:
- explicit OrdinalOnlyChunk(uint16_t v) : ordinal(v) {
- setAlignment(config->wordsize);
+ explicit OrdinalOnlyChunk(COFFLinkerContext &c, uint16_t v)
+ : ordinal(v), ctx(c) {
+ setAlignment(ctx.config.wordsize);
}
- size_t getSize() const override { return config->wordsize; }
+ size_t getSize() const override { return ctx.config.wordsize; }
void writeTo(uint8_t *buf) const override {
// An import-by-ordinal slot has MSB 1 to indicate that
// this is import-by-ordinal (and not import-by-name).
- if (config->is64()) {
+ if (ctx.config.is64()) {
write64le(buf, (1ULL << 63) | ordinal);
} else {
write32le(buf, (1ULL << 31) | ordinal);
@@ -97,6 +102,9 @@ class OrdinalOnlyChunk : public NonSectionChunk {
}
uint16_t ordinal;
+
+private:
+ COFFLinkerContext &ctx;
};
// A chunk for the import descriptor table.
@@ -135,14 +143,15 @@ class NullChunk : public NonSectionChunk {
};
static std::vector<std::vector<DefinedImportData *>>
-binImports(const std::vector<DefinedImportData *> &imports) {
+binImports(COFFLinkerContext &ctx,
+ const std::vector<DefinedImportData *> &imports) {
// Group DLL-imported symbols by DLL name because that's how
// symbols are laid out in the import descriptor table.
- auto less = [](const std::string &a, const std::string &b) {
- return config->dllOrder[a] < config->dllOrder[b];
+ auto less = [&ctx](const std::string &a, const std::string &b) {
+ return ctx.config.dllOrder[a] < ctx.config.dllOrder[b];
};
- std::map<std::string, std::vector<DefinedImportData *>,
- bool(*)(const std::string &, const std::string &)> m(less);
+ std::map<std::string, std::vector<DefinedImportData *>, decltype(less)> m(
+ less);
for (DefinedImportData *sym : imports)
m[sym->getDLLName().lower()].push_back(sym);
@@ -325,47 +334,56 @@ class TailMergeChunkX64 : public NonSectionChunk {
class ThunkChunkX86 : public NonSectionChunk {
public:
- ThunkChunkX86(Defined *i, Chunk *tm) : imp(i), tailMerge(tm) {}
+ ThunkChunkX86(COFFLinkerContext &ctx, Defined *i, Chunk *tm)
+ : imp(i), tailMerge(tm), ctx(ctx) {}
size_t getSize() const override { return sizeof(thunkX86); }
void writeTo(uint8_t *buf) const override {
memcpy(buf, thunkX86, sizeof(thunkX86));
- write32le(buf + 1, imp->getRVA() + config->imageBase);
+ write32le(buf + 1, imp->getRVA() + ctx.config.imageBase);
write32le(buf + 6, tailMerge->getRVA() - rva - 10);
}
void getBaserels(std::vector<Baserel> *res) override {
- res->emplace_back(rva + 1);
+ res->emplace_back(rva + 1, ctx.config.machine);
}
Defined *imp = nullptr;
Chunk *tailMerge = nullptr;
+
+private:
+ const COFFLinkerContext &ctx;
};
class TailMergeChunkX86 : public NonSectionChunk {
public:
- TailMergeChunkX86(Chunk *d, Defined *h) : desc(d), helper(h) {}
+ TailMergeChunkX86(COFFLinkerContext &ctx, Chunk *d, Defined *h)
+ : desc(d), helper(h), ctx(ctx) {}
size_t getSize() const override { return sizeof(tailMergeX86); }
void writeTo(uint8_t *buf) const override {
memcpy(buf, tailMergeX86, sizeof(tailMergeX86));
- write32le(buf + 4, desc->getRVA() + config->imageBase);
+ write32le(buf + 4, desc->getRVA() + ctx.config.imageBase);
write32le(buf + 9, helper->getRVA() - rva - 13);
}
void getBaserels(std::vector<Baserel> *res) override {
- res->emplace_back(rva + 4);
+ res->emplace_back(rva + 4, ctx.config.machine);
}
Chunk *desc = nullptr;
Defined *helper = nullptr;
+
+private:
+ const COFFLinkerContext &ctx;
};
class ThunkChunkARM : public NonSectionChunk {
public:
- ThunkChunkARM(Defined *i, Chunk *tm) : imp(i), tailMerge(tm) {
+ ThunkChunkARM(COFFLinkerContext &ctx, Defined *i, Chunk *tm)
+ : imp(i), tailMerge(tm), ctx(ctx) {
setAlignment(2);
}
@@ -373,7 +391,7 @@ class ThunkChunkARM : public NonSectionChunk {
void writeTo(uint8_t *buf) const override {
memcpy(buf, thunkARM, sizeof(thunkARM));
- applyMOV32T(buf + 0, imp->getRVA() + config->imageBase);
+ applyMOV32T(buf + 0, imp->getRVA() + ctx.config.imageBase);
applyBranch24T(buf + 8, tailMerge->getRVA() - rva - 12);
}
@@ -383,11 +401,15 @@ class ThunkChunkARM : public NonSectionChunk {
Defined *imp = nullptr;
Chunk *tailMerge = nullptr;
+
+private:
+ const COFFLinkerContext &ctx;
};
class TailMergeChunkARM : public NonSectionChunk {
public:
- TailMergeChunkARM(Chunk *d, Defined *h) : desc(d), helper(h) {
+ TailMergeChunkARM(COFFLinkerContext &ctx, Chunk *d, Defined *h)
+ : desc(d), helper(h), ctx(ctx) {
setAlignment(2);
}
@@ -395,7 +417,7 @@ class TailMergeChunkARM : public NonSectionChunk {
void writeTo(uint8_t *buf) const override {
memcpy(buf, tailMergeARM, sizeof(tailMergeARM));
- applyMOV32T(buf + 14, desc->getRVA() + config->imageBase);
+ applyMOV32T(buf + 14, desc->getRVA() + ctx.config.imageBase);
applyBranch24T(buf + 22, helper->getRVA() - rva - 26);
}
@@ -405,6 +427,9 @@ class TailMergeChunkARM : public NonSectionChunk {
Chunk *desc = nullptr;
Defined *helper = nullptr;
+
+private:
+ const COFFLinkerContext &ctx;
};
class ThunkChunkARM64 : public NonSectionChunk {
@@ -448,28 +473,32 @@ class TailMergeChunkARM64 : public NonSectionChunk {
// A chunk for the import descriptor table.
class DelayAddressChunk : public NonSectionChunk {
public:
- explicit DelayAddressChunk(Chunk *c) : thunk(c) {
- setAlignment(config->wordsize);
+ explicit DelayAddressChunk(COFFLinkerContext &ctx, Chunk *c)
+ : thunk(c), ctx(ctx) {
+ setAlignment(ctx.config.wordsize);
}
- size_t getSize() const override { return config->wordsize; }
+ size_t getSize() const override { return ctx.config.wordsize; }
void writeTo(uint8_t *buf) const override {
- if (config->is64()) {
- write64le(buf, thunk->getRVA() + config->imageBase);
+ if (ctx.config.is64()) {
+ write64le(buf, thunk->getRVA() + ctx.config.imageBase);
} else {
uint32_t bit = 0;
// Pointer to thumb code must have the LSB set, so adjust it.
- if (config->machine == ARMNT)
+ if (ctx.config.machine == ARMNT)
bit = 1;
- write32le(buf, (thunk->getRVA() + config->imageBase) | bit);
+ write32le(buf, (thunk->getRVA() + ctx.config.imageBase) | bit);
}
}
void getBaserels(std::vector<Baserel> *res) override {
- res->emplace_back(rva);
+ res->emplace_back(rva, ctx.config.machine);
}
Chunk *thunk;
+
+private:
+ const COFFLinkerContext &ctx;
};
// Export table
@@ -509,19 +538,20 @@ class ExportDirectoryChunk : public NonSectionChunk {
class AddressTableChunk : public NonSectionChunk {
public:
- explicit AddressTableChunk(size_t maxOrdinal) : size(maxOrdinal) {}
+ explicit AddressTableChunk(COFFLinkerContext &ctx, size_t maxOrdinal)
+ : size(maxOrdinal), ctx(ctx) {}
size_t getSize() const override { return size * 4; }
void writeTo(uint8_t *buf) const override {
memset(buf, 0, getSize());
- for (const Export &e : config->exports) {
+ for (const Export &e : ctx.config.exports) {
assert(e.ordinal != 0 && "Export symbol has invalid ordinal");
// OrdinalBase is 1, so subtract 1 to get the index.
uint8_t *p = buf + (e.ordinal - 1) * 4;
uint32_t bit = 0;
// Pointer to thumb code must have the LSB set, so adjust it.
- if (config->machine == ARMNT && !e.data)
+ if (ctx.config.machine == ARMNT && !e.data)
bit = 1;
if (e.forwardChunk) {
write32le(p, e.forwardChunk->getRVA() | bit);
@@ -535,6 +565,7 @@ class AddressTableChunk : public NonSectionChunk {
private:
size_t size;
+ const COFFLinkerContext &ctx;
};
class NamePointersChunk : public NonSectionChunk {
@@ -555,11 +586,12 @@ class NamePointersChunk : public NonSectionChunk {
class ExportOrdinalChunk : public NonSectionChunk {
public:
- explicit ExportOrdinalChunk(size_t i) : size(i) {}
+ explicit ExportOrdinalChunk(const COFFLinkerContext &ctx, size_t i)
+ : size(i), ctx(ctx) {}
size_t getSize() const override { return size * 2; }
void writeTo(uint8_t *buf) const override {
- for (Export &e : config->exports) {
+ for (const Export &e : ctx.config.exports) {
if (e.noname)
continue;
assert(e.ordinal != 0 && "Export symbol has invalid ordinal");
@@ -571,12 +603,13 @@ class ExportOrdinalChunk : public NonSectionChunk {
private:
size_t size;
+ const COFFLinkerContext &ctx;
};
} // anonymous namespace
-void IdataContents::create() {
- std::vector<std::vector<DefinedImportData *>> v = binImports(imports);
+void IdataContents::create(COFFLinkerContext &ctx) {
+ std::vector<std::vector<DefinedImportData *>> v = binImports(ctx, imports);
// Create .idata contents for each DLL.
for (std::vector<DefinedImportData *> &syms : v) {
@@ -588,18 +621,18 @@ void IdataContents::create() {
for (DefinedImportData *s : syms) {
uint16_t ord = s->getOrdinal();
if (s->getExternalName().empty()) {
- lookups.push_back(make<OrdinalOnlyChunk>(ord));
- addresses.push_back(make<OrdinalOnlyChunk>(ord));
+ lookups.push_back(make<OrdinalOnlyChunk>(ctx, ord));
+ addresses.push_back(make<OrdinalOnlyChunk>(ctx, ord));
continue;
}
auto *c = make<HintNameChunk>(s->getExternalName(), ord);
- lookups.push_back(make<LookupChunk>(c));
- addresses.push_back(make<LookupChunk>(c));
+ lookups.push_back(make<LookupChunk>(ctx, c));
+ addresses.push_back(make<LookupChunk>(ctx, c));
hints.push_back(c);
}
// Terminate with null values.
- lookups.push_back(make<NullChunk>(config->wordsize));
- addresses.push_back(make<NullChunk>(config->wordsize));
+ lookups.push_back(make<NullChunk>(ctx.config.wordsize));
+ addresses.push_back(make<NullChunk>(ctx.config.wordsize));
for (int i = 0, e = syms.size(); i < e; ++i)
syms[i]->setLocation(addresses[base + i]);
@@ -635,9 +668,9 @@ uint64_t DelayLoadContents::getDirSize() {
return dirs.size() * sizeof(delay_import_directory_table_entry);
}
-void DelayLoadContents::create(COFFLinkerContext &ctx, Defined *h) {
+void DelayLoadContents::create(Defined *h) {
helper = h;
- std::vector<std::vector<DefinedImportData *>> v = binImports(imports);
+ std::vector<std::vector<DefinedImportData *>> v = binImports(ctx, imports);
// Create .didat contents for each DLL.
for (std::vector<DefinedImportData *> &syms : v) {
@@ -649,15 +682,15 @@ void DelayLoadContents::create(COFFLinkerContext &ctx, Defined *h) {
Chunk *tm = newTailMergeChunk(dir);
for (DefinedImportData *s : syms) {
Chunk *t = newThunkChunk(s, tm);
- auto *a = make<DelayAddressChunk>(t);
+ auto *a = make<DelayAddressChunk>(ctx, t);
addresses.push_back(a);
thunks.push_back(t);
StringRef extName = s->getExternalName();
if (extName.empty()) {
- names.push_back(make<OrdinalOnlyChunk>(s->getOrdinal()));
+ names.push_back(make<OrdinalOnlyChunk>(ctx, s->getOrdinal()));
} else {
auto *c = make<HintNameChunk>(extName, 0);
- names.push_back(make<LookupChunk>(c));
+ names.push_back(make<LookupChunk>(ctx, c));
hintNames.push_back(c);
// Add a syntentic symbol for this load thunk, using the "__imp___load"
// prefix, in case this thunk needs to be added to the list of valid
@@ -692,13 +725,13 @@ void DelayLoadContents::create(COFFLinkerContext &ctx, Defined *h) {
}
Chunk *DelayLoadContents::newTailMergeChunk(Chunk *dir) {
- switch (config->machine) {
+ switch (ctx.config.machine) {
case AMD64:
return make<TailMergeChunkX64>(dir, helper);
case I386:
- return make<TailMergeChunkX86>(dir, helper);
+ return make<TailMergeChunkX86>(ctx, dir, helper);
case ARMNT:
- return make<TailMergeChunkARM>(dir, helper);
+ return make<TailMergeChunkARM>(ctx, dir, helper);
case ARM64:
return make<TailMergeChunkARM64>(dir, helper);
default:
@@ -708,13 +741,13 @@ Chunk *DelayLoadContents::newTailMergeChunk(Chunk *dir) {
Chunk *DelayLoadContents::newThunkChunk(DefinedImportData *s,
Chunk *tailMerge) {
- switch (config->machine) {
+ switch (ctx.config.machine) {
case AMD64:
return make<ThunkChunkX64>(s, tailMerge);
case I386:
- return make<ThunkChunkX86>(s, tailMerge);
+ return make<ThunkChunkX86>(ctx, s, tailMerge);
case ARMNT:
- return make<ThunkChunkARM>(s, tailMerge);
+ return make<ThunkChunkARM>(ctx, s, tailMerge);
case ARM64:
return make<ThunkChunkARM64>(s, tailMerge);
default:
@@ -722,20 +755,20 @@ Chunk *DelayLoadContents::newThunkChunk(DefinedImportData *s,
}
}
-EdataContents::EdataContents() {
+EdataContents::EdataContents(COFFLinkerContext &ctx) : ctx(ctx) {
uint16_t maxOrdinal = 0;
- for (Export &e : config->exports)
+ for (Export &e : ctx.config.exports)
maxOrdinal = std::max(maxOrdinal, e.ordinal);
- auto *dllName = make<StringChunk>(sys::path::filename(config->outputFile));
- auto *addressTab = make<AddressTableChunk>(maxOrdinal);
+ auto *dllName = make<StringChunk>(sys::path::filename(ctx.config.outputFile));
+ auto *addressTab = make<AddressTableChunk>(ctx, maxOrdinal);
std::vector<Chunk *> names;
- for (Export &e : config->exports)
+ for (Export &e : ctx.config.exports)
if (!e.noname)
names.push_back(make<StringChunk>(e.exportName));
std::vector<Chunk *> forwards;
- for (Export &e : config->exports) {
+ for (Export &e : ctx.config.exports) {
if (e.forwardTo.empty())
continue;
e.forwardChunk = make<StringChunk>(e.forwardTo);
@@ -743,7 +776,7 @@ EdataContents::EdataContents() {
}
auto *nameTab = make<NamePointersChunk>(names);
- auto *ordinalTab = make<ExportOrdinalChunk>(names.size());
+ auto *ordinalTab = make<ExportOrdinalChunk>(ctx, names.size());
auto *dir = make<ExportDirectoryChunk>(maxOrdinal, names.size(), dllName,
addressTab, nameTab, ordinalTab);
chunks.push_back(dir);
diff --git a/lld/COFF/DLL.h b/lld/COFF/DLL.h
index a5de351897d2..f90fd575efc1 100644
--- a/lld/COFF/DLL.h
+++ b/lld/COFF/DLL.h
@@ -23,7 +23,7 @@ class IdataContents {
void add(DefinedImportData *sym) { imports.push_back(sym); }
bool empty() { return imports.empty(); }
- void create();
+ void create(COFFLinkerContext &ctx);
std::vector<DefinedImportData *> imports;
std::vector<Chunk *> dirs;
@@ -37,9 +37,10 @@ class IdataContents {
// DelayLoadContents creates all chunks for the delay-load DLL import table.
class DelayLoadContents {
public:
+ DelayLoadContents(COFFLinkerContext &ctx) : ctx(ctx) {}
void add(DefinedImportData *sym) { imports.push_back(sym); }
bool empty() { return imports.empty(); }
- void create(COFFLinkerContext &ctx, Defined *helper);
+ void create(Defined *helper);
std::vector<Chunk *> getChunks();
std::vector<Chunk *> getDataChunks();
ArrayRef<Chunk *> getCodeChunks() { return thunks; }
@@ -60,19 +61,23 @@ class DelayLoadContents {
std::vector<Chunk *> hintNames;
std::vector<Chunk *> thunks;
std::vector<Chunk *> dllNames;
+
+ COFFLinkerContext &ctx;
};
// Windows-specific.
// EdataContents creates all chunks for the DLL export table.
class EdataContents {
public:
- EdataContents();
+ EdataContents(COFFLinkerContext &ctx);
std::vector<Chunk *> chunks;
uint64_t getRVA() { return chunks[0]->getRVA(); }
uint64_t getSize() {
return chunks.back()->getRVA() + chunks.back()->getSize() - getRVA();
}
+
+ COFFLinkerContext &ctx;
};
} // namespace lld::coff
diff --git a/lld/COFF/DebugTypes.cpp b/lld/COFF/DebugTypes.cpp
index 66b9b99199b2..811889c6d246 100644
--- a/lld/COFF/DebugTypes.cpp
+++ b/lld/COFF/DebugTypes.cpp
@@ -235,7 +235,7 @@ void TpiSource::remapRecord(MutableArrayRef<uint8_t> rec,
reinterpret_cast<TypeIndex *>(contents.data() + ref.Offset), ref.Count);
for (TypeIndex &ti : indices) {
if (!remapTypeIndex(ti, ref.Kind)) {
- if (config->verbose) {
+ if (ctx.config.verbose) {
uint16_t kind =
reinterpret_cast<const RecordPrefix *>(rec.data())->RecordKind;
StringRef fname = file ? file->getName() : "<unknown PDB>";
@@ -305,7 +305,7 @@ getHashesFromDebugH(ArrayRef<uint8_t> debugH) {
// Merge .debug$T for a generic object file.
Error TpiSource::mergeDebugT(TypeMerger *m) {
- assert(!config->debugGHashes &&
+ assert(!ctx.config.debugGHashes &&
"use remapTpiWithGHashes when ghash is enabled");
CVTypeArray types;
@@ -329,7 +329,7 @@ Error TpiSource::mergeDebugT(TypeMerger *m) {
tpiMap = indexMapStorage;
ipiMap = indexMapStorage;
- if (config->showSummary) {
+ if (ctx.config.showSummary) {
nbTypeRecords = indexMapStorage.size() - nbHeadIndices;
nbTypeRecordsBytes = reader.getLength();
// Count how many times we saw each type record in our input. This
@@ -356,7 +356,7 @@ Error TpiSource::mergeDebugT(TypeMerger *m) {
// Merge types from a type server PDB.
Error TypeServerSource::mergeDebugT(TypeMerger *m) {
- assert(!config->debugGHashes &&
+ assert(!ctx.config.debugGHashes &&
"use remapTpiWithGHashes when ghash is enabled");
pdb::PDBFile &pdbFile = pdbInputFile->session->getPDBFile();
@@ -385,7 +385,7 @@ Error TypeServerSource::mergeDebugT(TypeMerger *m) {
ipiMap = ipiSrc->indexMapStorage;
}
- if (config->showSummary) {
+ if (ctx.config.showSummary) {
nbTypeRecords = tpiMap.size() + ipiMap.size();
nbTypeRecordsBytes =
expectedTpi->typeArray().getUnderlyingStream().getLength() +
@@ -727,14 +727,14 @@ void TpiSource::mergeUniqueTypeRecords(ArrayRef<uint8_t> typeRecords,
}
void TpiSource::remapTpiWithGHashes(GHashState *g) {
- assert(config->debugGHashes && "ghashes must be enabled");
+ assert(ctx.config.debugGHashes && "ghashes must be enabled");
fillMapFromGHashes(g);
tpiMap = indexMapStorage;
ipiMap = indexMapStorage;
mergeUniqueTypeRecords(file->debugTypes);
// TODO: Free all unneeded ghash resources now that we have a full index map.
- if (config->showSummary) {
+ if (ctx.config.showSummary) {
nbTypeRecords = ghashes.size();
nbTypeRecordsBytes = file->debugTypes.size();
}
@@ -787,7 +787,7 @@ static ArrayRef<uint8_t> typeArrayToBytes(const CVTypeArray &types) {
// Merge types from a type server PDB.
void TypeServerSource::remapTpiWithGHashes(GHashState *g) {
- assert(config->debugGHashes && "ghashes must be enabled");
+ assert(ctx.config.debugGHashes && "ghashes must be enabled");
// IPI merging depends on TPI, so do TPI first, then do IPI. No need to
// propagate errors, those should've been handled during ghash loading.
@@ -805,13 +805,13 @@ void TypeServerSource::remapTpiWithGHashes(GHashState *g) {
ipiSrc->ipiMap = ipiMap;
ipiSrc->mergeUniqueTypeRecords(typeArrayToBytes(ipi.typeArray()));
- if (config->showSummary) {
+ if (ctx.config.showSummary) {
nbTypeRecords = ipiSrc->ghashes.size();
nbTypeRecordsBytes = ipi.typeArray().getUnderlyingStream().getLength();
}
}
- if (config->showSummary) {
+ if (ctx.config.showSummary) {
nbTypeRecords += ghashes.size();
nbTypeRecordsBytes += tpi.typeArray().getUnderlyingStream().getLength();
}
@@ -898,7 +898,7 @@ void UsePrecompSource::remapTpiWithGHashes(GHashState *g) {
mergeUniqueTypeRecords(file->debugTypes,
TypeIndex(precompDependency.getStartTypeIndex() +
precompDependency.getTypesCount()));
- if (config->showSummary) {
+ if (ctx.config.showSummary) {
nbTypeRecords = ghashes.size();
nbTypeRecordsBytes = file->debugTypes.size();
}
diff --git a/lld/COFF/Driver.cpp b/lld/COFF/Driver.cpp
index 8c73e25d5630..0a153c8f6cb7 100644
--- a/lld/COFF/Driver.cpp
+++ b/lld/COFF/Driver.cpp
@@ -61,9 +61,6 @@ using namespace llvm::sys;
namespace lld::coff {
-std::unique_ptr<Configuration> config;
-std::unique_ptr<LinkerDriver> driver;
-
bool link(ArrayRef<const char *> args, llvm::raw_ostream &stdoutOS,
llvm::raw_ostream &stderrOS, bool exitEarly, bool disableOutput) {
// This driver-specific context will be freed later by lldMain().
@@ -74,10 +71,7 @@ bool link(ArrayRef<const char *> args, llvm::raw_ostream &stdoutOS,
ctx->e.errorLimitExceededMsg = "too many errors emitted, stopping now"
" (use /errorlimit:0 to see all errors)";
- config = std::make_unique<Configuration>();
- driver = std::make_unique<LinkerDriver>(*ctx);
-
- driver->linkerMain(args);
+ ctx->driver.linkerMain(args);
return errorCount() == 0;
}
@@ -98,11 +92,11 @@ static std::pair<StringRef, StringRef> getOldNewOptions(opt::InputArgList &args,
// Drop directory components and replace extension with
// ".exe", ".dll" or ".sys".
-static std::string getOutputPath(StringRef path) {
+static std::string getOutputPath(StringRef path, bool isDll, bool isDriver) {
StringRef ext = ".exe";
- if (config->dll)
+ if (isDll)
ext = ".dll";
- else if (config->driver)
+ else if (isDriver)
ext = ".sys";
return (sys::path::stem(path) + ext).str();
@@ -146,15 +140,15 @@ static std::future<MBErrPair> createFutureForFile(std::string path) {
}
// Symbol names are mangled by prepending "_" on x86.
-static StringRef mangle(StringRef sym) {
- assert(config->machine != IMAGE_FILE_MACHINE_UNKNOWN);
- if (config->machine == I386)
+StringRef LinkerDriver::mangle(StringRef sym) {
+ assert(ctx.config.machine != IMAGE_FILE_MACHINE_UNKNOWN);
+ if (ctx.config.machine == I386)
return saver().save("_" + sym);
return sym;
}
-static llvm::Triple::ArchType getArch() {
- switch (config->machine) {
+llvm::Triple::ArchType LinkerDriver::getArch() {
+ switch (ctx.config.machine) {
case I386:
return llvm::Triple::ArchType::x86;
case AMD64:
@@ -177,9 +171,9 @@ MemoryBufferRef LinkerDriver::takeBuffer(std::unique_ptr<MemoryBuffer> mb) {
MemoryBufferRef mbref = *mb;
make<std::unique_ptr<MemoryBuffer>>(std::move(mb)); // take ownership
- if (driver->tar)
- driver->tar->append(relativeToRoot(mbref.getBufferIdentifier()),
- mbref.getBuffer());
+ if (ctx.driver.tar)
+ ctx.driver.tar->append(relativeToRoot(mbref.getBufferIdentifier()),
+ mbref.getBuffer());
return mbref;
}
@@ -223,7 +217,7 @@ void LinkerDriver::addBuffer(std::unique_ptr<MemoryBuffer> mb,
error(filename + ": is not a native COFF file. Recompile without /GL");
break;
case file_magic::pecoff_executable:
- if (config->mingw) {
+ if (ctx.config.mingw) {
ctx.symtab.addFile(make<DLLFile>(ctx, mbref));
break;
}
@@ -254,12 +248,12 @@ void LinkerDriver::enqueuePath(StringRef path, bool wholeArchive, bool lazy) {
// the option `/nodefaultlib` than a reference to a file in the root
// directory.
std::string nearest;
- if (optTable.findNearest(pathStr, nearest) > 1)
+ if (ctx.optTable.findNearest(pathStr, nearest) > 1)
error(msg);
else
error(msg + "; did you mean '" + nearest + "'");
} else
- driver->addBuffer(std::move(mbOrErr.first), wholeArchive, lazy);
+ ctx.driver.addBuffer(std::move(mbOrErr.first), wholeArchive, lazy);
});
}
@@ -300,8 +294,8 @@ void LinkerDriver::enqueueArchiveMember(const Archive::Child &c,
auto reportBufferError = [=](Error &&e, StringRef childName) {
fatal("could not get the buffer for the member defining symbol " +
- toCOFFString(sym) + ": " + parentName + "(" + childName + "): " +
- toString(std::move(e)));
+ toCOFFString(ctx, sym) + ": " + parentName + "(" + childName +
+ "): " + toString(std::move(e)));
};
if (!c.getParent()->isThin()) {
@@ -311,16 +305,16 @@ void LinkerDriver::enqueueArchiveMember(const Archive::Child &c,
reportBufferError(mbOrErr.takeError(), check(c.getFullName()));
MemoryBufferRef mb = mbOrErr.get();
enqueueTask([=]() {
- driver->addArchiveBuffer(mb, toCOFFString(sym), parentName,
- offsetInArchive);
+ ctx.driver.addArchiveBuffer(mb, toCOFFString(ctx, sym), parentName,
+ offsetInArchive);
});
return;
}
- std::string childName = CHECK(
- c.getFullName(),
- "could not get the filename for the member defining symbol " +
- toCOFFString(sym));
+ std::string childName =
+ CHECK(c.getFullName(),
+ "could not get the filename for the member defining symbol " +
+ toCOFFString(ctx, sym));
auto future = std::make_shared<std::future<MBErrPair>>(
createFutureForFile(childName));
enqueueTask([=]() {
@@ -329,14 +323,15 @@ void LinkerDriver::enqueueArchiveMember(const Archive::Child &c,
reportBufferError(errorCodeToError(mbOrErr.second), childName);
// Pass empty string as archive name so that the original filename is
// used as the buffer identifier.
- driver->addArchiveBuffer(takeBuffer(std::move(mbOrErr.first)),
- toCOFFString(sym), "", /*OffsetInArchive=*/0);
+ ctx.driver.addArchiveBuffer(takeBuffer(std::move(mbOrErr.first)),
+ toCOFFString(ctx, sym), "",
+ /*OffsetInArchive=*/0);
});
}
-static bool isDecorated(StringRef sym) {
+bool LinkerDriver::isDecorated(StringRef sym) {
return sym.startswith("@") || sym.contains("@@") || sym.startswith("?") ||
- (!config->mingw && sym.contains('@'));
+ (!ctx.config.mingw && sym.contains('@'));
}
// Parses .drectve section contents and returns a list of files
@@ -348,7 +343,7 @@ void LinkerDriver::parseDirectives(InputFile *file) {
log("Directives: " + toString(file) + ": " + s);
- ArgParser parser;
+ ArgParser parser(ctx);
// .drectve is always tokenized using Windows shell rules.
// /EXPORT: option can appear too many times, processing in fastpath.
ParsedDirectives directives = parser.parseDirectives(s);
@@ -362,14 +357,14 @@ void LinkerDriver::parseDirectives(InputFile *file) {
continue;
Export exp = parseExport(e);
- if (config->machine == I386 && config->mingw) {
+ if (ctx.config.machine == I386 && ctx.config.mingw) {
if (!isDecorated(exp.name))
exp.name = saver().save("_" + exp.name);
if (!exp.extName.empty() && !isDecorated(exp.extName))
exp.extName = saver().save("_" + exp.extName);
}
exp.directives = true;
- config->exports.push_back(exp);
+ ctx.config.exports.push_back(exp);
}
// Handle /include: in bulk.
@@ -398,7 +393,7 @@ void LinkerDriver::parseDirectives(InputFile *file) {
enqueuePath(*path, false, false);
break;
case OPT_entry:
- config->entry = addUndefined(mangle(arg->getValue()));
+ ctx.config.entry = addUndefined(mangle(arg->getValue()));
break;
case OPT_failifmismatch:
checkFailIfMismatch(arg->getValue(), file);
@@ -407,32 +402,32 @@ void LinkerDriver::parseDirectives(InputFile *file) {
addUndefined(arg->getValue());
break;
case OPT_manifestdependency:
- config->manifestDependencies.insert(arg->getValue());
+ ctx.config.manifestDependencies.insert(arg->getValue());
break;
case OPT_merge:
parseMerge(arg->getValue());
break;
case OPT_nodefaultlib:
- config->noDefaultLibs.insert(doFindLib(arg->getValue()).lower());
+ ctx.config.noDefaultLibs.insert(doFindLib(arg->getValue()).lower());
break;
case OPT_release:
- config->writeCheckSum = true;
+ ctx.config.writeCheckSum = true;
break;
case OPT_section:
parseSection(arg->getValue());
break;
case OPT_stack:
- parseNumbers(arg->getValue(), &config->stackReserve,
- &config->stackCommit);
+ parseNumbers(arg->getValue(), &ctx.config.stackReserve,
+ &ctx.config.stackCommit);
break;
case OPT_subsystem: {
bool gotVersion = false;
- parseSubsystem(arg->getValue(), &config->subsystem,
- &config->majorSubsystemVersion,
- &config->minorSubsystemVersion, &gotVersion);
+ parseSubsystem(arg->getValue(), &ctx.config.subsystem,
+ &ctx.config.majorSubsystemVersion,
+ &ctx.config.minorSubsystemVersion, &gotVersion);
if (gotVersion) {
- config->majorOSVersion = config->majorSubsystemVersion;
- config->minorOSVersion = config->minorSubsystemVersion;
+ ctx.config.majorOSVersion = ctx.config.majorSubsystemVersion;
+ ctx.config.minorOSVersion = ctx.config.minorSubsystemVersion;
}
break;
}
@@ -451,9 +446,9 @@ void LinkerDriver::parseDirectives(InputFile *file) {
// Find file from search paths. You can omit ".obj", this function takes
// care of that. Note that the returned path is not guaranteed to exist.
StringRef LinkerDriver::doFindFile(StringRef filename) {
- auto getFilename = [](StringRef filename) -> StringRef {
- if (config->vfs)
- if (auto statOrErr = config->vfs->status(filename))
+ auto getFilename = [this](StringRef filename) -> StringRef {
+ if (ctx.config.vfs)
+ if (auto statOrErr = ctx.config.vfs->status(filename))
return saver().save(statOrErr->getName());
return filename;
};
@@ -522,7 +517,7 @@ StringRef LinkerDriver::doFindLib(StringRef filename) {
StringRef ret = doFindFile(filename);
// For MinGW, if the find above didn't turn up anything, try
// looking for a MinGW formatted library name.
- if (config->mingw && ret == filename)
+ if (ctx.config.mingw && ret == filename)
return doFindLibMinGW(filename);
return ret;
}
@@ -531,13 +526,13 @@ StringRef LinkerDriver::doFindLib(StringRef filename) {
// consideration. This never returns the same path (in that case,
// it returns std::nullopt).
std::optional<StringRef> LinkerDriver::findLib(StringRef filename) {
- if (config->noDefaultLibAll)
+ if (ctx.config.noDefaultLibAll)
return std::nullopt;
if (!visitedLibs.insert(filename.lower()).second)
return std::nullopt;
StringRef path = doFindLib(filename);
- if (config->noDefaultLibs.count(path.lower()))
+ if (ctx.config.noDefaultLibs.count(path.lower()))
return std::nullopt;
if (std::optional<sys::fs::UniqueID> id = getUniqueID(path))
@@ -658,7 +653,7 @@ Symbol *LinkerDriver::addUndefined(StringRef name) {
Symbol *b = ctx.symtab.addUndefined(name);
if (!b->isGCRoot) {
b->isGCRoot = true;
- config->gcroot.push_back(b);
+ ctx.config.gcroot.push_back(b);
}
return b;
}
@@ -687,15 +682,15 @@ StringRef LinkerDriver::mangleMaybe(Symbol *s) {
// each of which corresponds to a user-defined "main" function. This function
// infers an entry point from a user-defined "main" function.
StringRef LinkerDriver::findDefaultEntry() {
- assert(config->subsystem != IMAGE_SUBSYSTEM_UNKNOWN &&
+ assert(ctx.config.subsystem != IMAGE_SUBSYSTEM_UNKNOWN &&
"must handle /subsystem before calling this");
- if (config->mingw)
- return mangle(config->subsystem == IMAGE_SUBSYSTEM_WINDOWS_GUI
+ if (ctx.config.mingw)
+ return mangle(ctx.config.subsystem == IMAGE_SUBSYSTEM_WINDOWS_GUI
? "WinMainCRTStartup"
: "mainCRTStartup");
- if (config->subsystem == IMAGE_SUBSYSTEM_WINDOWS_GUI) {
+ if (ctx.config.subsystem == IMAGE_SUBSYSTEM_WINDOWS_GUI) {
if (findUnderscoreMangle("wWinMain")) {
if (!findUnderscoreMangle("WinMain"))
return mangle("wWinMainCRTStartup");
@@ -712,9 +707,9 @@ StringRef LinkerDriver::findDefaultEntry() {
}
WindowsSubsystem LinkerDriver::inferSubsystem() {
- if (config->dll)
+ if (ctx.config.dll)
return IMAGE_SUBSYSTEM_WINDOWS_GUI;
- if (config->mingw)
+ if (ctx.config.mingw)
return IMAGE_SUBSYSTEM_WINDOWS_CUI;
// Note that link.exe infers the subsystem from the presence of these
// functions even if /entry: or /nodefaultlib are passed which causes them
@@ -736,10 +731,10 @@ WindowsSubsystem LinkerDriver::inferSubsystem() {
return IMAGE_SUBSYSTEM_UNKNOWN;
}
-static uint64_t getDefaultImageBase() {
- if (config->is64())
- return config->dll ? 0x180000000 : 0x140000000;
- return config->dll ? 0x10000000 : 0x400000;
+uint64_t LinkerDriver::getDefaultImageBase() {
+ if (ctx.config.is64())
+ return ctx.config.dll ? 0x180000000 : 0x140000000;
+ return ctx.config.dll ? 0x10000000 : 0x400000;
}
static std::string rewritePath(StringRef s) {
@@ -880,8 +875,9 @@ static unsigned parseDebugTypes(const opt::InputArgList &args) {
return debugTypes;
}
-static std::string getMapFile(const opt::InputArgList &args,
- opt::OptSpecifier os, opt::OptSpecifier osFile) {
+std::string LinkerDriver::getMapFile(const opt::InputArgList &args,
+ opt::OptSpecifier os,
+ opt::OptSpecifier osFile) {
auto *arg = args.getLastArg(os, osFile);
if (!arg)
return "";
@@ -889,14 +885,14 @@ static std::string getMapFile(const opt::InputArgList &args,
return arg->getValue();
assert(arg->getOption().getID() == os.getID());
- StringRef outFile = config->outputFile;
+ StringRef outFile = ctx.config.outputFile;
return (outFile.substr(0, outFile.rfind('.')) + ".map").str();
}
-static std::string getImplibPath() {
- if (!config->implib.empty())
- return std::string(config->implib);
- SmallString<128> out = StringRef(config->outputFile);
+std::string LinkerDriver::getImplibPath() {
+ if (!ctx.config.implib.empty())
+ return std::string(ctx.config.implib);
+ SmallString<128> out = StringRef(ctx.config.outputFile);
sys::path::replace_extension(out, ".lib");
return std::string(out.str());
}
@@ -908,26 +904,26 @@ static std::string getImplibPath() {
// LINK | {value} | {value}.{.dll/.exe} | {output name}
// LIB | {value} | {value}.dll | {output name}.dll
//
-static std::string getImportName(bool asLib) {
+std::string LinkerDriver::getImportName(bool asLib) {
SmallString<128> out;
- if (config->importName.empty()) {
- out.assign(sys::path::filename(config->outputFile));
+ if (ctx.config.importName.empty()) {
+ out.assign(sys::path::filename(ctx.config.outputFile));
if (asLib)
sys::path::replace_extension(out, ".dll");
} else {
- out.assign(config->importName);
+ out.assign(ctx.config.importName);
if (!sys::path::has_extension(out))
sys::path::replace_extension(out,
- (config->dll || asLib) ? ".dll" : ".exe");
+ (ctx.config.dll || asLib) ? ".dll" : ".exe");
}
return std::string(out.str());
}
-static void createImportLibrary(bool asLib) {
+void LinkerDriver::createImportLibrary(bool asLib) {
std::vector<COFFShortExport> exports;
- for (Export &e1 : config->exports) {
+ for (Export &e1 : ctx.config.exports) {
COFFShortExport e2;
e2.Name = std::string(e1.name);
e2.SymbolName = std::string(e1.symbolName);
@@ -944,9 +940,9 @@ static void createImportLibrary(bool asLib) {
std::string libName = getImportName(asLib);
std::string path = getImplibPath();
- if (!config->incremental) {
- checkError(writeImportLibrary(libName, path, exports, config->machine,
- config->mingw));
+ if (!ctx.config.incremental) {
+ checkError(writeImportLibrary(libName, path, exports, ctx.config.machine,
+ ctx.config.mingw));
return;
}
@@ -955,8 +951,8 @@ static void createImportLibrary(bool asLib) {
ErrorOr<std::unique_ptr<MemoryBuffer>> oldBuf = MemoryBuffer::getFile(
path, /*IsText=*/false, /*RequiresNullTerminator=*/false);
if (!oldBuf) {
- checkError(writeImportLibrary(libName, path, exports, config->machine,
- config->mingw));
+ checkError(writeImportLibrary(libName, path, exports, ctx.config.machine,
+ ctx.config.mingw));
return;
}
@@ -966,8 +962,8 @@ static void createImportLibrary(bool asLib) {
fatal("cannot create temporary file for import library " + path + ": " +
ec.message());
- if (Error e = writeImportLibrary(libName, tmpName, exports, config->machine,
- config->mingw)) {
+ if (Error e = writeImportLibrary(libName, tmpName, exports,
+ ctx.config.machine, ctx.config.mingw)) {
checkError(std::move(e));
return;
}
@@ -982,39 +978,39 @@ static void createImportLibrary(bool asLib) {
}
}
-static void parseModuleDefs(StringRef path) {
+void LinkerDriver::parseModuleDefs(StringRef path) {
std::unique_ptr<MemoryBuffer> mb =
CHECK(MemoryBuffer::getFile(path, /*IsText=*/false,
/*RequiresNullTerminator=*/false,
/*IsVolatile=*/true),
"could not open " + path);
COFFModuleDefinition m = check(parseCOFFModuleDefinition(
- mb->getMemBufferRef(), config->machine, config->mingw));
+ mb->getMemBufferRef(), ctx.config.machine, ctx.config.mingw));
// Include in /reproduce: output if applicable.
- driver->takeBuffer(std::move(mb));
+ ctx.driver.takeBuffer(std::move(mb));
- if (config->outputFile.empty())
- config->outputFile = std::string(saver().save(m.OutputFile));
- config->importName = std::string(saver().save(m.ImportName));
+ if (ctx.config.outputFile.empty())
+ ctx.config.outputFile = std::string(saver().save(m.OutputFile));
+ ctx.config.importName = std::string(saver().save(m.ImportName));
if (m.ImageBase)
- config->imageBase = m.ImageBase;
+ ctx.config.imageBase = m.ImageBase;
if (m.StackReserve)
- config->stackReserve = m.StackReserve;
+ ctx.config.stackReserve = m.StackReserve;
if (m.StackCommit)
- config->stackCommit = m.StackCommit;
+ ctx.config.stackCommit = m.StackCommit;
if (m.HeapReserve)
- config->heapReserve = m.HeapReserve;
+ ctx.config.heapReserve = m.HeapReserve;
if (m.HeapCommit)
- config->heapCommit = m.HeapCommit;
+ ctx.config.heapCommit = m.HeapCommit;
if (m.MajorImageVersion)
- config->majorImageVersion = m.MajorImageVersion;
+ ctx.config.majorImageVersion = m.MajorImageVersion;
if (m.MinorImageVersion)
- config->minorImageVersion = m.MinorImageVersion;
+ ctx.config.minorImageVersion = m.MinorImageVersion;
if (m.MajorOSVersion)
- config->majorOSVersion = m.MajorOSVersion;
+ ctx.config.majorOSVersion = m.MajorOSVersion;
if (m.MinorOSVersion)
- config->minorOSVersion = m.MinorOSVersion;
+ ctx.config.minorOSVersion = m.MinorOSVersion;
for (COFFShortExport e1 : m.Exports) {
Export e2;
@@ -1026,7 +1022,7 @@ static void parseModuleDefs(StringRef path) {
StringRef(e1.Name).contains('.')) {
e2.name = saver().save(e1.ExtName);
e2.forwardTo = saver().save(e1.Name);
- config->exports.push_back(e2);
+ ctx.config.exports.push_back(e2);
continue;
}
e2.name = saver().save(e1.Name);
@@ -1037,7 +1033,7 @@ static void parseModuleDefs(StringRef path) {
e2.data = e1.Data;
e2.isPrivate = e1.Private;
e2.constant = e1.Constant;
- config->exports.push_back(e2);
+ ctx.config.exports.push_back(e2);
}
}
@@ -1059,7 +1055,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(COFFLinkerContext &ctx, StringRef arg) {
+void LinkerDriver::parseOrderFile(StringRef arg) {
// For some reason, the MSVC linker requires a filename to be
// preceded by "@".
if (!arg.startswith("@")) {
@@ -1088,22 +1084,22 @@ static void parseOrderFile(COFFLinkerContext &ctx, StringRef arg) {
// end of an output section.
for (StringRef arg : args::getLines(mb->getMemBufferRef())) {
std::string s(arg);
- if (config->machine == I386 && !isDecorated(s))
+ if (ctx.config.machine == I386 && !isDecorated(s))
s = "_" + s;
if (set.count(s) == 0) {
- if (config->warnMissingOrderSymbol)
+ if (ctx.config.warnMissingOrderSymbol)
warn("/order:" + arg + ": missing symbol: " + s + " [LNK4037]");
}
else
- config->order[s] = INT_MIN + config->order.size();
+ ctx.config.order[s] = INT_MIN + ctx.config.order.size();
}
// Include in /reproduce: output if applicable.
- driver->takeBuffer(std::move(mb));
+ ctx.driver.takeBuffer(std::move(mb));
}
-static void parseCallGraphFile(COFFLinkerContext &ctx, StringRef path) {
+void LinkerDriver::parseCallGraphFile(StringRef path) {
std::unique_ptr<MemoryBuffer> mb =
CHECK(MemoryBuffer::getFile(path, /*IsText=*/false,
/*RequiresNullTerminator=*/false,
@@ -1120,7 +1116,7 @@ static void parseCallGraphFile(COFFLinkerContext &ctx, StringRef path) {
auto findSection = [&](StringRef name) -> SectionChunk * {
Symbol *sym = map.lookup(name);
if (!sym) {
- if (config->warnMissingOrderSymbol)
+ if (ctx.config.warnMissingOrderSymbol)
warn(path + ": no such symbol: " + name);
return nullptr;
}
@@ -1142,11 +1138,11 @@ static void parseCallGraphFile(COFFLinkerContext &ctx, StringRef path) {
if (SectionChunk *from = findSection(fields[0]))
if (SectionChunk *to = findSection(fields[1]))
- config->callGraphProfile[{from, to}] += count;
+ ctx.config.callGraphProfile[{from, to}] += count;
}
// Include in /reproduce: output if applicable.
- driver->takeBuffer(std::move(mb));
+ ctx.driver.takeBuffer(std::move(mb));
}
static void readCallGraphsFromObjectFiles(COFFLinkerContext &ctx) {
@@ -1172,7 +1168,7 @@ static void readCallGraphsFromObjectFiles(COFFLinkerContext &ctx) {
auto *from = dyn_cast_or_null<SectionChunk>(fromSym->getChunk());
auto *to = dyn_cast_or_null<SectionChunk>(toSym->getChunk());
if (from && to)
- config->callGraphProfile[{from, to}] += count;
+ ctx.config.callGraphProfile[{from, to}] += count;
}
}
}
@@ -1187,7 +1183,7 @@ static void markAddrsig(Symbol *s) {
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)
+ for (Export &r : ctx.config.exports)
markAddrsig(r.sym);
// Visit the address-significance table in each object file and mark each
@@ -1225,12 +1221,12 @@ static void findKeepUniqueSections(COFFLinkerContext &ctx) {
// binary).
// lld only supports %_PDB% and %_EXT% and warns on references to all other env
// vars.
-static void parsePDBAltPath(StringRef altPath) {
+void LinkerDriver::parsePDBAltPath() {
SmallString<128> buf;
StringRef pdbBasename =
- sys::path::filename(config->pdbPath, sys::path::Style::windows);
+ sys::path::filename(ctx.config.pdbPath, sys::path::Style::windows);
StringRef binaryExtension =
- sys::path::extension(config->outputFile, sys::path::Style::windows);
+ sys::path::extension(ctx.config.outputFile, sys::path::Style::windows);
if (!binaryExtension.empty())
binaryExtension = binaryExtension.substr(1); // %_EXT% does not include '.'.
@@ -1241,19 +1237,22 @@ static void parsePDBAltPath(StringRef altPath) {
// v v v
// a...%...%...
size_t cursor = 0;
- while (cursor < altPath.size()) {
+ while (cursor < ctx.config.pdbAltPath.size()) {
size_t firstMark, secondMark;
- if ((firstMark = altPath.find('%', cursor)) == StringRef::npos ||
- (secondMark = altPath.find('%', firstMark + 1)) == StringRef::npos) {
+ if ((firstMark = ctx.config.pdbAltPath.find('%', cursor)) ==
+ StringRef::npos ||
+ (secondMark = ctx.config.pdbAltPath.find('%', firstMark + 1)) ==
+ StringRef::npos) {
// Didn't find another full fragment, treat rest of string as literal.
- buf.append(altPath.substr(cursor));
+ buf.append(ctx.config.pdbAltPath.substr(cursor));
break;
}
// Found a full fragment. Append text in front of first %, and interpret
// text between first and second % as variable name.
- buf.append(altPath.substr(cursor, firstMark - cursor));
- StringRef var = altPath.substr(firstMark, secondMark - firstMark + 1);
+ buf.append(ctx.config.pdbAltPath.substr(cursor, firstMark - cursor));
+ StringRef var =
+ ctx.config.pdbAltPath.substr(firstMark, secondMark - firstMark + 1);
if (var.equals_insensitive("%_pdb%"))
buf.append(pdbBasename);
else if (var.equals_insensitive("%_ext%"))
@@ -1267,7 +1266,7 @@ static void parsePDBAltPath(StringRef altPath) {
cursor = secondMark + 1;
}
- config->pdbAltPath = buf;
+ ctx.config.pdbAltPath = buf;
}
/// Convert resource files and potentially merge input resource object
@@ -1281,7 +1280,7 @@ void LinkerDriver::convertResources() {
resourceObjFiles.push_back(f);
}
- if (!config->mingw &&
+ if (!ctx.config.mingw &&
(resourceObjFiles.size() > 1 ||
(resourceObjFiles.size() == 1 && !resources.empty()))) {
error((!resources.empty() ? "internal .obj file created from .res files"
@@ -1312,16 +1311,16 @@ void LinkerDriver::convertResources() {
// than MinGW in the case that nothing is explicitly exported.
void LinkerDriver::maybeExportMinGWSymbols(const opt::InputArgList &args) {
if (!args.hasArg(OPT_export_all_symbols)) {
- if (!config->dll)
+ if (!ctx.config.dll)
return;
- if (!config->exports.empty())
+ if (!ctx.config.exports.empty())
return;
if (args.hasArg(OPT_exclude_all_symbols))
return;
}
- AutoExporter exporter(excludedSymbols);
+ AutoExporter exporter(ctx, excludedSymbols);
for (auto *arg : args.filtered(OPT_wholearchive_file))
if (std::optional<StringRef> path = doFindFile(arg->getValue()))
@@ -1336,12 +1335,12 @@ void LinkerDriver::maybeExportMinGWSymbols(const opt::InputArgList &args) {
ctx.symtab.forEachSymbol([&](Symbol *s) {
auto *def = dyn_cast<Defined>(s);
- if (!exporter.shouldExport(ctx, def))
+ if (!exporter.shouldExport(def))
return;
if (!def->isGCRoot) {
def->isGCRoot = true;
- config->gcroot.push_back(def);
+ ctx.config.gcroot.push_back(def);
}
Export e;
@@ -1351,7 +1350,7 @@ void LinkerDriver::maybeExportMinGWSymbols(const opt::InputArgList &args) {
if (!(c->getOutputCharacteristics() & IMAGE_SCN_MEM_EXECUTE))
e.data = true;
s->isUsedInRegularObj = true;
- config->exports.push_back(e);
+ ctx.config.exports.push_back(e);
});
}
@@ -1404,6 +1403,7 @@ getVFS(const opt::InputArgList &args) {
void LinkerDriver::linkerMain(ArrayRef<const char *> argsArr) {
ScopedTimer rootTimer(ctx.rootTimer);
+ Configuration *config = &ctx.config;
// Needed for LTO.
InitializeAllTargetInfos();
@@ -1423,7 +1423,7 @@ void LinkerDriver::linkerMain(ArrayRef<const char *> argsArr) {
}
// Parse command line options.
- ArgParser parser;
+ ArgParser parser(ctx);
opt::InputArgList args = parser.parse(argsArr);
// Parse and evaluate -mllvm options.
@@ -2036,7 +2036,7 @@ void LinkerDriver::linkerMain(ArrayRef<const char *> argsArr) {
// Handle /functionpadmin
for (auto *arg : args.filtered(OPT_functionpadmin, OPT_functionpadmin_opt))
- parseFunctionPadMin(arg, config->machine);
+ parseFunctionPadMin(arg);
if (tar) {
tar->append("response.txt",
@@ -2128,7 +2128,8 @@ void LinkerDriver::linkerMain(ArrayRef<const char *> argsArr) {
// Set default image name if neither /out or /def set it.
if (config->outputFile.empty()) {
config->outputFile = getOutputPath(
- (*args.filtered(OPT_INPUT, OPT_wholearchive_file).begin())->getValue());
+ (*args.filtered(OPT_INPUT, OPT_wholearchive_file).begin())->getValue(),
+ config->dll, config->driver);
}
// Fail early if an output file is not writable.
@@ -2174,8 +2175,8 @@ void LinkerDriver::linkerMain(ArrayRef<const char *> argsArr) {
sys::fs::make_absolute(config->pdbAltPath);
sys::path::remove_dots(config->pdbAltPath);
} else {
- // Don't do this earlier, so that Config->OutputFile is ready.
- parsePDBAltPath(config->pdbAltPath);
+ // Don't do this earlier, so that ctx.OutputFile is ready.
+ parsePDBAltPath();
}
}
@@ -2317,7 +2318,7 @@ void LinkerDriver::linkerMain(ArrayRef<const char *> argsArr) {
// If -thinlto-index-only is given, we should create only "index
// files" and not object files. Index file creation is already done
- // in compileBitcodeFiles, so we are done if that's the case.
+ // in addCombinedLTOObject, so we are done if that's the case.
if (config->thinLTOIndexOnly)
return;
@@ -2364,7 +2365,7 @@ void LinkerDriver::linkerMain(ArrayRef<const char *> argsArr) {
// Handle /output-def (MinGW specific).
if (auto *arg = args.getLastArg(OPT_output_def))
- writeDefFile(arg->getValue());
+ writeDefFile(arg->getValue(), config->exports);
// Set extra alignment for .comm symbols
for (auto pair : config->alignComm) {
@@ -2403,14 +2404,14 @@ 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(ctx, arg->getValue());
+ parseOrderFile(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(ctx, arg->getValue());
+ parseCallGraphFile(arg->getValue());
}
readCallGraphsFromObjectFiles(ctx);
}
@@ -2447,7 +2448,7 @@ void LinkerDriver::linkerMain(ArrayRef<const char *> argsArr) {
// Identify identical COMDAT sections to merge them.
if (config->doICF != ICFLevel::None) {
findKeepUniqueSections(ctx);
- doICF(ctx, config->doICF);
+ doICF(ctx);
}
// Write the result.
diff --git a/lld/COFF/Driver.h b/lld/COFF/Driver.h
index 0c1ae3e013c5..28bf2cc81ef3 100644
--- a/lld/COFF/Driver.h
+++ b/lld/COFF/Driver.h
@@ -9,7 +9,6 @@
#ifndef LLD_COFF_DRIVER_H
#define LLD_COFF_DRIVER_H
-#include "COFFLinkerContext.h"
#include "Config.h"
#include "SymbolTable.h"
#include "lld/Common/LLVM.h"
@@ -30,8 +29,6 @@
namespace lld::coff {
-extern std::unique_ptr<class LinkerDriver> driver;
-
using llvm::COFF::MachineTypes;
using llvm::COFF::WindowsSubsystem;
using std::optional;
@@ -41,10 +38,6 @@ class COFFOptTable : public llvm::opt::OptTable {
COFFOptTable();
};
-// Constructing the option table is expensive. Use a global table to avoid doing
-// it more than once.
-extern COFFOptTable optTable;
-
// The result of parsing the .drective section. The /export: and /include:
// options are handled separately because they reference symbols, and the number
// of symbols can be quite large. The LLVM Option library will perform at least
@@ -59,6 +52,8 @@ struct ParsedDirectives {
class ArgParser {
public:
+ ArgParser(COFFLinkerContext &ctx);
+
// Parses command line options.
llvm::opt::InputArgList parse(llvm::ArrayRef<const char *> args);
@@ -75,11 +70,13 @@ class ArgParser {
void addLINK(SmallVector<const char *, 256> &argv);
std::vector<const char *> tokenize(StringRef s);
+
+ COFFLinkerContext &ctx;
};
class LinkerDriver {
public:
- LinkerDriver(COFFLinkerContext &c) : ctx(c) {}
+ LinkerDriver(COFFLinkerContext &ctx) : ctx(ctx) {}
void linkerMain(llvm::ArrayRef<const char *> args);
@@ -115,6 +112,42 @@ class LinkerDriver {
// Determines the location of the sysroot based on `args`, environment, etc.
void detectWinSysRoot(const llvm::opt::InputArgList &args);
+ // Symbol names are mangled by prepending "_" on x86.
+ StringRef mangle(StringRef sym);
+
+ llvm::Triple::ArchType getArch();
+
+ uint64_t getDefaultImageBase();
+
+ bool isDecorated(StringRef sym);
+
+ std::string getMapFile(const llvm::opt::InputArgList &args,
+ llvm::opt::OptSpecifier os,
+ llvm::opt::OptSpecifier osFile);
+
+ std::string getImplibPath();
+
+ // The import name is calculated as follows:
+ //
+ // | LIBRARY w/ ext | LIBRARY w/o ext | no LIBRARY
+ // -----+----------------+---------------------+------------------
+ // LINK | {value} | {value}.{.dll/.exe} | {output name}
+ // LIB | {value} | {value}.dll | {output name}.dll
+ //
+ std::string getImportName(bool asLib);
+
+ void createImportLibrary(bool asLib);
+
+ void parseModuleDefs(StringRef path);
+
+ // Parse an /order file. If an option is given, the linker places COMDAT
+ // sections int he same order as their names appear in the given file.
+ void parseOrderFile(StringRef arg);
+
+ void parseCallGraphFile(StringRef path);
+
+ void parsePDBAltPath();
+
// Parses LIB environment which contains a list of search paths.
void addLibSearchPaths();
@@ -171,61 +204,68 @@ class LinkerDriver {
llvm::SmallString<128> universalCRTLibPath;
int sdkMajor = 0;
llvm::SmallString<128> windowsSdkLibPath;
-};
-// Functions below this line are defined in DriverUtils.cpp.
+ // Functions below this line are defined in DriverUtils.cpp.
-void printHelp(const char *argv0);
+ void printHelp(const char *argv0);
-// Parses a string in the form of "<integer>[,<integer>]".
-void parseNumbers(StringRef arg, uint64_t *addr, uint64_t *size = nullptr);
+ // Parses a string in the form of "<integer>[,<integer>]".
+ void parseNumbers(StringRef arg, uint64_t *addr, uint64_t *size = nullptr);
-void parseGuard(StringRef arg);
+ void parseGuard(StringRef arg);
-// Parses a string in the form of "<integer>[.<integer>]".
-// Minor's default value is 0.
-void parseVersion(StringRef arg, uint32_t *major, uint32_t *minor);
+ // Parses a string in the form of "<integer>[.<integer>]".
+ // Minor's default value is 0.
+ void parseVersion(StringRef arg, uint32_t *major, uint32_t *minor);
-// Parses a string in the form of "<subsystem>[,<integer>[.<integer>]]".
-void parseSubsystem(StringRef arg, WindowsSubsystem *sys, uint32_t *major,
- uint32_t *minor, bool *gotVersion = nullptr);
+ // Parses a string in the form of "<subsystem>[,<integer>[.<integer>]]".
+ void parseSubsystem(StringRef arg, WindowsSubsystem *sys, uint32_t *major,
+ uint32_t *minor, bool *gotVersion = nullptr);
-void parseAlternateName(StringRef);
-void parseMerge(StringRef);
-void parsePDBPageSize(StringRef);
-void parseSection(StringRef);
-void parseAligncomm(StringRef);
+ void parseAlternateName(StringRef);
+ void parseMerge(StringRef);
+ void parsePDBPageSize(StringRef);
+ void parseSection(StringRef);
+ void parseAligncomm(StringRef);
-// Parses a string in the form of "[:<integer>]"
-void parseFunctionPadMin(llvm::opt::Arg *a, llvm::COFF::MachineTypes machine);
+ // Parses a string in the form of "[:<integer>]"
+ void parseFunctionPadMin(llvm::opt::Arg *a);
-// Parses a string in the form of "EMBED[,=<integer>]|NO".
-void parseManifest(StringRef arg);
+ // Parses a string in the form of "EMBED[,=<integer>]|NO".
+ void parseManifest(StringRef arg);
-// Parses a string in the form of "level=<string>|uiAccess=<string>"
-void parseManifestUAC(StringRef arg);
+ // Parses a string in the form of "level=<string>|uiAccess=<string>"
+ void parseManifestUAC(StringRef arg);
-// Parses a string in the form of "cd|net[,(cd|net)]*"
-void parseSwaprun(StringRef arg);
+ // Parses a string in the form of "cd|net[,(cd|net)]*"
+ void parseSwaprun(StringRef arg);
-// Create a resource file containing a manifest XML.
-std::unique_ptr<MemoryBuffer> createManifestRes();
-void createSideBySideManifest();
+ // Create a resource file containing a manifest XML.
+ std::unique_ptr<MemoryBuffer> createManifestRes();
+ void createSideBySideManifest();
+ std::string createDefaultXml();
+ std::string createManifestXmlWithInternalMt(StringRef defaultXml);
+ std::string createManifestXmlWithExternalMt(StringRef defaultXml);
+ std::string createManifestXml();
-// Used for dllexported symbols.
-Export parseExport(StringRef arg);
-void fixupExports();
-void assignExportOrdinals();
+ std::unique_ptr<llvm::WritableMemoryBuffer>
+ createMemoryBufferForManifestRes(size_t manifestRes);
-// Parses a string in the form of "key=value" and check
-// if value matches previous values for the key.
-// This feature used in the directive section to reject
-// incompatible objects.
-void checkFailIfMismatch(StringRef arg, InputFile *source);
+ // Used for dllexported symbols.
+ Export parseExport(StringRef arg);
+ void fixupExports();
+ void assignExportOrdinals();
-// Convert Windows resource files (.res files) to a .obj file.
-MemoryBufferRef convertResToCOFF(ArrayRef<MemoryBufferRef> mbs,
- ArrayRef<ObjFile *> objs);
+ // Parses a string in the form of "key=value" and check
+ // if value matches previous values for the key.
+ // This feature used in the directive section to reject
+ // incompatible objects.
+ void checkFailIfMismatch(StringRef arg, InputFile *source);
+
+ // Convert Windows resource files (.res files) to a .obj file.
+ MemoryBufferRef convertResToCOFF(ArrayRef<MemoryBufferRef> mbs,
+ ArrayRef<ObjFile *> objs);
+};
// Create enum with OPT_xxx values for each option in Options.td
enum {
diff --git a/lld/COFF/DriverUtils.cpp b/lld/COFF/DriverUtils.cpp
index d4eea0893941..782fdcdd4338 100644
--- a/lld/COFF/DriverUtils.cpp
+++ b/lld/COFF/DriverUtils.cpp
@@ -12,7 +12,7 @@
//
//===----------------------------------------------------------------------===//
-#include "Config.h"
+#include "COFFLinkerContext.h"
#include "Driver.h"
#include "Symbols.h"
#include "lld/Common/ErrorHandler.h"
@@ -75,7 +75,7 @@ class Executor {
} // anonymous namespace
// Parses a string in the form of "<integer>[,<integer>]".
-void parseNumbers(StringRef arg, uint64_t *addr, uint64_t *size) {
+void LinkerDriver::parseNumbers(StringRef arg, uint64_t *addr, uint64_t *size) {
auto [s1, s2] = arg.split(',');
if (s1.getAsInteger(0, *addr))
fatal("invalid number: " + s1);
@@ -85,7 +85,8 @@ void parseNumbers(StringRef arg, uint64_t *addr, uint64_t *size) {
// Parses a string in the form of "<integer>[.<integer>]".
// If second number is not present, Minor is set to 0.
-void parseVersion(StringRef arg, uint32_t *major, uint32_t *minor) {
+void LinkerDriver::parseVersion(StringRef arg, uint32_t *major,
+ uint32_t *minor) {
auto [s1, s2] = arg.split('.');
if (s1.getAsInteger(10, *major))
fatal("invalid number: " + s1);
@@ -94,28 +95,29 @@ void parseVersion(StringRef arg, uint32_t *major, uint32_t *minor) {
fatal("invalid number: " + s2);
}
-void parseGuard(StringRef fullArg) {
+void LinkerDriver::parseGuard(StringRef fullArg) {
SmallVector<StringRef, 1> splitArgs;
fullArg.split(splitArgs, ",");
for (StringRef arg : splitArgs) {
if (arg.equals_insensitive("no"))
- config->guardCF = GuardCFLevel::Off;
+ ctx.config.guardCF = GuardCFLevel::Off;
else if (arg.equals_insensitive("nolongjmp"))
- config->guardCF &= ~GuardCFLevel::LongJmp;
+ ctx.config.guardCF &= ~GuardCFLevel::LongJmp;
else if (arg.equals_insensitive("noehcont"))
- config->guardCF &= ~GuardCFLevel::EHCont;
+ ctx.config.guardCF &= ~GuardCFLevel::EHCont;
else if (arg.equals_insensitive("cf") || arg.equals_insensitive("longjmp"))
- config->guardCF |= GuardCFLevel::CF | GuardCFLevel::LongJmp;
+ ctx.config.guardCF |= GuardCFLevel::CF | GuardCFLevel::LongJmp;
else if (arg.equals_insensitive("ehcont"))
- config->guardCF |= GuardCFLevel::CF | GuardCFLevel::EHCont;
+ ctx.config.guardCF |= GuardCFLevel::CF | GuardCFLevel::EHCont;
else
fatal("invalid argument to /guard: " + arg);
}
}
// Parses a string in the form of "<subsystem>[,<integer>[.<integer>]]".
-void parseSubsystem(StringRef arg, WindowsSubsystem *sys, uint32_t *major,
- uint32_t *minor, bool *gotVersion) {
+void LinkerDriver::parseSubsystem(StringRef arg, WindowsSubsystem *sys,
+ uint32_t *major, uint32_t *minor,
+ bool *gotVersion) {
auto [sysStr, ver] = arg.split(',');
std::string sysStrLower = sysStr.lower();
*sys = StringSwitch<WindowsSubsystem>(sysStrLower)
@@ -140,19 +142,19 @@ void parseSubsystem(StringRef arg, WindowsSubsystem *sys, uint32_t *major,
// Parse a string of the form of "<from>=<to>".
// Results are directly written to Config.
-void parseAlternateName(StringRef s) {
+void LinkerDriver::parseAlternateName(StringRef s) {
auto [from, to] = s.split('=');
if (from.empty() || to.empty())
fatal("/alternatename: invalid argument: " + s);
- auto it = config->alternateNames.find(from);
- if (it != config->alternateNames.end() && it->second != to)
+ auto it = ctx.config.alternateNames.find(from);
+ if (it != ctx.config.alternateNames.end() && it->second != to)
fatal("/alternatename: conflicts: " + s);
- config->alternateNames.insert(it, std::make_pair(from, to));
+ ctx.config.alternateNames.insert(it, std::make_pair(from, to));
}
// Parse a string of the form of "<from>=<to>".
// Results are directly written to Config.
-void parseMerge(StringRef s) {
+void LinkerDriver::parseMerge(StringRef s) {
auto [from, to] = s.split('=');
if (from.empty() || to.empty())
fatal("/merge: invalid argument: " + s);
@@ -160,7 +162,7 @@ void parseMerge(StringRef s) {
fatal("/merge: cannot merge '.rsrc' with any section");
if (from == ".reloc" || to == ".reloc")
fatal("/merge: cannot merge '.reloc' with any section");
- auto pair = config->merge.insert(std::make_pair(from, to));
+ auto pair = ctx.config.merge.insert(std::make_pair(from, to));
bool inserted = pair.second;
if (!inserted) {
StringRef existing = pair.first->second;
@@ -169,7 +171,7 @@ void parseMerge(StringRef s) {
}
}
-void parsePDBPageSize(StringRef s) {
+void LinkerDriver::parsePDBPageSize(StringRef s) {
int v;
if (s.getAsInteger(0, v)) {
error("/pdbpagesize: invalid argument: " + s);
@@ -180,7 +182,7 @@ void parsePDBPageSize(StringRef s) {
return;
}
- config->pdbPageSize = v;
+ ctx.config.pdbPageSize = v;
}
static uint32_t parseSectionAttributes(StringRef s) {
@@ -216,15 +218,15 @@ static uint32_t parseSectionAttributes(StringRef s) {
}
// Parses /section option argument.
-void parseSection(StringRef s) {
+void LinkerDriver::parseSection(StringRef s) {
auto [name, attrs] = s.split(',');
if (name.empty() || attrs.empty())
fatal("/section: invalid argument: " + s);
- config->section[name] = parseSectionAttributes(attrs);
+ ctx.config.section[name] = parseSectionAttributes(attrs);
}
// Parses /aligncomm option argument.
-void parseAligncomm(StringRef s) {
+void LinkerDriver::parseAligncomm(StringRef s) {
auto [name, align] = s.split(',');
if (name.empty() || align.empty()) {
error("/aligncomm: invalid argument: " + s);
@@ -235,56 +237,57 @@ void parseAligncomm(StringRef s) {
error("/aligncomm: invalid argument: " + s);
return;
}
- config->alignComm[std::string(name)] =
- std::max(config->alignComm[std::string(name)], 1 << v);
+ ctx.config.alignComm[std::string(name)] =
+ std::max(ctx.config.alignComm[std::string(name)], 1 << v);
}
// Parses /functionpadmin option argument.
-void parseFunctionPadMin(llvm::opt::Arg *a, llvm::COFF::MachineTypes machine) {
+void LinkerDriver::parseFunctionPadMin(llvm::opt::Arg *a) {
StringRef arg = a->getNumValues() ? a->getValue() : "";
if (!arg.empty()) {
// Optional padding in bytes is given.
- if (arg.getAsInteger(0, config->functionPadMin))
+ if (arg.getAsInteger(0, ctx.config.functionPadMin))
error("/functionpadmin: invalid argument: " + arg);
return;
}
// No optional argument given.
// Set default padding based on machine, similar to link.exe.
// There is no default padding for ARM platforms.
- if (machine == I386) {
- config->functionPadMin = 5;
- } else if (machine == AMD64) {
- config->functionPadMin = 6;
+ if (ctx.config.machine == I386) {
+ ctx.config.functionPadMin = 5;
+ } else if (ctx.config.machine == AMD64) {
+ ctx.config.functionPadMin = 6;
} else {
error("/functionpadmin: invalid argument for this machine: " + arg);
}
}
// Parses a string in the form of "EMBED[,=<integer>]|NO".
-// Results are directly written to Config.
-void parseManifest(StringRef arg) {
+// Results are directly written to
+// Config.
+void LinkerDriver::parseManifest(StringRef arg) {
if (arg.equals_insensitive("no")) {
- config->manifest = Configuration::No;
+ ctx.config.manifest = Configuration::No;
return;
}
if (!arg.startswith_insensitive("embed"))
fatal("invalid option " + arg);
- config->manifest = Configuration::Embed;
+ ctx.config.manifest = Configuration::Embed;
arg = arg.substr(strlen("embed"));
if (arg.empty())
return;
if (!arg.startswith_insensitive(",id="))
fatal("invalid option " + arg);
arg = arg.substr(strlen(",id="));
- if (arg.getAsInteger(0, config->manifestID))
+ if (arg.getAsInteger(0, ctx.config.manifestID))
fatal("invalid option " + arg);
}
// Parses a string in the form of "level=<string>|uiAccess=<string>|NO".
// Results are directly written to Config.
-void parseManifestUAC(StringRef arg) {
+void LinkerDriver::parseManifestUAC(StringRef arg) {
if (arg.equals_insensitive("no")) {
- config->manifestUAC = false;
+ ctx.config.manifestUAC = false;
return;
}
for (;;) {
@@ -293,12 +296,12 @@ void parseManifestUAC(StringRef arg) {
return;
if (arg.startswith_insensitive("level=")) {
arg = arg.substr(strlen("level="));
- std::tie(config->manifestLevel, arg) = arg.split(" ");
+ std::tie(ctx.config.manifestLevel, arg) = arg.split(" ");
continue;
}
if (arg.startswith_insensitive("uiaccess=")) {
arg = arg.substr(strlen("uiaccess="));
- std::tie(config->manifestUIAccess, arg) = arg.split(" ");
+ std::tie(ctx.config.manifestUIAccess, arg) = arg.split(" ");
continue;
}
fatal("invalid option " + arg);
@@ -307,13 +310,13 @@ void parseManifestUAC(StringRef arg) {
// Parses a string in the form of "cd|net[,(cd|net)]*"
// Results are directly written to Config.
-void parseSwaprun(StringRef arg) {
+void LinkerDriver::parseSwaprun(StringRef arg) {
do {
auto [swaprun, newArg] = arg.split(',');
if (swaprun.equals_insensitive("cd"))
- config->swaprunCD = true;
+ ctx.config.swaprunCD = true;
else if (swaprun.equals_insensitive("net"))
- config->swaprunNet = true;
+ ctx.config.swaprunNet = true;
else if (swaprun.empty())
error("/swaprun: missing argument");
else
@@ -371,7 +374,7 @@ class TemporaryFile {
};
}
-static std::string createDefaultXml() {
+std::string LinkerDriver::createDefaultXml() {
std::string ret;
raw_string_ostream os(ret);
@@ -380,17 +383,17 @@ static std::string createDefaultXml() {
os << "<?xml version=\"1.0\" standalone=\"yes\"?>\n"
<< "<assembly xmlns=\"urn:schemas-microsoft-com:asm.v1\"\n"
<< " manifestVersion=\"1.0\">\n";
- if (config->manifestUAC) {
+ if (ctx.config.manifestUAC) {
os << " <trustInfo>\n"
<< " <security>\n"
<< " <requestedPrivileges>\n"
- << " <requestedExecutionLevel level=" << config->manifestLevel
- << " uiAccess=" << config->manifestUIAccess << "/>\n"
+ << " <requestedExecutionLevel level=" << ctx.config.manifestLevel
+ << " uiAccess=" << ctx.config.manifestUIAccess << "/>\n"
<< " </requestedPrivileges>\n"
<< " </security>\n"
<< " </trustInfo>\n";
}
- for (auto manifestDependency : config->manifestDependencies) {
+ for (auto manifestDependency : ctx.config.manifestDependencies) {
os << " <dependency>\n"
<< " <dependentAssembly>\n"
<< " <assemblyIdentity " << manifestDependency << " />\n"
@@ -401,7 +404,8 @@ static std::string createDefaultXml() {
return os.str();
}
-static std::string createManifestXmlWithInternalMt(StringRef defaultXml) {
+std::string
+LinkerDriver::createManifestXmlWithInternalMt(StringRef defaultXml) {
std::unique_ptr<MemoryBuffer> defaultXmlCopy =
MemoryBuffer::getMemBufferCopy(defaultXml);
@@ -410,11 +414,11 @@ static std::string createManifestXmlWithInternalMt(StringRef defaultXml) {
fatal("internal manifest tool failed on default xml: " +
toString(std::move(e)));
- for (StringRef filename : config->manifestInput) {
+ for (StringRef filename : ctx.config.manifestInput) {
std::unique_ptr<MemoryBuffer> manifest =
check(MemoryBuffer::getFile(filename));
// Call takeBuffer to include in /reproduce: output if applicable.
- if (auto e = merger.merge(driver->takeBuffer(std::move(manifest))))
+ if (auto e = merger.merge(takeBuffer(std::move(manifest))))
fatal("internal manifest tool failed on file " + filename + ": " +
toString(std::move(e)));
}
@@ -422,7 +426,8 @@ static std::string createManifestXmlWithInternalMt(StringRef defaultXml) {
return std::string(merger.getMergedManifest().get()->getBuffer());
}
-static std::string createManifestXmlWithExternalMt(StringRef defaultXml) {
+std::string
+LinkerDriver::createManifestXmlWithExternalMt(StringRef defaultXml) {
// Create the default manifest file as a temporary file.
TemporaryFile Default("defaultxml", "manifest");
std::error_code ec;
@@ -439,14 +444,14 @@ static std::string createManifestXmlWithExternalMt(StringRef defaultXml) {
Executor e("mt.exe");
e.add("/manifest");
e.add(Default.path);
- for (StringRef filename : config->manifestInput) {
+ for (StringRef filename : ctx.config.manifestInput) {
e.add("/manifest");
e.add(filename);
// Manually add the file to the /reproduce: tar if needed.
- if (driver->tar)
+ if (tar)
if (auto mbOrErr = MemoryBuffer::getFile(filename))
- driver->takeBuffer(std::move(*mbOrErr));
+ takeBuffer(std::move(*mbOrErr));
}
e.add("/nologo");
e.add("/out:" + StringRef(user.path));
@@ -458,9 +463,9 @@ static std::string createManifestXmlWithExternalMt(StringRef defaultXml) {
->getBuffer());
}
-static std::string createManifestXml() {
+std::string LinkerDriver::createManifestXml() {
std::string defaultXml = createDefaultXml();
- if (config->manifestInput.empty())
+ if (ctx.config.manifestInput.empty())
return defaultXml;
if (windows_manifest::isAvailable())
@@ -469,14 +474,14 @@ static std::string createManifestXml() {
return createManifestXmlWithExternalMt(defaultXml);
}
-static std::unique_ptr<WritableMemoryBuffer>
-createMemoryBufferForManifestRes(size_t manifestSize) {
+std::unique_ptr<WritableMemoryBuffer>
+LinkerDriver::createMemoryBufferForManifestRes(size_t manifestSize) {
size_t resSize = alignTo(
object::WIN_RES_MAGIC_SIZE + object::WIN_RES_NULL_ENTRY_SIZE +
sizeof(object::WinResHeaderPrefix) + sizeof(object::WinResIDs) +
sizeof(object::WinResHeaderSuffix) + manifestSize,
object::WIN_RES_DATA_ALIGNMENT);
- return WritableMemoryBuffer::getNewMemBuffer(resSize, config->outputFile +
+ return WritableMemoryBuffer::getNewMemBuffer(resSize, ctx.config.outputFile +
".manifest.res");
}
@@ -487,7 +492,8 @@ static void writeResFileHeader(char *&buf) {
buf += object::WIN_RES_NULL_ENTRY_SIZE;
}
-static void writeResEntryHeader(char *&buf, size_t manifestSize) {
+static void writeResEntryHeader(char *&buf, size_t manifestSize,
+ int manifestID) {
// Write the prefix.
auto *prefix = reinterpret_cast<object::WinResHeaderPrefix *>(buf);
prefix->DataSize = manifestSize;
@@ -499,7 +505,7 @@ static void writeResEntryHeader(char *&buf, size_t manifestSize) {
// Write the Type/Name IDs.
auto *iDs = reinterpret_cast<object::WinResIDs *>(buf);
iDs->setType(RT_MANIFEST);
- iDs->setName(config->manifestID);
+ iDs->setName(manifestID);
buf += sizeof(object::WinResIDs);
// Write the suffix.
@@ -513,7 +519,7 @@ static void writeResEntryHeader(char *&buf, size_t manifestSize) {
}
// Create a resource file containing a manifest XML.
-std::unique_ptr<MemoryBuffer> createManifestRes() {
+std::unique_ptr<MemoryBuffer> LinkerDriver::createManifestRes() {
std::string manifest = createManifestXml();
std::unique_ptr<WritableMemoryBuffer> res =
@@ -521,17 +527,17 @@ std::unique_ptr<MemoryBuffer> createManifestRes() {
char *buf = res->getBufferStart();
writeResFileHeader(buf);
- writeResEntryHeader(buf, manifest.size());
+ writeResEntryHeader(buf, manifest.size(), ctx.config.manifestID);
// Copy the manifest data into the .res file.
std::copy(manifest.begin(), manifest.end(), buf);
return std::move(res);
}
-void createSideBySideManifest() {
- std::string path = std::string(config->manifestFile);
+void LinkerDriver::createSideBySideManifest() {
+ std::string path = std::string(ctx.config.manifestFile);
if (path == "")
- path = config->outputFile + ".manifest";
+ path = ctx.config.outputFile + ".manifest";
std::error_code ec;
raw_fd_ostream out(path, ec, sys::fs::OF_TextWithCRLF);
if (ec)
@@ -543,7 +549,7 @@ void createSideBySideManifest() {
// "<name>[=<internalname>][, at ordinal[,NONAME]][,DATA][,PRIVATE]"
// or "<name>=<dllname>.<name>".
// Used for parsing /export arguments.
-Export parseExport(StringRef arg) {
+Export LinkerDriver::parseExport(StringRef arg) {
Export e;
StringRef rest;
std::tie(e.name, rest) = arg.split(",");
@@ -605,14 +611,14 @@ Export parseExport(StringRef arg) {
fatal("invalid /export: " + arg);
}
-static StringRef undecorate(StringRef sym) {
- if (config->machine != I386)
+static StringRef undecorate(COFFLinkerContext &ctx, StringRef sym) {
+ if (ctx.config.machine != I386)
return sym;
// In MSVC mode, a fully decorated stdcall function is exported
// as-is with the leading underscore (with type IMPORT_NAME).
// In MinGW mode, a decorated stdcall function gets the underscore
// removed, just like normal cdecl functions.
- if (sym.startswith("_") && sym.contains('@') && !config->mingw)
+ if (sym.startswith("_") && sym.contains('@') && !ctx.config.mingw)
return sym;
return sym.startswith("_") ? sym.substr(1) : sym;
}
@@ -639,26 +645,26 @@ static StringRef killAt(StringRef sym, bool prefix) {
// Performs error checking on all /export arguments.
// It also sets ordinals.
-void fixupExports() {
+void LinkerDriver::fixupExports() {
// Symbol ordinals must be unique.
std::set<uint16_t> ords;
- for (Export &e : config->exports) {
+ for (Export &e : ctx.config.exports) {
if (e.ordinal == 0)
continue;
if (!ords.insert(e.ordinal).second)
fatal("duplicate export ordinal: " + e.name);
}
- for (Export &e : config->exports) {
+ for (Export &e : ctx.config.exports) {
if (!e.forwardTo.empty()) {
- e.exportName = undecorate(e.name);
+ e.exportName = undecorate(ctx, e.name);
} else {
- e.exportName = undecorate(e.extName.empty() ? e.name : e.extName);
+ e.exportName = undecorate(ctx, e.extName.empty() ? e.name : e.extName);
}
}
- if (config->killAt && config->machine == I386) {
- for (Export &e : config->exports) {
+ if (ctx.config.killAt && ctx.config.machine == I386) {
+ for (Export &e : ctx.config.exports) {
e.name = killAt(e.name, true);
e.exportName = killAt(e.exportName, false);
e.extName = killAt(e.extName, true);
@@ -667,9 +673,9 @@ void fixupExports() {
}
// Uniquefy by name.
- DenseMap<StringRef, Export *> map(config->exports.size());
+ DenseMap<StringRef, Export *> map(ctx.config.exports.size());
std::vector<Export> v;
- for (Export &e : config->exports) {
+ for (Export &e : ctx.config.exports) {
auto pair = map.insert(std::make_pair(e.exportName, &e));
bool inserted = pair.second;
if (inserted) {
@@ -681,20 +687,20 @@ void fixupExports() {
continue;
warn("duplicate /export option: " + e.name);
}
- config->exports = std::move(v);
+ ctx.config.exports = std::move(v);
// Sort by name.
- llvm::sort(config->exports, [](const Export &a, const Export &b) {
+ llvm::sort(ctx.config.exports, [](const Export &a, const Export &b) {
return a.exportName < b.exportName;
});
}
-void assignExportOrdinals() {
+void LinkerDriver::assignExportOrdinals() {
// Assign unique ordinals if default (= 0).
uint32_t max = 0;
- for (Export &e : config->exports)
+ for (Export &e : ctx.config.exports)
max = std::max(max, (uint32_t)e.ordinal);
- for (Export &e : config->exports)
+ for (Export &e : ctx.config.exports)
if (e.ordinal == 0)
e.ordinal = ++max;
if (max > std::numeric_limits<uint16_t>::max())
@@ -704,11 +710,11 @@ void assignExportOrdinals() {
// Parses a string in the form of "key=value" and check
// if value matches previous values for the same key.
-void checkFailIfMismatch(StringRef arg, InputFile *source) {
+void LinkerDriver::checkFailIfMismatch(StringRef arg, InputFile *source) {
auto [k, v] = arg.split('=');
if (k.empty() || v.empty())
fatal("/failifmismatch: invalid argument: " + arg);
- std::pair<StringRef, InputFile *> existing = config->mustMatch[k];
+ std::pair<StringRef, InputFile *> existing = ctx.config.mustMatch[k];
if (!existing.first.empty() && v != existing.first) {
std::string sourceStr = source ? toString(source) : "cmd-line";
std::string existingStr =
@@ -717,14 +723,14 @@ void checkFailIfMismatch(StringRef arg, InputFile *source) {
existingStr + " has value " + existing.first + "\n>>> " + sourceStr +
" has value " + v);
}
- config->mustMatch[k] = {v, source};
+ ctx.config.mustMatch[k] = {v, source};
}
// Convert Windows resource files (.res files) to a .obj file.
// Does what cvtres.exe does, but in-process and cross-platform.
-MemoryBufferRef convertResToCOFF(ArrayRef<MemoryBufferRef> mbs,
- ArrayRef<ObjFile *> objs) {
- object::WindowsResourceParser parser(/* MinGW */ config->mingw);
+MemoryBufferRef LinkerDriver::convertResToCOFF(ArrayRef<MemoryBufferRef> mbs,
+ ArrayRef<ObjFile *> objs) {
+ object::WindowsResourceParser parser(/* MinGW */ ctx.config.mingw);
std::vector<std::string> duplicates;
for (MemoryBufferRef mb : mbs) {
@@ -749,18 +755,18 @@ MemoryBufferRef convertResToCOFF(ArrayRef<MemoryBufferRef> mbs,
fatal(toString(std::move(ec)));
}
- if (config->mingw)
+ if (ctx.config.mingw)
parser.cleanUpManifests(duplicates);
for (const auto &dupeDiag : duplicates)
- if (config->forceMultipleRes)
+ if (ctx.config.forceMultipleRes)
warn(dupeDiag);
else
error(dupeDiag);
Expected<std::unique_ptr<MemoryBuffer>> e =
- llvm::object::writeWindowsResourceCOFF(config->machine, parser,
- config->timestamp);
+ llvm::object::writeWindowsResourceCOFF(ctx.config.machine, parser,
+ ctx.config.timestamp);
if (!e)
fatal("failed to write .res to COFF: " + toString(e.takeError()));
@@ -790,8 +796,6 @@ static constexpr llvm::opt::OptTable::Info infoTable[] = {
COFFOptTable::COFFOptTable() : OptTable(infoTable, true) {}
-COFFOptTable optTable;
-
// Set color diagnostics according to --color-diagnostics={auto,always,never}
// or --no-color-diagnostics flags.
static void handleColorDiagnostics(opt::InputArgList &args) {
@@ -827,6 +831,8 @@ static cl::TokenizerCallback getQuotingStyle(opt::InputArgList &args) {
return cl::TokenizeWindowsCommandLine;
}
+ArgParser::ArgParser(COFFLinkerContext &c) : ctx(c) {}
+
// Parses a given list of options.
opt::InputArgList ArgParser::parse(ArrayRef<const char *> argv) {
// Make InputArgList from string vectors.
@@ -837,7 +843,8 @@ opt::InputArgList ArgParser::parse(ArrayRef<const char *> argv) {
// options so we parse here before and ignore all the options but
// --rsp-quoting and /lldignoreenv.
// (This means --rsp-quoting can't be added through %LINK%.)
- opt::InputArgList args = optTable.ParseArgs(argv, missingIndex, missingCount);
+ opt::InputArgList args =
+ ctx.optTable.ParseArgs(argv, missingIndex, missingCount);
// Expand response files (arguments in the form of @<filename>) and insert
// flags from %LINK% and %_LINK_%, and then parse the argument again.
@@ -846,8 +853,8 @@ opt::InputArgList ArgParser::parse(ArrayRef<const char *> argv) {
if (!args.hasArg(OPT_lldignoreenv))
addLINK(expandedArgv);
cl::ExpandResponseFiles(saver(), getQuotingStyle(args), expandedArgv);
- args = optTable.ParseArgs(makeArrayRef(expandedArgv).drop_front(),
- missingIndex, missingCount);
+ args = ctx.optTable.ParseArgs(makeArrayRef(expandedArgv).drop_front(),
+ missingIndex, missingCount);
// Print the real command line if response files are expanded.
if (args.hasArg(OPT_verbose) && argv.size() != expandedArgv.size()) {
@@ -859,10 +866,10 @@ opt::InputArgList ArgParser::parse(ArrayRef<const char *> argv) {
// Save the command line after response file expansion so we can write it to
// the PDB if necessary. Mimic MSVC, which skips input files.
- config->argv = {argv[0]};
+ ctx.config.argv = {argv[0]};
for (opt::Arg *arg : args) {
if (arg->getOption().getKind() != opt::Option::InputClass) {
- config->argv.push_back(args.getArgString(arg->getIndex()));
+ ctx.config.argv.push_back(args.getArgString(arg->getIndex()));
}
}
@@ -876,7 +883,7 @@ opt::InputArgList ArgParser::parse(ArrayRef<const char *> argv) {
for (opt::Arg *arg : args.filtered(OPT_UNKNOWN)) {
std::string nearest;
- if (optTable.findNearest(arg->getAsString(args), nearest) > 1)
+ if (ctx.optTable.findNearest(arg->getAsString(args), nearest) > 1)
warn("ignoring unknown argument '" + arg->getAsString(args) + "'");
else
warn("ignoring unknown argument '" + arg->getAsString(args) +
@@ -921,7 +928,7 @@ ParsedDirectives ArgParser::parseDirectives(StringRef s) {
unsigned missingIndex;
unsigned missingCount;
- result.args = optTable.ParseArgs(rest, missingIndex, missingCount);
+ result.args = ctx.optTable.ParseArgs(rest, missingIndex, missingCount);
if (missingCount)
fatal(Twine(result.args.getArgString(missingIndex)) + ": missing argument");
@@ -951,10 +958,10 @@ std::vector<const char *> ArgParser::tokenize(StringRef s) {
return std::vector<const char *>(tokens.begin(), tokens.end());
}
-void printHelp(const char *argv0) {
- optTable.printHelp(lld::outs(),
- (std::string(argv0) + " [options] file...").c_str(),
- "LLVM Linker", false);
+void LinkerDriver::printHelp(const char *argv0) {
+ ctx.optTable.printHelp(lld::outs(),
+ (std::string(argv0) + " [options] file...").c_str(),
+ "LLVM Linker", false);
}
} // namespace coff
diff --git a/lld/COFF/ICF.cpp b/lld/COFF/ICF.cpp
index f001225b7834..7ece725313d0 100644
--- a/lld/COFF/ICF.cpp
+++ b/lld/COFF/ICF.cpp
@@ -38,7 +38,7 @@ namespace lld::coff {
class ICF {
public:
- ICF(COFFLinkerContext &c, ICFLevel icfLevel) : icfLevel(icfLevel), ctx(c){};
+ ICF(COFFLinkerContext &c) : ctx(c){};
void run();
private:
@@ -61,7 +61,6 @@ class ICF {
std::vector<SectionChunk *> chunks;
int cnt = 0;
std::atomic<bool> repeat = {false};
- ICFLevel icfLevel = ICFLevel::All;
COFFLinkerContext &ctx;
};
@@ -84,7 +83,7 @@ bool ICF::isEligible(SectionChunk *c) {
return false;
// Under regular (not safe) ICF, all code sections are eligible.
- if ((icfLevel == ICFLevel::All) &&
+ if ((ctx.config.doICF == ICFLevel::All) &&
c->getOutputCharacteristics() & llvm::COFF::IMAGE_SCN_MEM_EXECUTE)
return true;
@@ -317,8 +316,6 @@ void ICF::run() {
}
// Entry point to ICF.
-void doICF(COFFLinkerContext &ctx, ICFLevel icfLevel) {
- ICF(ctx, icfLevel).run();
-}
+void doICF(COFFLinkerContext &ctx) { ICF(ctx).run(); }
} // namespace lld::coff
diff --git a/lld/COFF/ICF.h b/lld/COFF/ICF.h
index 8aafdf7b2335..f9ed8edc396f 100644
--- a/lld/COFF/ICF.h
+++ b/lld/COFF/ICF.h
@@ -15,10 +15,9 @@
namespace lld::coff {
-class Chunk;
class COFFLinkerContext;
-void doICF(COFFLinkerContext &ctx, ICFLevel);
+void doICF(COFFLinkerContext &ctx);
} // namespace lld::coff
diff --git a/lld/COFF/InputFiles.cpp b/lld/COFF/InputFiles.cpp
index 84920aecf749..f491a225f326 100644
--- a/lld/COFF/InputFiles.cpp
+++ b/lld/COFF/InputFiles.cpp
@@ -72,7 +72,7 @@ std::string lld::toString(const coff::InputFile *file) {
/// 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.
-static void checkAndSetWeakAlias(SymbolTable *symtab, InputFile *f,
+static void checkAndSetWeakAlias(COFFLinkerContext &ctx, InputFile *f,
Symbol *source, Symbol *target) {
if (auto *u = dyn_cast<Undefined>(source)) {
if (u->weakAlias && u->weakAlias != target) {
@@ -81,9 +81,9 @@ static void checkAndSetWeakAlias(SymbolTable *symtab, InputFile *f,
// of another symbol emitted near the weak symbol.
// Just use the definition from the first object file that defined
// this weak symbol.
- if (config->mingw)
+ if (ctx.config.mingw)
return;
- symtab->reportDuplicate(source, f);
+ ctx.symtab.reportDuplicate(source, f);
}
u->weakAlias = target;
}
@@ -109,13 +109,13 @@ void ArchiveFile::parse() {
void ArchiveFile::addMember(const Archive::Symbol &sym) {
const Archive::Child &c =
CHECK(sym.getMember(),
- "could not get the member for symbol " + toCOFFString(sym));
+ "could not get the member for symbol " + toCOFFString(ctx, sym));
// Return an empty buffer if we have already returned the same buffer.
if (!seen.insert(c.getChildOffset()).second)
return;
- driver->enqueueArchiveMember(c, sym, getName());
+ ctx.driver.enqueueArchiveMember(c, sym, getName());
}
std::vector<MemoryBufferRef> lld::coff::getArchiveMembers(Archive *file) {
@@ -237,7 +237,7 @@ SectionChunk *ObjFile::readSection(uint32_t sectionNumber,
// and then write it to a separate .pdb file.
// Ignore DWARF debug info unless /debug is given.
- if (!config->debug && name.startswith(".debug_"))
+ if (!ctx.config.debug && name.startswith(".debug_"))
return nullptr;
if (sec->Characteristics & llvm::COFF::IMAGE_SCN_LNK_REMOVE)
@@ -260,7 +260,7 @@ SectionChunk *ObjFile::readSection(uint32_t sectionNumber,
guardEHContChunks.push_back(c);
else if (name == ".sxdata")
sxDataChunks.push_back(c);
- else if (config->tailMerge && sec->NumberOfRelocations == 0 &&
+ else if (ctx.config.tailMerge && sec->NumberOfRelocations == 0 &&
name == ".rdata" && leaderName.startswith("??_C@"))
// COFF sections that look like string literal sections (i.e. no
// relocations, in .rdata, leader symbol name matches the MSVC name mangling
@@ -366,7 +366,7 @@ Symbol *ObjFile::createRegular(COFFSymbolRef sym) {
// everything should be fine. If something actually refers to the symbol
// (e.g. the undefined weak alias), linking will fail due to undefined
// references at the end.
- if (config->mingw && name.startswith(".weak."))
+ if (ctx.config.mingw && name.startswith(".weak."))
return nullptr;
return ctx.symtab.addUndefined(name, this, false);
}
@@ -400,7 +400,7 @@ void ObjFile::initializeSymbols() {
} else if (std::optional<Symbol *> optSym =
createDefined(coffSym, comdatDefs, prevailingComdat)) {
symbols[i] = *optSym;
- if (config->mingw && prevailingComdat)
+ if (ctx.config.mingw && prevailingComdat)
recordPrevailingSymbolForMingw(coffSym, prevailingSectionMap);
} else {
// createDefined() returns std::nullopt if a symbol belongs to a section
@@ -421,7 +421,7 @@ void ObjFile::initializeSymbols() {
if (const coff_aux_section_definition *def = sym.getSectionDefinition()) {
if (def->Selection == IMAGE_COMDAT_SELECT_ASSOCIATIVE)
readAssociativeDefinition(sym, def);
- else if (config->mingw)
+ else if (ctx.config.mingw)
maybeAssociateSEHForMingw(sym, def, prevailingSectionMap);
}
if (sparseChunks[sym.getSectionNumber()] == pendingComdat) {
@@ -436,7 +436,7 @@ void ObjFile::initializeSymbols() {
for (auto &kv : weakAliases) {
Symbol *sym = kv.first;
uint32_t idx = kv.second;
- checkAndSetWeakAlias(&ctx.symtab, this, sym, symbols[idx]);
+ checkAndSetWeakAlias(ctx, this, sym, symbols[idx]);
}
// Free the memory used by sparseChunks now that symbol loading is finished.
@@ -496,10 +496,10 @@ void ObjFile::handleComdatSelection(
// Clang on the other hand picks "any". To be able to link two object files
// with a __declspec(selectany) declaration, one compiled with gcc and the
// other with clang, we merge them as proper "same size as"
- if (config->mingw && ((selection == IMAGE_COMDAT_SELECT_ANY &&
- leaderSelection == IMAGE_COMDAT_SELECT_SAME_SIZE) ||
- (selection == IMAGE_COMDAT_SELECT_SAME_SIZE &&
- leaderSelection == IMAGE_COMDAT_SELECT_ANY))) {
+ if (ctx.config.mingw && ((selection == IMAGE_COMDAT_SELECT_ANY &&
+ leaderSelection == IMAGE_COMDAT_SELECT_SAME_SIZE) ||
+ (selection == IMAGE_COMDAT_SELECT_SAME_SIZE &&
+ leaderSelection == IMAGE_COMDAT_SELECT_ANY))) {
leaderSelection = selection = IMAGE_COMDAT_SELECT_SAME_SIZE;
}
@@ -511,7 +511,7 @@ void ObjFile::handleComdatSelection(
// seems better though.
// (This behavior matches ModuleLinker::getComdatResult().)
if (selection != leaderSelection) {
- log(("conflicting comdat type for " + toString(*leader) + ": " +
+ log(("conflicting comdat type for " + toString(ctx, *leader) + ": " +
Twine((int)leaderSelection) + " in " + toString(leader->getFile()) +
" and " + Twine((int)selection) + " in " + toString(this))
.str());
@@ -530,7 +530,7 @@ void ObjFile::handleComdatSelection(
case IMAGE_COMDAT_SELECT_SAME_SIZE:
if (leaderChunk->getSize() != getSection(sym)->SizeOfRawData) {
- if (!config->mingw) {
+ if (!ctx.config.mingw) {
ctx.symtab.reportDuplicate(leader, this);
} else {
const coff_aux_section_definition *leaderDef = nullptr;
@@ -607,7 +607,7 @@ std::optional<Symbol *> ObjFile::createDefined(
if (sym.isExternal())
return ctx.symtab.addAbsolute(name, sym);
- return make<DefinedAbsolute>(name, sym);
+ return make<DefinedAbsolute>(ctx, name, sym);
}
int32_t sectionNumber = sym.getSectionNumber();
@@ -751,7 +751,7 @@ void ObjFile::initializeFlags() {
// DebugTypes.h). Both cases only happen with cl.exe: clang-cl produces regular
// output even with /Yc and /Yu and with /Zi.
void ObjFile::initializeDependencies() {
- if (!config->debug)
+ if (!ctx.config.debug)
return;
bool isPCH = false;
@@ -906,7 +906,7 @@ ObjFile::getVariableLocation(StringRef var) {
if (!dwarf)
return std::nullopt;
}
- if (config->machine == I386)
+ if (ctx.config.machine == I386)
var.consume_front("_");
std::optional<std::pair<std::string, unsigned>> ret =
dwarf->getVariableLoc(var);
@@ -935,9 +935,12 @@ void ObjFile::enqueuePdbFile(StringRef path, ObjFile *fromFile) {
auto it = ctx.pdbInputFileInstances.emplace(*p, nullptr);
if (!it.second)
return; // already scheduled for load
- driver->enqueuePDB(*p);
+ ctx.driver.enqueuePDB(*p);
}
+ImportFile::ImportFile(COFFLinkerContext &ctx, MemoryBufferRef m)
+ : InputFile(ctx, ImportKind, m), live(!ctx.config.doGC), thunkLive(live) {}
+
void ImportFile::parse() {
const char *buf = mb.getBufferStart();
const auto *hdr = reinterpret_cast<const coff_import_header *>(buf);
@@ -993,8 +996,10 @@ BitcodeFile::BitcodeFile(COFFLinkerContext &ctx, MemoryBufferRef mb,
bool lazy)
: InputFile(ctx, BitcodeKind, mb, lazy) {
std::string path = mb.getBufferIdentifier().str();
- if (config->thinLTOIndexOnly)
- path = replaceThinLTOSuffix(mb.getBufferIdentifier());
+ if (ctx.config.thinLTOIndexOnly)
+ path = replaceThinLTOSuffix(mb.getBufferIdentifier(),
+ ctx.config.thinLTOObjectSuffixReplace.first,
+ ctx.config.thinLTOObjectSuffixReplace.second);
// ThinLTO assumes that all MemoryBufferRefs given to it have a unique
// name. If two archives define two members with the same name, this
@@ -1014,36 +1019,9 @@ BitcodeFile::BitcodeFile(COFFLinkerContext &ctx, MemoryBufferRef mb,
BitcodeFile::~BitcodeFile() = default;
-namespace {
-// Convenience class for initializing a coff_section with specific flags.
-class FakeSection {
-public:
- FakeSection(int c) { section.Characteristics = c; }
-
- coff_section section;
-};
-
-// Convenience class for initializing a SectionChunk with specific flags.
-class FakeSectionChunk {
-public:
- FakeSectionChunk(const coff_section *section) : chunk(nullptr, section) {
- // Comdats from LTO files can't be fully treated as regular comdats
- // at this point; we don't know what size or contents they are going to
- // have, so we can't do proper checking of such aspects of them.
- chunk.selection = IMAGE_COMDAT_SELECT_ANY;
- }
-
- SectionChunk chunk;
-};
-
-FakeSection ltoTextSection(IMAGE_SCN_MEM_EXECUTE);
-FakeSection ltoDataSection(IMAGE_SCN_CNT_INITIALIZED_DATA);
-FakeSectionChunk ltoTextSectionChunk(<oTextSection.section);
-FakeSectionChunk ltoDataSectionChunk(<oDataSection.section);
-} // namespace
-
void BitcodeFile::parse() {
llvm::StringSaver &saver = lld::saver();
+
std::vector<std::pair<Symbol *, bool>> comdat(obj->getComdatTable().size());
for (size_t i = 0; i != obj->getComdatTable().size(); ++i)
// FIXME: Check nodeduplicate
@@ -1055,9 +1033,9 @@ void BitcodeFile::parse() {
Symbol *sym;
SectionChunk *fakeSC = nullptr;
if (objSym.isExecutable())
- fakeSC = <oTextSectionChunk.chunk;
+ fakeSC = &ctx.ltoTextSectionChunk->chunk;
else
- fakeSC = <oDataSectionChunk.chunk;
+ fakeSC = &ctx.ltoDataSectionChunk->chunk;
if (objSym.isUndefined()) {
sym = ctx.symtab.addUndefined(symName, this, false);
} else if (objSym.isCommon()) {
@@ -1067,7 +1045,7 @@ void BitcodeFile::parse() {
sym = ctx.symtab.addUndefined(symName, this, true);
std::string fallback = std::string(objSym.getCOFFWeakExternalFallback());
Symbol *alias = ctx.symtab.addUndefined(saver.save(fallback));
- checkAndSetWeakAlias(&ctx.symtab, this, sym, alias);
+ checkAndSetWeakAlias(ctx, this, sym, alias);
} else if (comdatIndex != -1) {
if (symName == obj->getComdatTable()[comdatIndex].first) {
sym = comdat[comdatIndex].first;
@@ -1084,7 +1062,7 @@ void BitcodeFile::parse() {
}
symbols.push_back(sym);
if (objSym.isUsed())
- config->gcroot.push_back(sym);
+ ctx.config.gcroot.push_back(sym);
}
directives = obj->getCOFFLinkerOpts();
}
@@ -1110,10 +1088,8 @@ MachineTypes BitcodeFile::getMachineType() {
}
}
-std::string lld::coff::replaceThinLTOSuffix(StringRef path) {
- StringRef suffix = config->thinLTOObjectSuffixReplace.first;
- StringRef repl = config->thinLTOObjectSuffixReplace.second;
-
+std::string lld::coff::replaceThinLTOSuffix(StringRef path, StringRef suffix,
+ StringRef repl) {
if (path.consume_back(suffix))
return (path + repl).str();
return std::string(path);
diff --git a/lld/COFF/InputFiles.h b/lld/COFF/InputFiles.h
index 75c6ee51c54b..e80886447fbf 100644
--- a/lld/COFF/InputFiles.h
+++ b/lld/COFF/InputFiles.h
@@ -333,8 +333,7 @@ class PDBInputFile : public InputFile {
// for details about the format.
class ImportFile : public InputFile {
public:
- explicit ImportFile(COFFLinkerContext &ctx, MemoryBufferRef m)
- : InputFile(ctx, ImportKind, m) {}
+ explicit ImportFile(COFFLinkerContext &ctx, MemoryBufferRef m);
static bool classof(const InputFile *f) { return f->kind() == ImportKind; }
@@ -358,8 +357,8 @@ class ImportFile : public InputFile {
// symbols provided by this import library member. We also track whether the
// imported symbol is used separately from whether the thunk is used in order
// to avoid creating unnecessary thunks.
- bool live = !config->doGC;
- bool thunkLive = !config->doGC;
+ bool live;
+ bool thunkLive;
};
// Used for LTO.
@@ -408,7 +407,16 @@ inline bool isBitcode(MemoryBufferRef mb) {
return identify_magic(mb.getBuffer()) == llvm::file_magic::bitcode;
}
-std::string replaceThinLTOSuffix(StringRef path);
+// Convenience class for initializing a coff_section with specific flags.
+class FakeSection {
+public:
+ FakeSection(int c) { section.Characteristics = c; }
+
+ coff_section section;
+};
+
+std::string replaceThinLTOSuffix(StringRef path, StringRef suffix,
+ StringRef repl);
} // namespace coff
std::string toString(const coff::InputFile *file);
diff --git a/lld/COFF/LLDMapFile.cpp b/lld/COFF/LLDMapFile.cpp
index af15af5accf1..c14480aaf821 100644
--- a/lld/COFF/LLDMapFile.cpp
+++ b/lld/COFF/LLDMapFile.cpp
@@ -73,12 +73,13 @@ static SymbolMapTy getSectionSyms(ArrayRef<DefinedRegular *> syms) {
// Construct a map from symbols to their stringified representations.
static DenseMap<DefinedRegular *, std::string>
-getSymbolStrings(ArrayRef<DefinedRegular *> syms) {
+getSymbolStrings(const COFFLinkerContext &ctx,
+ ArrayRef<DefinedRegular *> syms) {
std::vector<std::string> str(syms.size());
parallelFor((size_t)0, syms.size(), [&](size_t i) {
raw_string_ostream os(str[i]);
writeHeader(os, syms[i]->getRVA(), 0, 0);
- os << indent16 << toString(*syms[i]);
+ os << indent16 << toString(ctx, *syms[i]);
});
DenseMap<DefinedRegular *, std::string> ret;
@@ -88,18 +89,18 @@ getSymbolStrings(ArrayRef<DefinedRegular *> syms) {
}
void lld::coff::writeLLDMapFile(const COFFLinkerContext &ctx) {
- if (config->lldmapFile.empty())
+ if (ctx.config.lldmapFile.empty())
return;
std::error_code ec;
- raw_fd_ostream os(config->lldmapFile, ec, sys::fs::OF_None);
+ raw_fd_ostream os(ctx.config.lldmapFile, ec, sys::fs::OF_None);
if (ec)
- fatal("cannot open " + config->lldmapFile + ": " + ec.message());
+ fatal("cannot open " + ctx.config.lldmapFile + ": " + ec.message());
// Collect symbol info that we want to print out.
std::vector<DefinedRegular *> syms = getSymbols(ctx);
SymbolMapTy sectionSyms = getSectionSyms(syms);
- DenseMap<DefinedRegular *, std::string> symStr = getSymbolStrings(syms);
+ DenseMap<DefinedRegular *, std::string> symStr = getSymbolStrings(ctx, syms);
// Print out the header line.
os << "Address Size Align Out In Symbol\n";
diff --git a/lld/COFF/LTO.cpp b/lld/COFF/LTO.cpp
index 7dcd7a2aefb4..327992890420 100644
--- a/lld/COFF/LTO.cpp
+++ b/lld/COFF/LTO.cpp
@@ -7,6 +7,7 @@
//===----------------------------------------------------------------------===//
#include "LTO.h"
+#include "COFFLinkerContext.h"
#include "Config.h"
#include "InputFiles.h"
#include "Symbols.h"
@@ -53,17 +54,17 @@ static std::unique_ptr<raw_fd_ostream> openFile(StringRef file) {
return ret;
}
-static std::string getThinLTOOutputFile(StringRef path) {
+std::string BitcodeCompiler::getThinLTOOutputFile(StringRef path) {
return lto::getThinLTOOutputFile(
- std::string(path), std::string(config->thinLTOPrefixReplace.first),
- std::string(config->thinLTOPrefixReplace.second));
+ std::string(path), std::string(ctx.config.thinLTOPrefixReplace.first),
+ std::string(ctx.config.thinLTOPrefixReplace.second));
}
-static lto::Config createConfig() {
+lto::Config BitcodeCompiler::createConfig() {
lto::Config c;
c.Options = initTargetOptionsFromCodeGenFlags();
c.Options.EmitAddrsig = true;
- for (StringRef C : config->mllvmOpts)
+ for (StringRef C : ctx.config.mllvmOpts)
c.MllvmArgs.emplace_back(C.str());
// Always emit a section per function/datum with LTO. LLVM LTO should get most
@@ -74,7 +75,7 @@ static lto::Config createConfig() {
// Use static reloc model on 32-bit x86 because it usually results in more
// compact code, and because there are also known code generation bugs when
// using the PIC model (see PR34306).
- if (config->machine == COFF::IMAGE_FILE_MACHINE_I386)
+ if (ctx.config.machine == COFF::IMAGE_FILE_MACHINE_I386)
c.RelocModel = Reloc::Static;
else
c.RelocModel = Reloc::PIC_;
@@ -84,42 +85,42 @@ static lto::Config createConfig() {
c.DisableVerify = true;
#endif
c.DiagHandler = diagnosticHandler;
- c.OptLevel = config->ltoo;
+ c.OptLevel = ctx.config.ltoo;
c.CPU = getCPUStr();
c.MAttrs = getMAttrs();
- c.CGOptLevel = args::getCGOptLevel(config->ltoo);
- c.AlwaysEmitRegularLTOObj = !config->ltoObjPath.empty();
- c.DebugPassManager = config->ltoDebugPassManager;
- c.CSIRProfile = std::string(config->ltoCSProfileFile);
- c.RunCSIRInstr = config->ltoCSProfileGenerate;
- c.PGOWarnMismatch = config->ltoPGOWarnMismatch;
-
- if (config->saveTemps)
- checkError(c.addSaveTemps(std::string(config->outputFile) + ".",
+ c.CGOptLevel = args::getCGOptLevel(ctx.config.ltoo);
+ c.AlwaysEmitRegularLTOObj = !ctx.config.ltoObjPath.empty();
+ c.DebugPassManager = ctx.config.ltoDebugPassManager;
+ c.CSIRProfile = std::string(ctx.config.ltoCSProfileFile);
+ c.RunCSIRInstr = ctx.config.ltoCSProfileGenerate;
+ c.PGOWarnMismatch = ctx.config.ltoPGOWarnMismatch;
+
+ if (ctx.config.saveTemps)
+ checkError(c.addSaveTemps(std::string(ctx.config.outputFile) + ".",
/*UseInputModulePath*/ true));
return c;
}
-BitcodeCompiler::BitcodeCompiler() {
+BitcodeCompiler::BitcodeCompiler(COFFLinkerContext &c) : ctx(c) {
// Initialize indexFile.
- if (!config->thinLTOIndexOnlyArg.empty())
- indexFile = openFile(config->thinLTOIndexOnlyArg);
+ if (!ctx.config.thinLTOIndexOnlyArg.empty())
+ indexFile = openFile(ctx.config.thinLTOIndexOnlyArg);
// Initialize ltoObj.
lto::ThinBackend backend;
- if (config->thinLTOIndexOnly) {
+ if (ctx.config.thinLTOIndexOnly) {
auto OnIndexWrite = [&](StringRef S) { thinIndices.erase(S); };
backend = lto::createWriteIndexesThinBackend(
- std::string(config->thinLTOPrefixReplace.first),
- std::string(config->thinLTOPrefixReplace.second),
- config->thinLTOEmitImportsFiles, indexFile.get(), OnIndexWrite);
+ std::string(ctx.config.thinLTOPrefixReplace.first),
+ std::string(ctx.config.thinLTOPrefixReplace.second),
+ ctx.config.thinLTOEmitImportsFiles, indexFile.get(), OnIndexWrite);
} else {
backend = lto::createInProcessThinBackend(
- llvm::heavyweight_hardware_concurrency(config->thinLTOJobs));
+ llvm::heavyweight_hardware_concurrency(ctx.config.thinLTOJobs));
}
ltoObj = std::make_unique<lto::LTO>(createConfig(), backend,
- config->ltoPartitions);
+ ctx.config.ltoPartitions);
}
BitcodeCompiler::~BitcodeCompiler() = default;
@@ -132,7 +133,7 @@ void BitcodeCompiler::add(BitcodeFile &f) {
std::vector<Symbol *> symBodies = f.getSymbols();
std::vector<lto::SymbolResolution> resols(symBodies.size());
- if (config->thinLTOIndexOnly)
+ if (ctx.config.thinLTOIndexOnly)
thinIndices.insert(obj.getName());
// Provide a resolution to the LTO API for each symbol.
@@ -161,7 +162,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(COFFLinkerContext &ctx) {
+std::vector<InputFile *> BitcodeCompiler::compile() {
unsigned maxTasks = ltoObj->getMaxTasks();
buf.resize(maxTasks);
files.resize(maxTasks);
@@ -171,8 +172,8 @@ std::vector<InputFile *> BitcodeCompiler::compile(COFFLinkerContext &ctx) {
// native object files for ThinLTO incremental builds. If a path was
// specified, configure LTO to use it as the cache directory.
FileCache cache;
- if (!config->ltoCache.empty())
- cache = check(localCache("ThinLTO", "Thin", config->ltoCache,
+ if (!ctx.config.ltoCache.empty())
+ cache = check(localCache("ThinLTO", "Thin", ctx.config.ltoCache,
[&](size_t task, const Twine &moduleName,
std::unique_ptr<MemoryBuffer> mb) {
files[task] = std::move(mb);
@@ -191,23 +192,23 @@ std::vector<InputFile *> BitcodeCompiler::compile(COFFLinkerContext &ctx) {
for (StringRef s : thinIndices) {
std::string path = getThinLTOOutputFile(s);
openFile(path + ".thinlto.bc");
- if (config->thinLTOEmitImportsFiles)
+ if (ctx.config.thinLTOEmitImportsFiles)
openFile(path + ".imports");
}
// ThinLTO with index only option is required to generate only the index
// files. After that, we exit from linker and ThinLTO backend runs in a
// distributed environment.
- if (config->thinLTOIndexOnly) {
- if (!config->ltoObjPath.empty())
- saveBuffer(buf[0].second, config->ltoObjPath);
+ if (ctx.config.thinLTOIndexOnly) {
+ if (!ctx.config.ltoObjPath.empty())
+ saveBuffer(buf[0].second, ctx.config.ltoObjPath);
if (indexFile)
indexFile->close();
return {};
}
- if (!config->ltoCache.empty())
- pruneCache(config->ltoCache, config->ltoCachePolicy, files);
+ if (!ctx.config.ltoCache.empty())
+ pruneCache(ctx.config.ltoCache, ctx.config.ltoCachePolicy, files);
std::vector<InputFile *> ret;
for (unsigned i = 0; i != maxTasks; ++i) {
@@ -231,19 +232,19 @@ std::vector<InputFile *> BitcodeCompiler::compile(COFFLinkerContext &ctx) {
StringRef ltoObjName;
if (bitcodeFilePath == "ld-temp.o") {
ltoObjName =
- saver().save(Twine(config->outputFile) + ".lto" +
+ saver().save(Twine(ctx.config.outputFile) + ".lto" +
(i == 0 ? Twine("") : Twine('.') + Twine(i)) + ".obj");
} else {
StringRef directory = sys::path::parent_path(bitcodeFilePath);
StringRef baseName = sys::path::filename(bitcodeFilePath);
- StringRef outputFileBaseName = sys::path::filename(config->outputFile);
+ StringRef outputFileBaseName = sys::path::filename(ctx.config.outputFile);
SmallString<64> path;
sys::path::append(path, directory,
outputFileBaseName + ".lto." + baseName);
sys::path::remove_dots(path, true);
ltoObjName = saver().save(path.str());
}
- if (config->saveTemps)
+ if (ctx.config.saveTemps)
saveBuffer(buf[i].second, ltoObjName);
ret.push_back(make<ObjFile>(ctx, MemoryBufferRef(objBuf, ltoObjName)));
}
diff --git a/lld/COFF/LTO.h b/lld/COFF/LTO.h
index 9ef304005221..6826251b5ffa 100644
--- a/lld/COFF/LTO.h
+++ b/lld/COFF/LTO.h
@@ -28,6 +28,7 @@
#include <vector>
namespace llvm::lto {
+struct Config;
class LTO;
}
@@ -39,11 +40,11 @@ class COFFLinkerContext;
class BitcodeCompiler {
public:
- BitcodeCompiler();
+ BitcodeCompiler(COFFLinkerContext &ctx);
~BitcodeCompiler();
void add(BitcodeFile &f);
- std::vector<InputFile *> compile(COFFLinkerContext &ctx);
+ std::vector<InputFile *> compile();
private:
std::unique_ptr<llvm::lto::LTO> ltoObj;
@@ -52,6 +53,11 @@ class BitcodeCompiler {
std::vector<std::string> file_names;
std::unique_ptr<llvm::raw_fd_ostream> indexFile;
llvm::DenseSet<StringRef> thinIndices;
+
+ std::string getThinLTOOutputFile(StringRef path);
+ llvm::lto::Config createConfig();
+
+ COFFLinkerContext &ctx;
};
}
diff --git a/lld/COFF/MapFile.cpp b/lld/COFF/MapFile.cpp
index 797d22c8aaa8..f7a4ef961290 100644
--- a/lld/COFF/MapFile.cpp
+++ b/lld/COFF/MapFile.cpp
@@ -63,7 +63,8 @@ static void writeFormattedTimestamp(raw_ostream &os, time_t tds) {
time->tm_sec, time->tm_year + 1900);
}
-static void sortUniqueSymbols(std::vector<Defined *> &syms) {
+static void sortUniqueSymbols(std::vector<Defined *> &syms,
+ uint64_t imageBase) {
// Build helper vector
using SortEntry = std::pair<Defined *, size_t>;
std::vector<SortEntry> v;
@@ -80,11 +81,11 @@ static void sortUniqueSymbols(std::vector<Defined *> &syms) {
v.erase(end, v.end());
// Sort by RVA then original order
- parallelSort(v, [](const SortEntry &a, const SortEntry &b) {
- // Add config->imageBase to avoid comparing "negative" RVAs.
+ parallelSort(v, [imageBase](const SortEntry &a, const SortEntry &b) {
+ // Add config.imageBase to avoid comparing "negative" RVAs.
// This can happen with symbols of Absolute kind
- uint64_t rvaa = config->imageBase + a.first->getRVA();
- uint64_t rvab = config->imageBase + b.first->getRVA();
+ uint64_t rvaa = imageBase + a.first->getRVA();
+ uint64_t rvab = imageBase + b.first->getRVA();
return rvaa < rvab || (rvaa == rvab && a.second < b.second);
});
@@ -133,8 +134,8 @@ static void getSymbols(const COFFLinkerContext &ctx,
syms.push_back(impSym);
}
- sortUniqueSymbols(syms);
- sortUniqueSymbols(staticSyms);
+ sortUniqueSymbols(syms, ctx.config.imageBase);
+ sortUniqueSymbols(staticSyms, ctx.config.imageBase);
}
// Construct a map from symbols to their stringified representations.
@@ -184,7 +185,7 @@ getSymbolStrings(const COFFLinkerContext &ctx, ArrayRef<Defined *> syms) {
os << " ";
os << left_justify(sym->getName(), 26);
os << " ";
- os << format_hex_no_prefix((config->imageBase + sym->getRVA()), 16);
+ os << format_hex_no_prefix((ctx.config.imageBase + sym->getRVA()), 16);
if (!fileDescr.empty()) {
os << " "; // FIXME : Handle "f" and "i" flags sometimes generated
// by link.exe in those spaces
@@ -199,13 +200,13 @@ getSymbolStrings(const COFFLinkerContext &ctx, ArrayRef<Defined *> syms) {
}
void lld::coff::writeMapFile(COFFLinkerContext &ctx) {
- if (config->mapFile.empty())
+ if (ctx.config.mapFile.empty())
return;
std::error_code ec;
- raw_fd_ostream os(config->mapFile, ec, sys::fs::OF_None);
+ raw_fd_ostream os(ctx.config.mapFile, ec, sys::fs::OF_None);
if (ec)
- fatal("cannot open " + config->mapFile + ": " + ec.message());
+ fatal("cannot open " + ctx.config.mapFile + ": " + ec.message());
ScopedTimer t1(ctx.totalMapTimer);
@@ -223,24 +224,25 @@ void lld::coff::writeMapFile(COFFLinkerContext &ctx) {
t3.stop();
ScopedTimer t4(ctx.writeTimer);
- SmallString<128> AppName = sys::path::filename(config->outputFile);
+ SmallString<128> AppName = sys::path::filename(ctx.config.outputFile);
sys::path::replace_extension(AppName, "");
// Print out the file header
os << " " << AppName << "\n";
os << "\n";
- os << " Timestamp is " << format_hex_no_prefix(config->timestamp, 8) << " (";
- if (config->repro) {
+ os << " Timestamp is " << format_hex_no_prefix(ctx.config.timestamp, 8)
+ << " (";
+ if (ctx.config.repro) {
os << "Repro mode";
} else {
- writeFormattedTimestamp(os, config->timestamp);
+ writeFormattedTimestamp(os, ctx.config.timestamp);
}
os << ")\n";
os << "\n";
os << " Preferred load address is "
- << format_hex_no_prefix(config->imageBase, 16) << "\n";
+ << format_hex_no_prefix(ctx.config.imageBase, 16) << "\n";
os << "\n";
// Print out section table.
@@ -295,8 +297,8 @@ void lld::coff::writeMapFile(COFFLinkerContext &ctx) {
uint16_t entrySecIndex = 0;
uint64_t entryAddress = 0;
- if (!config->noEntry) {
- Defined *entry = dyn_cast_or_null<Defined>(config->entry);
+ if (!ctx.config.noEntry) {
+ Defined *entry = dyn_cast_or_null<Defined>(ctx.config.entry);
if (entry) {
Chunk *chunk = entry->getChunk();
entrySecIndex = chunk->getOutputSectionIdx();
@@ -316,12 +318,12 @@ void lld::coff::writeMapFile(COFFLinkerContext &ctx) {
os << staticSymStr[sym] << '\n';
// Print out the exported functions
- if (config->mapInfo) {
+ if (ctx.config.mapInfo) {
os << "\n";
os << " Exports\n";
os << "\n";
os << " ordinal name\n\n";
- for (Export &e : config->exports) {
+ for (Export &e : ctx.config.exports) {
os << format(" %7d", e.ordinal) << " " << e.name << "\n";
if (!e.extName.empty() && e.extName != e.name)
os << " exported name: " << e.extName << "\n";
diff --git a/lld/COFF/MarkLive.cpp b/lld/COFF/MarkLive.cpp
index 89a3394d7d03..ad8c340f1845 100644
--- a/lld/COFF/MarkLive.cpp
+++ b/lld/COFF/MarkLive.cpp
@@ -51,7 +51,7 @@ void markLive(COFFLinkerContext &ctx) {
};
// Add GC root chunks.
- for (Symbol *b : config->gcroot)
+ for (Symbol *b : ctx.config.gcroot)
addSym(b);
while (!worklist.empty()) {
diff --git a/lld/COFF/MinGW.cpp b/lld/COFF/MinGW.cpp
index 0689e44cc363..01372cbdf29a 100644
--- a/lld/COFF/MinGW.cpp
+++ b/lld/COFF/MinGW.cpp
@@ -24,8 +24,9 @@ using namespace lld;
using namespace lld::coff;
AutoExporter::AutoExporter(
+ COFFLinkerContext &ctx,
const llvm::DenseSet<StringRef> &manualExcludeSymbols)
- : manualExcludeSymbols(manualExcludeSymbols) {
+ : manualExcludeSymbols(manualExcludeSymbols), ctx(ctx) {
excludeLibs = {
"libgcc",
"libgcc_s",
@@ -80,7 +81,7 @@ AutoExporter::AutoExporter(
"_NULL_THUNK_DATA",
};
- if (config->machine == I386) {
+ if (ctx.config.machine == I386) {
excludeSymbols = {
"__NULL_IMPORT_DESCRIPTOR",
"__pei386_runtime_relocator",
@@ -128,8 +129,7 @@ void AutoExporter::addExcludedSymbol(StringRef symbol) {
excludeSymbols.insert(symbol);
}
-bool AutoExporter::shouldExport(const COFFLinkerContext &ctx,
- Defined *sym) const {
+bool AutoExporter::shouldExport(Defined *sym) const {
if (!sym || !sym->getChunk())
return false;
@@ -167,14 +167,15 @@ bool AutoExporter::shouldExport(const COFFLinkerContext &ctx,
return !excludeObjects.count(fileName);
}
-void lld::coff::writeDefFile(StringRef name) {
+void lld::coff::writeDefFile(StringRef name,
+ const std::vector<Export> &exports) {
std::error_code ec;
raw_fd_ostream os(name, ec, sys::fs::OF_None);
if (ec)
fatal("cannot open " + name + ": " + ec.message());
os << "EXPORTS\n";
- for (Export &e : config->exports) {
+ for (const Export &e : exports) {
os << " " << e.exportName << " "
<< "@" << e.ordinal;
if (auto *def = dyn_cast_or_null<Defined>(e.sym)) {
@@ -186,9 +187,9 @@ void lld::coff::writeDefFile(StringRef name) {
}
}
-static StringRef mangle(Twine sym) {
- assert(config->machine != IMAGE_FILE_MACHINE_UNKNOWN);
- if (config->machine == I386)
+static StringRef mangle(Twine sym, MachineTypes machine) {
+ assert(machine != IMAGE_FILE_MACHINE_UNKNOWN);
+ if (machine == I386)
return saver().save("_" + sym);
return saver().save(sym);
}
@@ -212,8 +213,10 @@ lld::coff::addWrappedSymbols(COFFLinkerContext &ctx, opt::InputArgList &args) {
if (!sym)
continue;
- Symbol *real = ctx.symtab.addUndefined(mangle("__real_" + name));
- Symbol *wrap = ctx.symtab.addUndefined(mangle("__wrap_" + name));
+ Symbol *real =
+ ctx.symtab.addUndefined(mangle("__real_" + name, ctx.config.machine));
+ Symbol *wrap =
+ ctx.symtab.addUndefined(mangle("__wrap_" + name, ctx.config.machine));
v.push_back({sym, real, wrap});
// These symbols may seem undefined initially, but don't bail out
@@ -254,7 +257,7 @@ void lld::coff::wrapSymbols(COFFLinkerContext &ctx,
// referenced it or not, though.)
if (imp) {
DefinedLocalImport *wrapimp = make<DefinedLocalImport>(
- saver().save("__imp_" + w.wrap->getName()), d);
+ ctx, saver().save("__imp_" + w.wrap->getName()), d);
ctx.symtab.localImportChunks.push_back(wrapimp->getChunk());
map[imp] = wrapimp;
}
diff --git a/lld/COFF/MinGW.h b/lld/COFF/MinGW.h
index 113cd8327d28..aa5e53278ca4 100644
--- a/lld/COFF/MinGW.h
+++ b/lld/COFF/MinGW.h
@@ -25,7 +25,8 @@ class COFFLinkerContext;
// symbols for MinGW.
class AutoExporter {
public:
- AutoExporter(const llvm::DenseSet<StringRef> &manualExcludeSymbols);
+ AutoExporter(COFFLinkerContext &ctx,
+ const llvm::DenseSet<StringRef> &manualExcludeSymbols);
void addWholeArchive(StringRef path);
void addExcludedSymbol(StringRef symbol);
@@ -38,10 +39,13 @@ class AutoExporter {
const llvm::DenseSet<StringRef> &manualExcludeSymbols;
- bool shouldExport(const COFFLinkerContext &ctx, Defined *sym) const;
+ bool shouldExport(Defined *sym) const;
+
+private:
+ COFFLinkerContext &ctx;
};
-void writeDefFile(StringRef name);
+void writeDefFile(StringRef name, const std::vector<Export> &exports);
// The -wrap option is a feature to rename symbols so that you can write
// wrappers for existing functions. If you pass `-wrap:foo`, all
diff --git a/lld/COFF/PDB.cpp b/lld/COFF/PDB.cpp
index ad5137019ceb..da91455398e0 100644
--- a/lld/COFF/PDB.cpp
+++ b/lld/COFF/PDB.cpp
@@ -67,8 +67,6 @@ using namespace lld::coff;
using llvm::object::coff_section;
using llvm::pdb::StringTableFixup;
-static ExitOnError exitOnErr;
-
namespace {
class DebugSHandler;
@@ -146,6 +144,11 @@ class PDBLinker {
void printStats();
private:
+ void pdbMakeAbsolute(SmallVectorImpl<char> &fileName);
+ void translateIdSymbols(MutableArrayRef<uint8_t> &recordData,
+ TpiSource *source);
+ void addCommonLinkerModuleSymbols(StringRef path,
+ pdb::DbiModuleDescriptorBuilder &mod);
pdb::PDBFileBuilder builder;
@@ -241,7 +244,7 @@ class DebugSHandler {
// Visual Studio's debugger requires absolute paths in various places in the
// PDB to work without additional configuration:
// https://docs.microsoft.com/en-us/visualstudio/debugger/debug-source-files-common-properties-solution-property-pages-dialog-box
-static void pdbMakeAbsolute(SmallVectorImpl<char> &fileName) {
+void PDBLinker::pdbMakeAbsolute(SmallVectorImpl<char> &fileName) {
// The default behavior is to produce paths that are valid within the context
// of the machine that you perform the link on. If the linker is running on
// a POSIX system, we will output absolute POSIX paths. If the linker is
@@ -256,7 +259,7 @@ static void pdbMakeAbsolute(SmallVectorImpl<char> &fileName) {
// It's not absolute in any path syntax. Relative paths necessarily refer to
// the local file system, so we can make it native without ending up with a
// nonsensical path.
- if (config->pdbSourcePath.empty()) {
+ if (ctx.config.pdbSourcePath.empty()) {
sys::path::native(fileName);
sys::fs::make_absolute(fileName);
sys::path::remove_dots(fileName, true);
@@ -267,7 +270,7 @@ static void pdbMakeAbsolute(SmallVectorImpl<char> &fileName) {
// Since PDB's are more of a Windows thing, we make this conservative and only
// decide that it's a unix path if we're fairly certain. Specifically, if
// it starts with a forward slash.
- SmallString<128> absoluteFileName = config->pdbSourcePath;
+ SmallString<128> absoluteFileName = ctx.config.pdbSourcePath;
sys::path::Style guessedStyle = absoluteFileName.startswith("/")
? sys::path::Style::posix
: sys::path::Style::windows;
@@ -338,8 +341,8 @@ static SymbolKind symbolKind(ArrayRef<uint8_t> recordData) {
}
/// MSVC translates S_PROC_ID_END to S_END, and S_[LG]PROC32_ID to S_[LG]PROC32
-static void translateIdSymbols(MutableArrayRef<uint8_t> &recordData,
- TypeMerger &tMerger, TpiSource *source) {
+void PDBLinker::translateIdSymbols(MutableArrayRef<uint8_t> &recordData,
+ TpiSource *source) {
RecordPrefix *prefix = reinterpret_cast<RecordPrefix *>(recordData.data());
SymbolKind kind = symbolKind(recordData);
@@ -370,7 +373,7 @@ static void translateIdSymbols(MutableArrayRef<uint8_t> &recordData,
// in both cases we just need the second type index.
if (!ti->isSimple() && !ti->isNoneType()) {
TypeIndex newType = TypeIndex(SimpleTypeKind::NotTranslated);
- if (config->debugGHashes) {
+ if (ctx.config.debugGHashes) {
auto idToType = tMerger.funcIdToType.find(*ti);
if (idToType != tMerger.funcIdToType.end())
newType = idToType->second;
@@ -575,7 +578,7 @@ void PDBLinker::writeSymbolRecord(SectionChunk *debugChunk,
// An object file may have S_xxx_ID symbols, but these get converted to
// "real" symbols in a PDB.
- translateIdSymbols(recordBytes, tMerger, source);
+ translateIdSymbols(recordBytes, source);
}
void PDBLinker::analyzeSymbolSubsection(
@@ -642,6 +645,7 @@ void PDBLinker::analyzeSymbolSubsection(
Error PDBLinker::writeAllModuleSymbolRecords(ObjFile *file,
BinaryStreamWriter &writer) {
+ ExitOnError exitOnErr;
std::vector<uint8_t> storage;
SmallVector<uint32_t, 4> scopes;
@@ -758,6 +762,7 @@ void DebugSHandler::handleDebugS(SectionChunk *debugChunk) {
contents = SectionChunk::consumeDebugMagic(contents, ".debug$S");
DebugSubsectionArray subsections;
BinaryStreamReader reader(contents, support::little);
+ ExitOnError exitOnErr;
exitOnErr(reader.readArray(subsections, contents.size()));
debugChunk->sortRelocations();
@@ -867,6 +872,7 @@ Error UnrelocatedDebugSubsection::commit(BinaryStreamWriter &writer) const {
TpiSource *source = debugChunk->file->debugTypesObj;
DebugInlineeLinesSubsectionRef inlineeLines;
BinaryStreamReader storageReader(relocatedBytes, support::little);
+ ExitOnError exitOnErr;
exitOnErr(inlineeLines.initialize(storageReader));
for (const InlineeSourceLine &line : inlineeLines) {
TypeIndex &inlinee = *const_cast<TypeIndex *>(&line.Header->Inlinee);
@@ -935,6 +941,8 @@ void DebugSHandler::finish() {
return;
}
+ ExitOnError exitOnErr;
+
// Handle FPO data. Each subsection begins with a single image base
// relocation, which is then added to the RvaStart of each frame data record
// when it is added to the PDB. The string table indices for the FPO program
@@ -984,7 +992,7 @@ void DebugSHandler::finish() {
for (const FileChecksumEntry &fc : checksums) {
SmallString<128> filename =
exitOnErr(cvStrTab.getString(fc.FileNameOffset));
- pdbMakeAbsolute(filename);
+ linker.pdbMakeAbsolute(filename);
exitOnErr(dbiBuilder.addModuleSourceFile(*file.moduleDBI, filename));
newChecksums->addChecksum(filename, fc.Kind, fc.Checksum);
}
@@ -995,8 +1003,8 @@ void DebugSHandler::finish() {
file.moduleDBI->addDebugSubsection(std::move(newChecksums));
}
-static void warnUnusable(InputFile *f, Error e) {
- if (!config->warnDebugInfoUnusable) {
+static void warnUnusable(InputFile *f, Error e, bool shouldWarn) {
+ if (!shouldWarn) {
consumeError(std::move(e));
return;
}
@@ -1023,6 +1031,7 @@ void PDBLinker::addDebugSymbols(TpiSource *source) {
return;
ScopedTimer t(ctx.symbolMergingTimer);
+ ExitOnError exitOnErr;
pdb::DbiStreamBuilder &dbiBuilder = builder.getDbiBuilder();
DebugSHandler dsh(*this, *source->file, source);
// Now do all live .debug$S and .debug$F sections.
@@ -1064,6 +1073,7 @@ void PDBLinker::addDebugSymbols(TpiSource *source) {
void PDBLinker::createModuleDBI(ObjFile *file) {
pdb::DbiStreamBuilder &dbiBuilder = builder.getDbiBuilder();
SmallString<128> objName;
+ ExitOnError exitOnErr;
bool inArchive = !file->parentName.empty();
objName = inArchive ? file->parentName : file->getName();
@@ -1093,11 +1103,12 @@ void PDBLinker::addDebug(TpiSource *source) {
// the PDB first, so that we can get the map from object file type and item
// indices to PDB type and item indices. If we are using ghashes, types have
// already been merged.
- if (!config->debugGHashes) {
+ if (!ctx.config.debugGHashes) {
ScopedTimer t(ctx.typeMergingTimer);
if (Error e = source->mergeDebugT(&tMerger)) {
// If type merging failed, ignore the symbols.
- warnUnusable(source->file, std::move(e));
+ warnUnusable(source->file, std::move(e),
+ ctx.config.warnDebugInfoUnusable);
return;
}
}
@@ -1105,7 +1116,8 @@ void PDBLinker::addDebug(TpiSource *source) {
// If type merging failed, ignore the symbols.
Error typeError = std::move(source->typeMergingError);
if (typeError) {
- warnUnusable(source->file, std::move(typeError));
+ warnUnusable(source->file, std::move(typeError),
+ ctx.config.warnDebugInfoUnusable);
return;
}
@@ -1146,7 +1158,7 @@ void PDBLinker::addObjectsToPDB() {
tMerger.sortDependencies();
// Merge type information from input files using global type hashing.
- if (config->debugGHashes)
+ if (ctx.config.debugGHashes)
tMerger.mergeTypesWithGHash();
// Merge dependencies and then regular objects.
@@ -1160,8 +1172,9 @@ void PDBLinker::addObjectsToPDB() {
// Construct TPI and IPI stream contents.
ScopedTimer t2(ctx.tpiStreamLayoutTimer);
+
// Collect all the merged types.
- if (config->debugGHashes) {
+ if (ctx.config.debugGHashes) {
addGHashTypeInfo(ctx, builder);
} else {
addTypeInfo(builder.getTpiBuilder(), tMerger.getTypeTable());
@@ -1169,7 +1182,7 @@ void PDBLinker::addObjectsToPDB() {
}
t2.stop();
- if (config->showSummary) {
+ if (ctx.config.showSummary) {
for (TpiSource *source : ctx.tpiSourceList) {
nbTypeRecords += source->nbTypeRecords;
nbTypeRecordsBytes += source->nbTypeRecordsBytes;
@@ -1196,7 +1209,7 @@ void PDBLinker::addPublicsToPDB() {
StringRef name = def->getName();
if (name.data()[0] == '_' && name.data()[1] == '_') {
// Drop the '_' prefix for x86.
- if (config->machine == I386)
+ if (ctx.config.machine == I386)
name = name.drop_front(1);
if (name.startswith("__profd_") || name.startswith("__profc_") ||
name.startswith("__covrec_")) {
@@ -1214,7 +1227,7 @@ void PDBLinker::addPublicsToPDB() {
}
void PDBLinker::printStats() {
- if (!config->showSummary)
+ if (!ctx.config.showSummary)
return;
SmallString<256> buffer;
@@ -1282,11 +1295,11 @@ void PDBLinker::printStats() {
<< "Run llvm-pdbutil to print details about a particular record:\n";
stream << formatv("llvm-pdbutil dump -{0}s -{0}-index {1:X} {2}\n",
(name == "TPI" ? "type" : "id"),
- tsis.back().typeIndex.getIndex(), config->pdbPath);
+ tsis.back().typeIndex.getIndex(), ctx.config.pdbPath);
}
};
- if (!config->debugGHashes) {
+ if (!ctx.config.debugGHashes) {
// FIXME: Reimplement for ghash.
printLargeInputTypeRecs("TPI", tMerger.tpiCounts, tMerger.getTypeTable());
printLargeInputTypeRecs("IPI", tMerger.ipiCounts, tMerger.getIDTable());
@@ -1296,7 +1309,7 @@ void PDBLinker::printStats() {
}
void PDBLinker::addNatvisFiles() {
- for (StringRef file : config->natvisFiles) {
+ for (StringRef file : ctx.config.natvisFiles) {
ErrorOr<std::unique_ptr<MemoryBuffer>> dataOrErr =
MemoryBuffer::getFile(file);
if (!dataOrErr) {
@@ -1306,16 +1319,17 @@ void PDBLinker::addNatvisFiles() {
std::unique_ptr<MemoryBuffer> data = std::move(*dataOrErr);
// Can't use takeBuffer() here since addInjectedSource() takes ownership.
- if (driver->tar)
- driver->tar->append(relativeToRoot(data->getBufferIdentifier()),
- data->getBuffer());
+ if (ctx.driver.tar)
+ ctx.driver.tar->append(relativeToRoot(data->getBufferIdentifier()),
+ data->getBuffer());
builder.addInjectedSource(file, std::move(data));
}
}
void PDBLinker::addNamedStreams() {
- for (const auto &streamFile : config->namedStreams) {
+ ExitOnError exitOnErr;
+ for (const auto &streamFile : ctx.config.namedStreams) {
const StringRef stream = streamFile.getKey(), file = streamFile.getValue();
ErrorOr<std::unique_ptr<MemoryBuffer>> dataOrErr =
MemoryBuffer::getFile(file);
@@ -1325,7 +1339,7 @@ void PDBLinker::addNamedStreams() {
}
std::unique_ptr<MemoryBuffer> data = std::move(*dataOrErr);
exitOnErr(builder.addNamedStream(stream, data->getBuffer()));
- driver->takeBuffer(std::move(data));
+ ctx.driver.takeBuffer(std::move(data));
}
}
@@ -1372,8 +1386,8 @@ static std::string quote(ArrayRef<StringRef> args) {
return r;
}
-static void fillLinkerVerRecord(Compile3Sym &cs) {
- cs.Machine = toCodeViewMachine(config->machine);
+static void fillLinkerVerRecord(Compile3Sym &cs, MachineTypes machine) {
+ cs.Machine = toCodeViewMachine(machine);
// Interestingly, if we set the string to 0.0.0.0, then when trying to view
// local variables WinDbg emits an error that private symbols are not present.
// By setting this to a valid MSVC linker version string, local variables are
@@ -1398,27 +1412,27 @@ static void fillLinkerVerRecord(Compile3Sym &cs) {
cs.setLanguage(SourceLanguage::Link);
}
-static void addCommonLinkerModuleSymbols(StringRef path,
- pdb::DbiModuleDescriptorBuilder &mod) {
+void PDBLinker::addCommonLinkerModuleSymbols(
+ StringRef path, pdb::DbiModuleDescriptorBuilder &mod) {
ObjNameSym ons(SymbolRecordKind::ObjNameSym);
EnvBlockSym ebs(SymbolRecordKind::EnvBlockSym);
Compile3Sym cs(SymbolRecordKind::Compile3Sym);
- fillLinkerVerRecord(cs);
+ fillLinkerVerRecord(cs, ctx.config.machine);
ons.Name = "* Linker *";
ons.Signature = 0;
- ArrayRef<StringRef> args = makeArrayRef(config->argv).drop_front();
+ ArrayRef<StringRef> args = makeArrayRef(ctx.config.argv).drop_front();
std::string argStr = quote(args);
ebs.Fields.push_back("cwd");
SmallString<64> cwd;
- if (config->pdbSourcePath.empty())
+ if (ctx.config.pdbSourcePath.empty())
sys::fs::current_path(cwd);
else
- cwd = config->pdbSourcePath;
+ cwd = ctx.config.pdbSourcePath;
ebs.Fields.push_back(cwd);
ebs.Fields.push_back("exe");
- SmallString<64> exe = config->argv[0];
+ SmallString<64> exe = ctx.config.argv[0];
pdbMakeAbsolute(exe);
ebs.Fields.push_back(exe);
ebs.Fields.push_back("pdb");
@@ -1461,7 +1475,7 @@ static void addLinkerModuleCoffGroup(PartialSection *sec,
}
static void addLinkerModuleSectionSymbol(pdb::DbiModuleDescriptorBuilder &mod,
- OutputSection &os) {
+ OutputSection &os, bool isMinGW) {
SectionSym sym(SymbolRecordKind::SectionSym);
sym.Alignment = 12; // 2^12 = 4KB
sym.Characteristics = os.header.Characteristics;
@@ -1474,7 +1488,7 @@ static void addLinkerModuleSectionSymbol(pdb::DbiModuleDescriptorBuilder &mod,
// Skip COFF groups in MinGW because it adds a significant footprint to the
// PDB, due to each function being in its own section
- if (config->mingw)
+ if (isMinGW)
return;
// Output COFF groups for individual chunks of this section.
@@ -1488,6 +1502,7 @@ void PDBLinker::addImportFilesToPDB() {
if (ctx.importFileInstances.empty())
return;
+ ExitOnError exitOnErr;
std::map<std::string, llvm::pdb::DbiModuleDescriptorBuilder *> dllToModuleDbi;
for (ImportFile *file : ctx.importFileInstances) {
@@ -1534,7 +1549,7 @@ void PDBLinker::addImportFilesToPDB() {
ons.Name = file->dllName;
ons.Signature = 0;
- fillLinkerVerRecord(cs);
+ fillLinkerVerRecord(cs, ctx.config.machine);
ts.Name = thunk->getName();
ts.Parent = 0;
@@ -1598,7 +1613,8 @@ void lld::coff::createPDB(COFFLinkerContext &ctx,
}
void PDBLinker::initialize(llvm::codeview::DebugInfo *buildId) {
- exitOnErr(builder.initialize(config->pdbPageSize));
+ ExitOnError exitOnErr;
+ exitOnErr(builder.initialize(ctx.config.pdbPageSize));
buildId->Signature.CVSignature = OMF::Signature::PDB70;
// Signature is set to a hash of the PDB contents when the PDB is done.
@@ -1619,7 +1635,7 @@ void PDBLinker::initialize(llvm::codeview::DebugInfo *buildId) {
pdb::DbiStreamBuilder &dbiBuilder = builder.getDbiBuilder();
dbiBuilder.setAge(buildId->PDB70.Age);
dbiBuilder.setVersionHeader(pdb::PdbDbiV70);
- dbiBuilder.setMachineType(config->machine);
+ dbiBuilder.setMachineType(ctx.config.machine);
// Technically we are not link.exe 14.11, but there are known cases where
// debugging tools on Windows expect Microsoft-specific version numbers or
// they fail to work at all. Since we know we produce PDBs that are
@@ -1628,9 +1644,10 @@ void PDBLinker::initialize(llvm::codeview::DebugInfo *buildId) {
}
void PDBLinker::addSections(ArrayRef<uint8_t> sectionTable) {
+ ExitOnError exitOnErr;
// It's not entirely clear what this is, but the * Linker * module uses it.
pdb::DbiStreamBuilder &dbiBuilder = builder.getDbiBuilder();
- nativePath = config->pdbPath;
+ nativePath = ctx.config.pdbPath;
pdbMakeAbsolute(nativePath);
uint32_t pdbFilePathNI = dbiBuilder.addECName(nativePath);
auto &linkerModule = exitOnErr(dbiBuilder.addModuleInfo("* Linker *"));
@@ -1639,7 +1656,7 @@ void PDBLinker::addSections(ArrayRef<uint8_t> sectionTable) {
// Add section contributions. They must be ordered by ascending RVA.
for (OutputSection *os : ctx.outputSections) {
- addLinkerModuleSectionSymbol(linkerModule, *os);
+ addLinkerModuleSectionSymbol(linkerModule, *os, ctx.config.mingw);
for (Chunk *c : os->chunks) {
pdb::SectionContrib sc =
createSectionContrib(ctx, c, linkerModule.getModuleIndex());
@@ -1669,14 +1686,14 @@ void PDBLinker::commit(codeview::GUID *guid) {
// Print an error and continue if PDB writing fails. This is done mainly so
// the user can see the output of /time and /summary, which is very helpful
// when trying to figure out why a PDB file is too large.
- if (Error e = builder.commit(config->pdbPath, guid)) {
+ if (Error e = builder.commit(ctx.config.pdbPath, guid)) {
checkError(std::move(e));
- error("failed to write PDB file " + Twine(config->pdbPath));
+ error("failed to write PDB file " + Twine(ctx.config.pdbPath));
}
}
-static uint32_t getSecrelReloc() {
- switch (config->machine) {
+static uint32_t getSecrelReloc(llvm::COFF::MachineTypes machine) {
+ switch (machine) {
case AMD64:
return COFF::IMAGE_REL_AMD64_SECREL;
case I386:
@@ -1701,7 +1718,7 @@ static bool findLineTable(const SectionChunk *c, uint32_t addr,
DebugLinesSubsectionRef &lines,
uint32_t &offsetInLinetable) {
ExitOnError exitOnErr;
- uint32_t secrelReloc = getSecrelReloc();
+ const uint32_t secrelReloc = getSecrelReloc(c->file->ctx.config.machine);
for (SectionChunk *dbgC : c->file->getDebugChunks()) {
if (dbgC->getSectionName() != ".debug$S")
diff --git a/lld/COFF/SymbolTable.cpp b/lld/COFF/SymbolTable.cpp
index b46e6719ca26..2ca7b82cac4e 100644
--- a/lld/COFF/SymbolTable.cpp
+++ b/lld/COFF/SymbolTable.cpp
@@ -53,20 +53,20 @@ void SymbolTable::addFile(InputFile *file) {
}
MachineTypes mt = file->getMachineType();
- if (config->machine == IMAGE_FILE_MACHINE_UNKNOWN) {
- config->machine = mt;
- driver->addWinSysRootLibSearchPaths();
- } else if (mt != IMAGE_FILE_MACHINE_UNKNOWN && config->machine != mt) {
+ if (ctx.config.machine == IMAGE_FILE_MACHINE_UNKNOWN) {
+ ctx.config.machine = mt;
+ ctx.driver.addWinSysRootLibSearchPaths();
+ } else if (mt != IMAGE_FILE_MACHINE_UNKNOWN && ctx.config.machine != mt) {
error(toString(file) + ": machine type " + machineToStr(mt) +
- " conflicts with " + machineToStr(config->machine));
+ " conflicts with " + machineToStr(ctx.config.machine));
return;
}
- driver->parseDirectives(file);
+ ctx.driver.parseDirectives(file);
}
-static void errorOrWarn(const Twine &s) {
- if (config->forceUnresolved)
+static void errorOrWarn(const Twine &s, bool forceUnresolved) {
+ if (forceUnresolved)
warn(s);
else
error(s);
@@ -143,7 +143,7 @@ getFileLine(const SectionChunk *c, uint32_t addr) {
std::optional<std::pair<StringRef, uint32_t>> fileLine =
getFileLineCodeView(c, addr);
// If codeview didn't yield any result, check dwarf in MinGW mode.
- if (!fileLine && config->mingw)
+ if (!fileLine && c->file->ctx.config.mingw)
fileLine = getFileLineDwarf(c, addr);
return fileLine;
}
@@ -201,7 +201,7 @@ getSymbolLocations(ObjFile *file, uint32_t symIndex, size_t maxStrings) {
<< "\n>>> ";
os << toString(file);
if (loc.sym)
- os << ":(" << toString(*loc.sym) << ')';
+ os << ":(" << toString(file->ctx, *loc.sym) << ')';
}
return std::make_pair(symbolLocations, numLocations);
}
@@ -236,10 +236,11 @@ struct UndefinedDiag {
std::vector<File> files;
};
-static void reportUndefinedSymbol(const UndefinedDiag &undefDiag) {
+static void reportUndefinedSymbol(const COFFLinkerContext &ctx,
+ const UndefinedDiag &undefDiag) {
std::string out;
llvm::raw_string_ostream os(out);
- os << "undefined symbol: " << toString(*undefDiag.sym);
+ os << "undefined symbol: " << toString(ctx, *undefDiag.sym);
const size_t maxUndefReferences = 3;
size_t numDisplayedRefs = 0, numRefs = 0;
@@ -255,7 +256,7 @@ static void reportUndefinedSymbol(const UndefinedDiag &undefDiag) {
}
if (numDisplayedRefs < numRefs)
os << "\n>>> referenced " << numRefs - numDisplayedRefs << " more times";
- errorOrWarn(os.str());
+ errorOrWarn(os.str(), ctx.config.forceUnresolved);
}
void SymbolTable::loadMinGWSymbols() {
@@ -269,7 +270,7 @@ void SymbolTable::loadMinGWSymbols() {
StringRef name = undef->getName();
- if (config->machine == I386 && config->stdcallFixup) {
+ if (ctx.config.machine == I386 && ctx.config.stdcallFixup) {
// Check if we can resolve an undefined decorated symbol by finding
// the intended target as an undecorated symbol (only with a leading
// underscore).
@@ -290,7 +291,7 @@ void SymbolTable::loadMinGWSymbols() {
}
// If it's lazy or already defined, hook it up as weak alias.
if (l->isLazy() || isa<Defined>(l)) {
- if (config->warnStdcallFixup)
+ if (ctx.config.warnStdcallFixup)
warn("Resolving " + origName + " by linking to " + newName);
else
log("Resolving " + origName + " by linking to " + newName);
@@ -300,7 +301,7 @@ void SymbolTable::loadMinGWSymbols() {
}
}
- if (config->autoImport) {
+ if (ctx.config.autoImport) {
if (name.startswith("__imp_"))
continue;
// If we have an undefined symbol, but we have a lazy symbol we could
@@ -358,7 +359,7 @@ bool SymbolTable::handleMinGWAutomaticImport(Symbol *sym, StringRef name) {
// for __imp_<name> instead, and drop the whole .refptr.<name> chunk.
DefinedRegular *refptr =
dyn_cast_or_null<DefinedRegular>(find((".refptr." + name).str()));
- if (refptr && refptr->getChunk()->getSize() == config->wordsize) {
+ if (refptr && refptr->getChunk()->getSize() == ctx.config.wordsize) {
SectionChunk *sc = dyn_cast_or_null<SectionChunk>(refptr->getChunk());
if (sc && sc->getRelocs().size() == 1 && *sc->symbols().begin() == sym) {
log("Replacing .refptr." + name + " with " + imp->getName());
@@ -383,12 +384,13 @@ static void reportProblemSymbols(
if (undefs.empty() && (!localImports || localImports->empty()))
return;
- for (Symbol *b : config->gcroot) {
+ for (Symbol *b : ctx.config.gcroot) {
if (undefs.count(b))
- errorOrWarn("<root>: undefined symbol: " + toString(*b));
+ errorOrWarn("<root>: undefined symbol: " + toString(ctx, *b),
+ ctx.config.forceUnresolved);
if (localImports)
if (Symbol *imp = localImports->lookup(b))
- warn("<root>: locally defined symbol imported: " + toString(*imp) +
+ warn("<root>: locally defined symbol imported: " + toString(ctx, *imp) +
" (defined in " + toString(imp->getFile()) + ") [LNK4217]");
}
@@ -413,7 +415,7 @@ static void reportProblemSymbols(
if (localImports)
if (Symbol *imp = localImports->lookup(sym))
warn(toString(file) +
- ": locally defined symbol imported: " + toString(*imp) +
+ ": locally defined symbol imported: " + toString(ctx, *imp) +
" (defined in " + toString(imp->getFile()) + ") [LNK4217]");
}
};
@@ -426,7 +428,7 @@ static void reportProblemSymbols(
processFile(file, file->getSymbols());
for (const UndefinedDiag &undefDiag : undefDiags)
- reportUndefinedSymbol(undefDiag);
+ reportUndefinedSymbol(ctx, undefDiag);
}
void SymbolTable::reportUnresolvable() {
@@ -446,7 +448,7 @@ void SymbolTable::reportUnresolvable() {
}
if (name.contains("_PchSym_"))
continue;
- if (config->autoImport && impSymbol(name))
+ if (ctx.config.autoImport && impSymbol(name))
continue;
undefs.insert(sym);
}
@@ -491,7 +493,7 @@ void SymbolTable::resolveRemainingUndefines() {
Symbol *imp = find(name.substr(strlen("__imp_")));
if (imp && isa<Defined>(imp)) {
auto *d = cast<Defined>(imp);
- replaceSymbol<DefinedLocalImport>(sym, name, d);
+ replaceSymbol<DefinedLocalImport>(sym, ctx, name, d);
localImportChunks.push_back(cast<DefinedLocalImport>(sym)->getChunk());
localImports[sym] = d;
continue;
@@ -503,19 +505,19 @@ void SymbolTable::resolveRemainingUndefines() {
if (name.contains("_PchSym_"))
continue;
- if (config->autoImport && handleMinGWAutomaticImport(sym, name))
+ if (ctx.config.autoImport && handleMinGWAutomaticImport(sym, name))
continue;
// Remaining undefined symbols are not fatal if /force is specified.
// They are replaced with dummy defined symbols.
- if (config->forceUnresolved)
- replaceSymbol<DefinedAbsolute>(sym, name, 0);
+ if (ctx.config.forceUnresolved)
+ replaceSymbol<DefinedAbsolute>(sym, ctx, name, 0);
undefs.insert(sym);
}
reportProblemSymbols(
- ctx, undefs, config->warnLocallyDefinedImported ? &localImports : nullptr,
- false);
+ ctx, undefs,
+ ctx.config.warnLocallyDefinedImported ? &localImports : nullptr, false);
}
std::pair<Symbol *, bool> SymbolTable::insert(StringRef name) {
@@ -642,7 +644,7 @@ void SymbolTable::reportDuplicate(Symbol *existing, InputFile *newFile,
uint32_t newSectionOffset) {
std::string msg;
llvm::raw_string_ostream os(msg);
- os << "duplicate symbol: " << toString(*existing);
+ os << "duplicate symbol: " << toString(ctx, *existing);
DefinedRegular *d = dyn_cast<DefinedRegular>(existing);
if (d && isa<ObjFile>(d->getFile())) {
@@ -654,7 +656,7 @@ void SymbolTable::reportDuplicate(Symbol *existing, InputFile *newFile,
os << getSourceLocation(newFile, newSc, newSectionOffset,
existing->getName());
- if (config->forceMultiple)
+ if (ctx.config.forceMultiple)
warn(os.str());
else
error(os.str());
@@ -664,7 +666,7 @@ Symbol *SymbolTable::addAbsolute(StringRef n, COFFSymbolRef sym) {
auto [s, wasInserted] = insert(n, nullptr);
s->isUsedInRegularObj = true;
if (wasInserted || isa<Undefined>(s) || s->isLazy())
- replaceSymbol<DefinedAbsolute>(s, n, sym);
+ replaceSymbol<DefinedAbsolute>(s, ctx, n, sym);
else if (auto *da = dyn_cast<DefinedAbsolute>(s)) {
if (da->getVA() != sym.getValue())
reportDuplicate(s, nullptr);
@@ -677,7 +679,7 @@ Symbol *SymbolTable::addAbsolute(StringRef n, uint64_t va) {
auto [s, wasInserted] = insert(n, nullptr);
s->isUsedInRegularObj = true;
if (wasInserted || isa<Undefined>(s) || s->isLazy())
- replaceSymbol<DefinedAbsolute>(s, n, va);
+ replaceSymbol<DefinedAbsolute>(s, ctx, n, va);
else if (auto *da = dyn_cast<DefinedAbsolute>(s)) {
if (da->getVA() != va)
reportDuplicate(s, nullptr);
@@ -751,7 +753,7 @@ Symbol *SymbolTable::addImportThunk(StringRef name, DefinedImportData *id,
auto [s, wasInserted] = insert(name, nullptr);
s->isUsedInRegularObj = true;
if (wasInserted || isa<Undefined>(s) || s->isLazy()) {
- replaceSymbol<DefinedImportThunk>(s, name, id, machine);
+ replaceSymbol<DefinedImportThunk>(s, ctx, name, id, machine);
return s;
}
@@ -788,7 +790,7 @@ Symbol *SymbolTable::find(StringRef name) const {
}
Symbol *SymbolTable::findUnderscore(StringRef name) const {
- if (config->machine == I386)
+ if (ctx.config.machine == I386)
return find(("_" + name).str());
return find(name);
}
@@ -835,7 +837,7 @@ Symbol *SymbolTable::findMangle(StringRef name) {
};
// For non-x86, just look for C++ functions.
- if (config->machine != I386)
+ if (ctx.config.machine != I386)
return findByPrefix("?" + name + "@@Y");
if (!name.startswith("_"))
@@ -862,10 +864,10 @@ void SymbolTable::compileBitcodeFiles() {
return;
ScopedTimer t(ctx.ltoTimer);
- lto.reset(new BitcodeCompiler());
+ lto.reset(new BitcodeCompiler(ctx));
for (BitcodeFile *f : ctx.bitcodeFileInstances)
lto->add(*f);
- for (InputFile *newObj : lto->compile(ctx)) {
+ for (InputFile *newObj : lto->compile()) {
ObjFile *obj = cast<ObjFile>(newObj);
obj->parse();
ctx.objFileInstances.push_back(obj);
diff --git a/lld/COFF/SymbolTable.h b/lld/COFF/SymbolTable.h
index 15cb5334df48..33ed65c45807 100644
--- a/lld/COFF/SymbolTable.h
+++ b/lld/COFF/SymbolTable.h
@@ -47,7 +47,7 @@ class Symbol;
// There is one add* function per symbol type.
class SymbolTable {
public:
- SymbolTable(COFFLinkerContext &ctx) : ctx(ctx) {}
+ SymbolTable(COFFLinkerContext &c) : ctx(c) {}
void addFile(InputFile *file);
diff --git a/lld/COFF/Symbols.cpp b/lld/COFF/Symbols.cpp
index 5a038b38f8ba..c042386e0106 100644
--- a/lld/COFF/Symbols.cpp
+++ b/lld/COFF/Symbols.cpp
@@ -7,6 +7,7 @@
//===----------------------------------------------------------------------===//
#include "Symbols.h"
+#include "COFFLinkerContext.h"
#include "InputFiles.h"
#include "lld/Common/ErrorHandler.h"
#include "lld/Common/Memory.h"
@@ -27,14 +28,15 @@ static_assert(sizeof(SymbolUnion) <= 48,
"symbols should be optimized for memory usage");
// Returns a symbol name for an error message.
-static std::string maybeDemangleSymbol(StringRef symName) {
- if (config->demangle) {
+static std::string maybeDemangleSymbol(const COFFLinkerContext &ctx,
+ StringRef symName) {
+ if (ctx.config.demangle) {
std::string prefix;
StringRef prefixless = symName;
if (prefixless.consume_front("__imp_"))
prefix = "__declspec(dllimport) ";
StringRef demangleInput = prefixless;
- if (config->machine == I386)
+ if (ctx.config.machine == I386)
demangleInput.consume_front("_");
std::string demangled = demangle(demangleInput.str());
if (demangled != demangleInput)
@@ -43,11 +45,12 @@ static std::string maybeDemangleSymbol(StringRef symName) {
}
return std::string(symName);
}
-std::string toString(coff::Symbol &b) {
- return maybeDemangleSymbol(b.getName());
+std::string toString(const COFFLinkerContext &ctx, coff::Symbol &b) {
+ return maybeDemangleSymbol(ctx, b.getName());
}
-std::string toCOFFString(const Archive::Symbol &b) {
- return maybeDemangleSymbol(b.getName());
+std::string toCOFFString(const COFFLinkerContext &ctx,
+ const Archive::Symbol &b) {
+ return maybeDemangleSymbol(ctx, b.getName());
}
namespace coff {
@@ -102,23 +105,24 @@ COFFSymbolRef DefinedCOFF::getCOFFSymbol() {
return COFFSymbolRef(reinterpret_cast<const coff_symbol32 *>(sym));
}
-uint16_t DefinedAbsolute::numOutputSections;
+uint64_t DefinedAbsolute::getRVA() { return va - ctx.config.imageBase; }
-static Chunk *makeImportThunk(DefinedImportData *s, uint16_t machine) {
+static Chunk *makeImportThunk(COFFLinkerContext &ctx, DefinedImportData *s,
+ uint16_t machine) {
if (machine == AMD64)
- return make<ImportThunkChunkX64>(s);
+ return make<ImportThunkChunkX64>(ctx, s);
if (machine == I386)
- return make<ImportThunkChunkX86>(s);
+ return make<ImportThunkChunkX86>(ctx, s);
if (machine == ARM64)
- return make<ImportThunkChunkARM64>(s);
+ return make<ImportThunkChunkARM64>(ctx, s);
assert(machine == ARMNT);
- return make<ImportThunkChunkARM>(s);
+ return make<ImportThunkChunkARM>(ctx, s);
}
-DefinedImportThunk::DefinedImportThunk(StringRef name, DefinedImportData *s,
- uint16_t machine)
+DefinedImportThunk::DefinedImportThunk(COFFLinkerContext &ctx, StringRef name,
+ DefinedImportData *s, uint16_t machine)
: Defined(DefinedImportThunkKind, name), wrappedSym(s),
- data(makeImportThunk(s, machine)) {}
+ data(makeImportThunk(ctx, s, machine)) {}
Defined *Undefined::getWeakAlias() {
// A weak alias may be a weak alias to another symbol, so check recursively.
@@ -130,11 +134,11 @@ Defined *Undefined::getWeakAlias() {
MemoryBufferRef LazyArchive::getMemberBuffer() {
Archive::Child c =
- CHECK(sym.getMember(),
- "could not get the member for symbol " + toCOFFString(sym));
+ CHECK(sym.getMember(), "could not get the member for symbol " +
+ toCOFFString(file->ctx, sym));
return CHECK(c.getMemoryBufferRef(),
- "could not get the buffer for the member defining symbol " +
- toCOFFString(sym));
+ "could not get the buffer for the member defining symbol " +
+ toCOFFString(file->ctx, sym));
}
} // namespace coff
} // namespace lld
diff --git a/lld/COFF/Symbols.h b/lld/COFF/Symbols.h
index 7e99b02629df..750269fd0bbb 100644
--- a/lld/COFF/Symbols.h
+++ b/lld/COFF/Symbols.h
@@ -22,13 +22,6 @@
namespace lld {
-std::string toString(coff::Symbol &b);
-
-// There are two
diff erent ways to convert an Archive::Symbol to a string:
-// One for Microsoft name mangling and one for Itanium name mangling.
-// Call the functions toCOFFString and toELFString, not just toString.
-std::string toCOFFString(const coff::Archive::Symbol &b);
-
namespace coff {
using llvm::object::Archive;
@@ -37,6 +30,7 @@ using llvm::object::coff_import_header;
using llvm::object::coff_symbol_generic;
class ArchiveFile;
+class COFFLinkerContext;
class InputFile;
class ObjFile;
class SymbolTable;
@@ -250,29 +244,25 @@ class DefinedCommon : public DefinedCOFF {
// Absolute symbols.
class DefinedAbsolute : public Defined {
public:
- DefinedAbsolute(StringRef n, COFFSymbolRef s)
- : Defined(DefinedAbsoluteKind, n), va(s.getValue()) {
+ DefinedAbsolute(const COFFLinkerContext &c, StringRef n, COFFSymbolRef s)
+ : Defined(DefinedAbsoluteKind, n), va(s.getValue()), ctx(c) {
isExternal = s.isExternal();
}
- DefinedAbsolute(StringRef n, uint64_t v)
- : Defined(DefinedAbsoluteKind, n), va(v) {}
+ DefinedAbsolute(const COFFLinkerContext &c, StringRef n, uint64_t v)
+ : Defined(DefinedAbsoluteKind, n), va(v), ctx(c) {}
static bool classof(const Symbol *s) {
return s->kind() == DefinedAbsoluteKind;
}
- uint64_t getRVA() { return va - config->imageBase; }
+ uint64_t getRVA();
void setVA(uint64_t v) { va = v; }
uint64_t getVA() const { return va; }
- // Section index relocations against absolute symbols resolve to
- // this 16 bit number, and it is the largest valid section index
- // plus one. This variable keeps it.
- static uint16_t numOutputSections;
-
private:
uint64_t va;
+ const COFFLinkerContext &ctx;
};
// This symbol is used for linker-synthesized symbols like __ImageBase and
@@ -393,7 +383,8 @@ class DefinedImportData : public Defined {
// a regular name. A function pointer is given as a DefinedImportData.
class DefinedImportThunk : public Defined {
public:
- DefinedImportThunk(StringRef name, DefinedImportData *s, uint16_t machine);
+ DefinedImportThunk(COFFLinkerContext &ctx, StringRef name,
+ DefinedImportData *s, uint16_t machine);
static bool classof(const Symbol *s) {
return s->kind() == DefinedImportThunkKind;
@@ -415,8 +406,9 @@ class DefinedImportThunk : public Defined {
// This is here just for compatibility with MSVC.
class DefinedLocalImport : public Defined {
public:
- DefinedLocalImport(StringRef n, Defined *s)
- : Defined(DefinedLocalImportKind, n), data(make<LocalImportChunk>(s)) {}
+ DefinedLocalImport(COFFLinkerContext &ctx, StringRef n, Defined *s)
+ : Defined(DefinedLocalImportKind, n),
+ data(make<LocalImportChunk>(ctx, s)) {}
static bool classof(const Symbol *s) {
return s->kind() == DefinedLocalImportKind;
@@ -511,6 +503,10 @@ void replaceSymbol(Symbol *s, ArgT &&... arg) {
}
} // namespace coff
+std::string toString(const coff::COFFLinkerContext &ctx, coff::Symbol &b);
+std::string toCOFFString(const coff::COFFLinkerContext &ctx,
+ const llvm::object::Archive::Symbol &b);
+
} // namespace lld
#endif
diff --git a/lld/COFF/TypeMerger.h b/lld/COFF/TypeMerger.h
index 17f019758e82..b4e3d6e7d9fd 100644
--- a/lld/COFF/TypeMerger.h
+++ b/lld/COFF/TypeMerger.h
@@ -32,13 +32,13 @@ class TypeMerger {
/// Get the type table or the global type table if /DEBUG:GHASH is enabled.
inline llvm::codeview::TypeCollection &getTypeTable() {
- assert(!config->debugGHashes);
+ assert(!ctx.config.debugGHashes);
return typeTable;
}
/// Get the ID table or the global ID table if /DEBUG:GHASH is enabled.
inline llvm::codeview::TypeCollection &getIDTable() {
- assert(!config->debugGHashes);
+ assert(!ctx.config.debugGHashes);
return idTable;
}
diff --git a/lld/COFF/Writer.cpp b/lld/COFF/Writer.cpp
index ccadc26d27e8..09cca5667a47 100644
--- a/lld/COFF/Writer.cpp
+++ b/lld/COFF/Writer.cpp
@@ -85,7 +85,7 @@ namespace {
class DebugDirectoryChunk : public NonSectionChunk {
public:
- DebugDirectoryChunk(COFFLinkerContext &c,
+ DebugDirectoryChunk(const COFFLinkerContext &c,
const std::vector<std::pair<COFF::DebugType, Chunk *>> &r,
bool writeRepro)
: records(r), writeRepro(writeRepro), ctx(c) {}
@@ -99,7 +99,7 @@ class DebugDirectoryChunk : public NonSectionChunk {
for (const std::pair<COFF::DebugType, Chunk *>& record : records) {
Chunk *c = record.second;
- OutputSection *os = ctx.getOutputSection(c);
+ const OutputSection *os = ctx.getOutputSection(c);
uint64_t offs = os->getFileOff() + (c->getRVA() - os->getRVA());
fillEntry(d, record.first, c->getSize(), c->getRVA(), offs);
++d;
@@ -138,14 +138,15 @@ class DebugDirectoryChunk : public NonSectionChunk {
mutable std::vector<support::ulittle32_t *> timeDateStamps;
const std::vector<std::pair<COFF::DebugType, Chunk *>> &records;
bool writeRepro;
-
- COFFLinkerContext &ctx;
+ const COFFLinkerContext &ctx;
};
class CVDebugRecordChunk : public NonSectionChunk {
public:
+ CVDebugRecordChunk(const COFFLinkerContext &c) : ctx(c) {}
+
size_t getSize() const override {
- return sizeof(codeview::DebugInfo) + config->pdbAltPath.size() + 1;
+ return sizeof(codeview::DebugInfo) + ctx.config.pdbAltPath.size() + 1;
}
void writeTo(uint8_t *b) const override {
@@ -155,12 +156,15 @@ class CVDebugRecordChunk : public NonSectionChunk {
// variable sized field (PDB Path)
char *p = reinterpret_cast<char *>(b + sizeof(*buildId));
- if (!config->pdbAltPath.empty())
- memcpy(p, config->pdbAltPath.data(), config->pdbAltPath.size());
- p[config->pdbAltPath.size()] = '\0';
+ if (!ctx.config.pdbAltPath.empty())
+ memcpy(p, ctx.config.pdbAltPath.data(), ctx.config.pdbAltPath.size());
+ p[ctx.config.pdbAltPath.size()] = '\0';
}
mutable codeview::DebugInfo *buildId = nullptr;
+
+private:
+ const COFFLinkerContext &ctx;
};
class ExtendedDllCharacteristicsChunk : public NonSectionChunk {
@@ -195,7 +199,8 @@ class PartialSectionKey {
// The writer writes a SymbolTable result to a file.
class Writer {
public:
- Writer(COFFLinkerContext &c) : buffer(errorHandler().outputBuffer), ctx(c) {}
+ Writer(COFFLinkerContext &c)
+ : buffer(errorHandler().outputBuffer), delayIdata(c), edata(c), ctx(c) {}
void run();
private:
@@ -208,6 +213,12 @@ class Writer {
void mergeSections();
void removeUnusedSections();
void assignAddresses();
+ bool isInRange(uint16_t relType, uint64_t s, uint64_t p, int margin);
+ std::pair<Defined *, bool> getThunk(DenseMap<uint64_t, Defined *> &lastThunks,
+ Defined *target, uint64_t p,
+ uint16_t type, int margin);
+ bool createThunks(OutputSection *os, int margin);
+ bool verifyRanges(const std::vector<Chunk *> chunks);
void finalizeAddresses();
void removeEmptySections();
void assignOutputSectionIndices();
@@ -217,6 +228,7 @@ class Writer {
void createSEHTable();
void createRuntimePseudoRelocs();
void insertCtorDtorSymbols();
+ void markSymbolsWithRelocations(ObjFile *file, SymbolRVASet &usedSymbols);
void createGuardCFTables();
void markSymbolsForRVATable(ObjFile *file,
ArrayRef<SectionChunk *> symIdxChunks,
@@ -234,6 +246,7 @@ class Writer {
void sortExceptionTable();
void sortCRTSectionChunks(std::vector<Chunk *> &chunks);
void addSyntheticIdata();
+ void sortBySectionOrder(std::vector<Chunk *> &chunks);
void fixPartialSectionChars(StringRef name, uint32_t chars);
bool fixGnuImportChunks();
void fixTlsAlignment();
@@ -331,14 +344,14 @@ void OutputSection::merge(OutputSection *other) {
}
// Write the section header to a given buffer.
-void OutputSection::writeHeaderTo(uint8_t *buf) {
+void OutputSection::writeHeaderTo(uint8_t *buf, bool isDebug) {
auto *hdr = reinterpret_cast<coff_section *>(buf);
*hdr = header;
if (stringTableOff) {
// If name is too long, write offset into the string table as a name.
encodeSectionName(hdr->Name, stringTableOff);
} else {
- assert(!config->debug || name.size() <= COFF::NameSize ||
+ assert(!isDebug || name.size() <= COFF::NameSize ||
(hdr->Characteristics & IMAGE_SCN_MEM_DISCARDABLE) == 0);
strncpy(hdr->Name, name.data(),
std::min(name.size(), (size_t)COFF::NameSize));
@@ -351,8 +364,8 @@ void OutputSection::addContributingPartialSection(PartialSection *sec) {
// Check whether the target address S is in range from a relocation
// of type relType at address P.
-static bool isInRange(uint16_t relType, uint64_t s, uint64_t p, int margin) {
- if (config->machine == ARMNT) {
+bool Writer::isInRange(uint16_t relType, uint64_t s, uint64_t p, int margin) {
+ if (ctx.config.machine == ARMNT) {
int64_t
diff = AbsoluteDifference(s, p + 4) + margin;
switch (relType) {
case IMAGE_REL_ARM_BRANCH20T:
@@ -363,7 +376,7 @@ static bool isInRange(uint16_t relType, uint64_t s, uint64_t p, int margin) {
default:
return true;
}
- } else if (config->machine == ARM64) {
+ } else if (ctx.config.machine == ARM64) {
int64_t
diff = AbsoluteDifference(s, p) + margin;
switch (relType) {
case IMAGE_REL_ARM64_BRANCH26:
@@ -382,19 +395,19 @@ static bool isInRange(uint16_t relType, uint64_t s, uint64_t p, int margin) {
// Return the last thunk for the given target if it is in range,
// or create a new one.
-static std::pair<Defined *, bool>
-getThunk(DenseMap<uint64_t, Defined *> &lastThunks, Defined *target, uint64_t p,
- uint16_t type, int margin) {
+std::pair<Defined *, bool>
+Writer::getThunk(DenseMap<uint64_t, Defined *> &lastThunks, Defined *target,
+ uint64_t p, uint16_t type, int margin) {
Defined *&lastThunk = lastThunks[target->getRVA()];
if (lastThunk && isInRange(type, lastThunk->getRVA(), p, margin))
return {lastThunk, false};
Chunk *c;
- switch (config->machine) {
+ switch (ctx.config.machine) {
case ARMNT:
- c = make<RangeExtensionThunkARM>(target);
+ c = make<RangeExtensionThunkARM>(ctx, target);
break;
case ARM64:
- c = make<RangeExtensionThunkARM64>(target);
+ c = make<RangeExtensionThunkARM64>(ctx, target);
break;
default:
llvm_unreachable("Unexpected architecture");
@@ -415,7 +428,7 @@ getThunk(DenseMap<uint64_t, Defined *> &lastThunks, Defined *target, uint64_t p,
// After adding thunks, we verify that all relocations are in range (with
// no extra margin requirements). If this failed, we restart (throwing away
// the previously created thunks) and retry with a wider margin.
-static bool createThunks(OutputSection *os, int margin) {
+bool Writer::createThunks(OutputSection *os, int margin) {
bool addressesChanged = false;
DenseMap<uint64_t, Defined *> lastThunks;
DenseMap<std::pair<ObjFile *, Defined *>, uint32_t> thunkSymtabIndices;
@@ -511,7 +524,7 @@ static bool createThunks(OutputSection *os, int margin) {
}
// Verify that all relocations are in range, with no extra margin requirements.
-static bool verifyRanges(const std::vector<Chunk *> chunks) {
+bool Writer::verifyRanges(const std::vector<Chunk *> chunks) {
for (Chunk *c : chunks) {
SectionChunk *sc = dyn_cast_or_null<SectionChunk>(c);
if (!sc)
@@ -539,7 +552,7 @@ static bool verifyRanges(const std::vector<Chunk *> chunks) {
// Assign addresses and add thunks if necessary.
void Writer::finalizeAddresses() {
assignAddresses();
- if (config->machine != ARMNT && config->machine != ARM64)
+ if (ctx.config.machine != ARMNT && ctx.config.machine != ARM64)
return;
size_t origNumChunks = 0;
@@ -600,7 +613,7 @@ void Writer::finalizeAddresses() {
}
void Writer::writePEChecksum() {
- if (!config->writeCheckSum) {
+ if (!ctx.config.writeCheckSum) {
return;
}
@@ -658,8 +671,8 @@ void Writer::run() {
fatal("image size (" + Twine(fileSize) + ") " +
"exceeds maximum allowable size (" + Twine(UINT32_MAX) + ")");
- openFile(config->outputFile);
- if (config->is64()) {
+ openFile(ctx.config.outputFile);
+ if (ctx.config.is64()) {
writeHeader<pe32plus_header>();
} else {
writeHeader<pe32_header>();
@@ -675,7 +688,7 @@ void Writer::run() {
t1.stop();
- if (!config->pdbPath.empty() && config->debug) {
+ if (!ctx.config.pdbPath.empty() && ctx.config.debug) {
assert(buildId);
createPDB(ctx, sectionTable, buildId->buildId);
}
@@ -704,11 +717,11 @@ static StringRef getOutputSectionName(StringRef name) {
}
// For /order.
-static void sortBySectionOrder(std::vector<Chunk *> &chunks) {
- auto getPriority = [](const Chunk *c) {
+void Writer::sortBySectionOrder(std::vector<Chunk *> &chunks) {
+ auto getPriority = [&ctx = ctx](const Chunk *c) {
if (auto *sec = dyn_cast<SectionChunk>(c))
if (sec->sym)
- return config->order.lookup(sec->sym->getName());
+ return ctx.config.order.lookup(sec->sym->getName());
return 0;
};
@@ -787,7 +800,7 @@ bool Writer::fixGnuImportChunks() {
// terminator in .idata$2.
void Writer::addSyntheticIdata() {
uint32_t rdata = IMAGE_SCN_CNT_INITIALIZED_DATA | IMAGE_SCN_MEM_READ;
- idata.create();
+ idata.create(ctx);
// Add the .idata content in the right section groups, to allow
// chunks from other linked in object files to be grouped together.
@@ -830,7 +843,8 @@ void Writer::locateImportTables() {
// Return whether a SectionChunk's suffix (the dollar and any trailing
// suffix) should be removed and sorted into the main suffixless
// PartialSection.
-static bool shouldStripSectionSuffix(SectionChunk *sc, StringRef name) {
+static bool shouldStripSectionSuffix(SectionChunk *sc, StringRef name,
+ bool isMinGW) {
// On MinGW, comdat groups are formed by putting the comdat group name
// after the '$' in the section name. For .eh_frame$<symbol>, that must
// still be sorted before the .eh_frame trailer from crtend.o, thus just
@@ -840,7 +854,7 @@ static bool shouldStripSectionSuffix(SectionChunk *sc, StringRef name) {
// hypothetical case of comdat .CRT$XCU, we definitely need to keep the
// suffix for sorting. Thus, to play it safe, only strip the suffix for
// the standard sections.
- if (!config->mingw)
+ if (!isMinGW)
return false;
if (!sc || !sc->isCOMDAT())
return false;
@@ -850,15 +864,15 @@ static bool shouldStripSectionSuffix(SectionChunk *sc, StringRef name) {
}
void Writer::sortSections() {
- if (!config->callGraphProfile.empty()) {
+ if (!ctx.config.callGraphProfile.empty()) {
DenseMap<const SectionChunk *, int> order =
computeCallGraphProfileOrder(ctx);
for (auto it : order) {
if (DefinedRegular *sym = it.first->sym)
- config->order[sym->getName()] = it.second;
+ ctx.config.order[sym->getName()] = it.second;
}
}
- if (!config->order.empty())
+ if (!ctx.config.order.empty())
for (auto it : partialSections)
sortBySectionOrder(it.second->chunks);
}
@@ -903,12 +917,12 @@ void Writer::createSections() {
for (Chunk *c : ctx.symtab.getChunks()) {
auto *sc = dyn_cast<SectionChunk>(c);
if (sc && !sc->live) {
- if (config->verbose)
+ if (ctx.config.verbose)
sc->printDiscardedMessage();
continue;
}
StringRef name = c->getSectionName();
- if (shouldStripSectionSuffix(sc, name))
+ if (shouldStripSectionSuffix(sc, name, ctx.config.mingw))
name = name.split('$').first;
if (name.startswith(".tls"))
@@ -990,6 +1004,8 @@ void Writer::createSections() {
}
void Writer::createMiscChunks() {
+ Configuration *config = &ctx.config;
+
for (MergeChunk *p : ctx.mergeChunkInstances) {
if (p) {
p->finalizeContents();
@@ -1017,7 +1033,7 @@ void Writer::createMiscChunks() {
// output a PDB no matter what, and this chunk provides the only means of
// allowing a debugger to match a PDB and an executable. So we need it even
// if we're ultimately not going to write CodeView data to the PDB.
- buildId = make<CVDebugRecordChunk>();
+ buildId = make<CVDebugRecordChunk>(ctx);
debugRecords.push_back({COFF::IMAGE_DEBUG_TYPE_CODEVIEW, buildId});
}
@@ -1061,16 +1077,16 @@ void Writer::createImportTables() {
continue;
std::string dll = StringRef(file->dllName).lower();
- if (config->dllOrder.count(dll) == 0)
- config->dllOrder[dll] = config->dllOrder.size();
+ if (ctx.config.dllOrder.count(dll) == 0)
+ ctx.config.dllOrder[dll] = ctx.config.dllOrder.size();
if (file->impSym && !isa<DefinedImportData>(file->impSym))
- fatal(toString(*file->impSym) + " was replaced");
+ fatal(toString(ctx, *file->impSym) + " was replaced");
DefinedImportData *impSym = cast_or_null<DefinedImportData>(file->impSym);
- if (config->delayLoads.count(StringRef(file->dllName).lower())) {
+ if (ctx.config.delayLoads.count(StringRef(file->dllName).lower())) {
if (!file->thunkSym)
fatal("cannot delay-load " + toString(file) +
- " due to import of data: " + toString(*impSym));
+ " due to import of data: " + toString(ctx, *impSym));
delayIdata.add(impSym);
} else {
idata.add(impSym);
@@ -1090,15 +1106,15 @@ void Writer::appendImportThunks() {
continue;
if (!isa<DefinedImportThunk>(file->thunkSym))
- fatal(toString(*file->thunkSym) + " was replaced");
+ fatal(toString(ctx, *file->thunkSym) + " was replaced");
DefinedImportThunk *thunk = cast<DefinedImportThunk>(file->thunkSym);
if (file->thunkLive)
textSec->addChunk(thunk->getChunk());
}
if (!delayIdata.empty()) {
- Defined *helper = cast<Defined>(config->delayLoadHelper);
- delayIdata.create(ctx, helper);
+ Defined *helper = cast<Defined>(ctx.config.delayLoadHelper);
+ delayIdata.create(helper);
for (Chunk *c : delayIdata.getChunks())
didatSec->addChunk(c);
for (Chunk *c : delayIdata.getDataChunks())
@@ -1112,9 +1128,9 @@ void Writer::createExportTable() {
if (!edataSec->chunks.empty()) {
// Allow using a custom built export table from input object files, instead
// of having the linker synthesize the tables.
- if (config->hadExplicitExports)
+ if (ctx.config.hadExplicitExports)
warn("literal .edata sections override exports");
- } else if (!config->exports.empty()) {
+ } else if (!ctx.config.exports.empty()) {
for (Chunk *c : edata.chunks)
edataSec->addChunk(c);
}
@@ -1123,9 +1139,9 @@ void Writer::createExportTable() {
edataEnd = edataSec->chunks.back();
}
// Warn on exported deleting destructor.
- for (auto e : config->exports)
+ for (auto e : ctx.config.exports)
if (e.sym && e.sym->getName().startswith("??_G"))
- warn("export of deleting dtor: " + toString(*e.sym));
+ warn("export of deleting dtor: " + toString(ctx, *e.sym));
}
void Writer::removeUnusedSections() {
@@ -1252,7 +1268,7 @@ void Writer::createSymbolAndStringTable() {
continue;
if ((sec->header.Characteristics & IMAGE_SCN_MEM_DISCARDABLE) == 0)
continue;
- if (config->warnLongSectionNames) {
+ if (ctx.config.warnLongSectionNames) {
warn("section name " + sec->name +
" is longer than 8 characters and will use a non-standard string "
"table");
@@ -1260,7 +1276,7 @@ void Writer::createSymbolAndStringTable() {
sec->setStringTableOff(addEntryToStringTable(sec->name));
}
- if (config->debugDwarf || config->debugSymtab) {
+ if (ctx.config.debugDwarf || ctx.config.debugSymtab) {
for (ObjFile *file : ctx.objFileInstances) {
for (Symbol *b : file->getSymbols()) {
auto *d = dyn_cast_or_null<Defined>(b);
@@ -1297,7 +1313,7 @@ void Writer::createSymbolAndStringTable() {
pointerToSymbolTable = fileOff;
fileOff += outputSymtab.size() * sizeof(coff_symbol16);
fileOff += 4 + strtab.size();
- fileSize = alignTo(fileOff, config->fileAlign);
+ fileSize = alignTo(fileOff, ctx.config.fileAlign);
}
void Writer::mergeSections() {
@@ -1306,7 +1322,7 @@ void Writer::mergeSections() {
lastPdata = pdataSec->chunks.back();
}
- for (auto &p : config->merge) {
+ for (auto &p : ctx.config.merge) {
StringRef toName = p.second;
if (p.first == toName)
continue;
@@ -1314,8 +1330,8 @@ void Writer::mergeSections() {
while (true) {
if (!names.insert(toName).second)
fatal("/merge: cycle found for section '" + p.first + "'");
- auto i = config->merge.find(toName);
- if (i == config->merge.end())
+ auto i = ctx.config.merge.find(toName);
+ if (i == ctx.config.merge.end())
break;
toName = i->second;
}
@@ -1334,6 +1350,8 @@ void Writer::mergeSections() {
// Visits all sections to assign incremental, non-overlapping RVAs and
// file offsets.
void Writer::assignAddresses() {
+ Configuration *config = &ctx.config;
+
sizeOfHeaders = dosStubSize + sizeof(PEMagic) + sizeof(coff_file_header) +
sizeof(data_directory) * numberOfDataDirectory +
sizeof(coff_section) * ctx.outputSections.size();
@@ -1391,6 +1409,7 @@ template <typename PEHeaderTy> void Writer::writeHeader() {
// under DOS, that program gets run (usually to just print an error message).
// When run under Windows, the loader looks at AddressOfNewExeHeader and uses
// the PE header instead.
+ Configuration *config = &ctx.config;
uint8_t *buf = buffer->getBufferStart();
auto *dos = reinterpret_cast<dos_header *>(buf);
buf += sizeof(dos_header);
@@ -1565,7 +1584,7 @@ template <typename PEHeaderTy> void Writer::writeHeader() {
// Write section table
for (OutputSection *sec : ctx.outputSections) {
- sec->writeHeaderTo(buf);
+ sec->writeHeaderTo(buf, config->debug);
buf += sizeof(coff_section);
}
sectionTable = ArrayRef<uint8_t>(
@@ -1674,8 +1693,8 @@ static void maybeAddAddressTakenFunction(SymbolRVASet &addressTakenSyms,
// Visit all relocations from all section contributions of this object file and
// mark the relocation target as address-taken.
-static void markSymbolsWithRelocations(ObjFile *file,
- SymbolRVASet &usedSymbols) {
+void Writer::markSymbolsWithRelocations(ObjFile *file,
+ SymbolRVASet &usedSymbols) {
for (Chunk *c : file->getChunks()) {
// We only care about live section chunks. Common chunks and other chunks
// don't generally contain relocations.
@@ -1684,7 +1703,8 @@ static void markSymbolsWithRelocations(ObjFile *file,
continue;
for (const coff_relocation &reloc : sc->getRelocs()) {
- if (config->machine == I386 && reloc.Type == COFF::IMAGE_REL_I386_REL32)
+ if (ctx.config.machine == I386 &&
+ reloc.Type == COFF::IMAGE_REL_I386_REL32)
// Ignore relative relocations on x86. On x86_64 they can't be ignored
// since they're also used to compute absolute addresses.
continue;
@@ -1699,6 +1719,8 @@ static void markSymbolsWithRelocations(ObjFile *file,
// address-taken functions. It is sorted and uniqued, just like the safe SEH
// table.
void Writer::createGuardCFTables() {
+ Configuration *config = &ctx.config;
+
SymbolRVASet addressTakenSyms;
SymbolRVASet giatsRVASet;
std::vector<Symbol *> giatsSymbols;
@@ -1862,7 +1884,7 @@ void Writer::createRuntimePseudoRelocs() {
sc->getRuntimePseudoRelocs(rels);
}
- if (!config->pseudoRelocs) {
+ if (!ctx.config.pseudoRelocs) {
// Not writing any pseudo relocs; if some were needed, error out and
// indicate what required them.
for (const RuntimePseudoReloc &rpr : rels)
@@ -1891,10 +1913,10 @@ void Writer::createRuntimePseudoRelocs() {
// There's a symbol pointing to the start sentinel pointer, __CTOR_LIST__
// and __DTOR_LIST__ respectively.
void Writer::insertCtorDtorSymbols() {
- AbsolutePointerChunk *ctorListHead = make<AbsolutePointerChunk>(-1);
- AbsolutePointerChunk *ctorListEnd = make<AbsolutePointerChunk>(0);
- AbsolutePointerChunk *dtorListHead = make<AbsolutePointerChunk>(-1);
- AbsolutePointerChunk *dtorListEnd = make<AbsolutePointerChunk>(0);
+ AbsolutePointerChunk *ctorListHead = make<AbsolutePointerChunk>(ctx, -1);
+ AbsolutePointerChunk *ctorListEnd = make<AbsolutePointerChunk>(ctx, 0);
+ AbsolutePointerChunk *dtorListHead = make<AbsolutePointerChunk>(ctx, -1);
+ AbsolutePointerChunk *dtorListEnd = make<AbsolutePointerChunk>(ctx, 0);
ctorsSec->insertChunkAtStart(ctorListHead);
ctorsSec->addChunk(ctorListEnd);
dtorsSec->insertChunkAtStart(dtorListHead);
@@ -1911,7 +1933,7 @@ void Writer::insertCtorDtorSymbols() {
// Handles /section options to allow users to overwrite
// section attributes.
void Writer::setSectionPermissions() {
- for (auto &p : config->section) {
+ for (auto &p : ctx.config.section) {
StringRef name = p.first;
uint32_t perm = p.second;
for (OutputSection *sec : ctx.outputSections)
@@ -1922,10 +1944,6 @@ void Writer::setSectionPermissions() {
// Write section contents to a mmap'ed file.
void Writer::writeSections() {
- // Record the number of sections to apply section index relocations
- // against absolute symbols. See applySecIdx in Chunks.cpp..
- DefinedAbsolute::numOutputSections = ctx.outputSections.size();
-
uint8_t *buf = buffer->getBufferStart();
for (OutputSection *sec : ctx.outputSections) {
uint8_t *secBuf = buf + sec->getFileOff();
@@ -1947,6 +1965,8 @@ void Writer::writeBuildId() {
// 2) In all cases, the PE COFF file header also contains a timestamp.
// For reproducibility, instead of a timestamp we want to use a hash of the
// PE contents.
+ Configuration *config = &ctx.config;
+
if (config->debug) {
assert(buildId && "BuildId is not set!");
// BuildId->BuildId was filled in when the PDB was written.
@@ -2003,7 +2023,7 @@ void Writer::sortExceptionTable() {
};
uint8_t *begin = bufAddr(firstPdata);
uint8_t *end = bufAddr(lastPdata) + lastPdata->getSize();
- if (config->machine == AMD64) {
+ if (ctx.config.machine == AMD64) {
struct Entry { ulittle32_t begin, end, unwind; };
if ((end - begin) % sizeof(Entry) != 0) {
fatal("unexpected .pdata size: " + Twine(end - begin) +
@@ -2014,7 +2034,7 @@ void Writer::sortExceptionTable() {
[](const Entry &a, const Entry &b) { return a.begin < b.begin; });
return;
}
- if (config->machine == ARMNT || config->machine == ARM64) {
+ if (ctx.config.machine == ARMNT || ctx.config.machine == ARM64) {
struct Entry { ulittle32_t begin, unwind; };
if ((end - begin) % sizeof(Entry) != 0) {
fatal("unexpected .pdata size: " + Twine(end - begin) +
@@ -2055,7 +2075,7 @@ void Writer::sortCRTSectionChunks(std::vector<Chunk *> &chunks) {
};
llvm::stable_sort(chunks, sectionChunkOrder);
- if (config->verbose) {
+ if (ctx.config.verbose) {
for (auto &c : chunks) {
auto sc = dyn_cast<SectionChunk>(c);
log(" " + sc->file->mb.getBufferIdentifier().str() +
@@ -2081,7 +2101,7 @@ uint32_t Writer::getSizeOfInitializedData() {
// Add base relocations to .reloc section.
void Writer::addBaserels() {
- if (!config->relocatable)
+ if (!ctx.config.relocatable)
return;
relocSec->chunks.clear();
std::vector<Baserel> v;
@@ -2144,14 +2164,14 @@ void Writer::fixTlsAlignment() {
uint8_t *secBuf = buffer->getBufferStart() + sec->getFileOff();
uint64_t tlsOffset = tlsSym->getRVA() - sec->getRVA();
- uint64_t directorySize = config->is64()
+ uint64_t directorySize = ctx.config.is64()
? sizeof(object::coff_tls_directory64)
: sizeof(object::coff_tls_directory32);
if (tlsOffset + directorySize > sec->getRawSize())
fatal("_tls_used sym is malformed");
- if (config->is64()) {
+ if (ctx.config.is64()) {
object::coff_tls_directory64 *tlsDir =
reinterpret_cast<object::coff_tls_directory64 *>(&secBuf[tlsOffset]);
tlsDir->setAlignment(tlsAlignment);
@@ -2166,7 +2186,7 @@ void Writer::checkLoadConfig() {
Symbol *sym = ctx.symtab.findUnderscore("_load_config_used");
auto *b = cast_if_present<DefinedRegular>(sym);
if (!b) {
- if (config->guardCF != GuardCFLevel::Off)
+ if (ctx.config.guardCF != GuardCFLevel::Off)
warn("Control Flow Guard is enabled but '_load_config_used' is missing");
return;
}
@@ -2175,7 +2195,7 @@ void Writer::checkLoadConfig() {
uint8_t *buf = buffer->getBufferStart();
uint8_t *secBuf = buf + sec->getFileOff();
uint8_t *symBuf = secBuf + (b->getRVA() - sec->getRVA());
- uint32_t expectedAlign = config->is64() ? 8 : 4;
+ uint32_t expectedAlign = ctx.config.is64() ? 8 : 4;
if (b->getChunk()->getAlignment() < expectedAlign)
warn("'_load_config_used' is misaligned (expected alignment to be " +
Twine(expectedAlign) + " bytes, got " +
@@ -2185,7 +2205,7 @@ void Writer::checkLoadConfig() {
Twine::utohexstr(b->getRVA()) + " not aligned to " +
Twine(expectedAlign) + " bytes)");
- if (config->is64())
+ if (ctx.config.is64())
checkLoadConfigGuardData(
reinterpret_cast<const coff_load_configuration64 *>(symBuf));
else
@@ -2208,7 +2228,7 @@ void Writer::checkLoadConfigGuardData(const T *loadConfig) {
#define CHECK_VA(field, sym) \
if (auto *s = dyn_cast<DefinedSynthetic>(ctx.symtab.findUnderscore(sym))) \
- if (loadConfig->field != config->imageBase + s->getRVA()) \
+ if (loadConfig->field != ctx.config.imageBase + s->getRVA()) \
warn(#field " not set correctly in '_load_config_used'");
#define CHECK_ABSOLUTE(field, sym) \
@@ -2216,7 +2236,7 @@ void Writer::checkLoadConfigGuardData(const T *loadConfig) {
if (loadConfig->field != s->getVA()) \
warn(#field " not set correctly in '_load_config_used'");
- if (config->guardCF == GuardCFLevel::Off)
+ if (ctx.config.guardCF == GuardCFLevel::Off)
return;
RETURN_IF_NOT_CONTAINS(GuardFlags)
CHECK_VA(GuardCFFunctionTable, "__guard_fids_table")
@@ -2227,13 +2247,13 @@ void Writer::checkLoadConfigGuardData(const T *loadConfig) {
CHECK_ABSOLUTE(GuardAddressTakenIatEntryCount, "__guard_iat_count")
}
- if (!(config->guardCF & GuardCFLevel::LongJmp))
+ if (!(ctx.config.guardCF & GuardCFLevel::LongJmp))
return;
RETURN_IF_NOT_CONTAINS(GuardLongJumpTargetCount)
CHECK_VA(GuardLongJumpTargetTable, "__guard_longjmp_table")
CHECK_ABSOLUTE(GuardLongJumpTargetCount, "__guard_longjmp_count")
- if (!(config->guardCF & GuardCFLevel::EHCont))
+ if (!(ctx.config.guardCF & GuardCFLevel::EHCont))
return;
RETURN_IF_NOT_CONTAINS(GuardEHContinuationCount)
CHECK_VA(GuardEHContinuationTable, "__guard_eh_cont_table")
diff --git a/lld/COFF/Writer.h b/lld/COFF/Writer.h
index d2c05e4ae0b5..4a74aa7ada59 100644
--- a/lld/COFF/Writer.h
+++ b/lld/COFF/Writer.h
@@ -45,9 +45,9 @@ class OutputSection {
void insertChunkAtStart(Chunk *c);
void merge(OutputSection *other);
void setPermissions(uint32_t c);
- uint64_t getRVA() { return header.VirtualAddress; }
- uint64_t getFileOff() { return header.PointerToRawData; }
- void writeHeaderTo(uint8_t *buf);
+ uint64_t getRVA() const { return header.VirtualAddress; }
+ uint64_t getFileOff() const { return header.PointerToRawData; }
+ void writeHeaderTo(uint8_t *buf, bool isDebug);
void addContributingPartialSection(PartialSection *sec);
// Returns the size of this section in an executable memory image.
More information about the llvm-commits
mailing list