aboutsummaryrefslogtreecommitdiff
path: root/contrib/llvm-project/lld/COFF/Writer.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'contrib/llvm-project/lld/COFF/Writer.cpp')
-rw-r--r--contrib/llvm-project/lld/COFF/Writer.cpp128
1 files changed, 108 insertions, 20 deletions
diff --git a/contrib/llvm-project/lld/COFF/Writer.cpp b/contrib/llvm-project/lld/COFF/Writer.cpp
index 0188f0971a75..5e8b8a624c3b 100644
--- a/contrib/llvm-project/lld/COFF/Writer.cpp
+++ b/contrib/llvm-project/lld/COFF/Writer.cpp
@@ -7,6 +7,7 @@
//===----------------------------------------------------------------------===//
#include "Writer.h"
+#include "CallGraphSort.h"
#include "Config.h"
#include "DLL.h"
#include "InputFiles.h"
@@ -87,6 +88,8 @@ OutputSection *Chunk::getOutputSection() const {
return osidx == 0 ? nullptr : outputSections[osidx - 1];
}
+void OutputSection::clear() { outputSections.clear(); }
+
namespace {
class DebugDirectoryChunk : public NonSectionChunk {
@@ -224,16 +227,21 @@ private:
void markSymbolsForRVATable(ObjFile *file,
ArrayRef<SectionChunk *> symIdxChunks,
SymbolRVASet &tableSymbols);
+ void getSymbolsFromSections(ObjFile *file,
+ ArrayRef<SectionChunk *> symIdxChunks,
+ std::vector<Symbol *> &symbols);
void maybeAddRVATable(SymbolRVASet tableSymbols, StringRef tableSym,
StringRef countSym);
void setSectionPermissions();
void writeSections();
void writeBuildId();
+ void sortSections();
void sortExceptionTable();
void sortCRTSectionChunks(std::vector<Chunk *> &chunks);
void addSyntheticIdata();
void fixPartialSectionChars(StringRef name, uint32_t chars);
bool fixGnuImportChunks();
+ void fixTlsAlignment();
PartialSection *createPartialSection(StringRef name, uint32_t outChars);
PartialSection *findPartialSection(StringRef name, uint32_t outChars);
@@ -260,6 +268,7 @@ private:
DelayLoadContents delayIdata;
EdataContents edata;
bool setNoSEHCharacteristic = false;
+ uint32_t tlsAlignment = 0;
DebugDirectoryChunk *debugDirectory = nullptr;
std::vector<std::pair<COFF::DebugType, Chunk *>> debugRecords;
@@ -604,8 +613,9 @@ void Writer::run() {
createImportTables();
createSections();
- createMiscChunks();
appendImportThunks();
+ // Import thunks must be added before the Control Flow Guard tables are added.
+ createMiscChunks();
createExportTable();
mergeSections();
removeUnusedSections();
@@ -628,6 +638,11 @@ void Writer::run() {
writeSections();
sortExceptionTable();
+ // Fix up the alignment in the TLS Directory's characteristic field,
+ // if a specific alignment value is needed
+ if (tlsAlignment)
+ fixTlsAlignment();
+
t1.stop();
if (!config->pdbPath.empty() && config->debug) {
@@ -801,6 +816,19 @@ static bool shouldStripSectionSuffix(SectionChunk *sc, StringRef name) {
name.startswith(".xdata$") || name.startswith(".eh_frame$");
}
+void Writer::sortSections() {
+ if (!config->callGraphProfile.empty()) {
+ DenseMap<const SectionChunk *, int> order = computeCallGraphProfileOrder();
+ for (auto it : order) {
+ if (DefinedRegular *sym = it.first->sym)
+ config->order[sym->getName()] = it.second;
+ }
+ }
+ if (!config->order.empty())
+ for (auto it : partialSections)
+ sortBySectionOrder(it.second->chunks);
+}
+
// Create output section objects and add them to OutputSections.
void Writer::createSections() {
// First, create the builtin sections.
@@ -848,6 +876,10 @@ void Writer::createSections() {
StringRef name = c->getSectionName();
if (shouldStripSectionSuffix(sc, name))
name = name.split('$').first;
+
+ if (name.startswith(".tls"))
+ tlsAlignment = std::max(tlsAlignment, c->getAlignment());
+
PartialSection *pSec = createPartialSection(name,
c->getOutputCharacteristics());
pSec->chunks.push_back(c);
@@ -864,10 +896,7 @@ void Writer::createSections() {
if (hasIdata)
addSyntheticIdata();
- // Process an /order option.
- if (!config->order.empty())
- for (auto it : partialSections)
- sortBySectionOrder(it.second->chunks);
+ sortSections();
if (hasIdata)
locateImportTables();
@@ -952,16 +981,15 @@ void Writer::createMiscChunks() {
}
if (config->cetCompat) {
- ExtendedDllCharacteristicsChunk *extendedDllChars =
- make<ExtendedDllCharacteristicsChunk>(
- IMAGE_DLL_CHARACTERISTICS_EX_CET_COMPAT);
- debugRecords.push_back(
- {COFF::IMAGE_DEBUG_TYPE_EX_DLLCHARACTERISTICS, extendedDllChars});
+ debugRecords.push_back({COFF::IMAGE_DEBUG_TYPE_EX_DLLCHARACTERISTICS,
+ make<ExtendedDllCharacteristicsChunk>(
+ IMAGE_DLL_CHARACTERISTICS_EX_CET_COMPAT)});
}
- if (debugRecords.size() > 0) {
- for (std::pair<COFF::DebugType, Chunk *> r : debugRecords)
- debugInfoSec->addChunk(r.second);
+ // Align and add each chunk referenced by the debug data directory.
+ for (std::pair<COFF::DebugType, Chunk *> r : debugRecords) {
+ r.second->setAlignment(4);
+ debugInfoSec->addChunk(r.second);
}
// Create SEH table. x86-only.
@@ -1362,8 +1390,8 @@ template <typename PEHeaderTy> void Writer::writeHeader() {
pe->MinorImageVersion = config->minorImageVersion;
pe->MajorOperatingSystemVersion = config->majorOSVersion;
pe->MinorOperatingSystemVersion = config->minorOSVersion;
- pe->MajorSubsystemVersion = config->majorOSVersion;
- pe->MinorSubsystemVersion = config->minorOSVersion;
+ pe->MajorSubsystemVersion = config->majorSubsystemVersion;
+ pe->MinorSubsystemVersion = config->minorSubsystemVersion;
pe->Subsystem = config->subsystem;
pe->SizeOfImage = sizeOfImage;
pe->SizeOfHeaders = sizeOfHeaders;
@@ -1607,6 +1635,8 @@ static void markSymbolsWithRelocations(ObjFile *file,
// table.
void Writer::createGuardCFTables() {
SymbolRVASet addressTakenSyms;
+ SymbolRVASet giatsRVASet;
+ std::vector<Symbol *> giatsSymbols;
SymbolRVASet longJmpTargets;
for (ObjFile *file : ObjFile::instances) {
// If the object was compiled with /guard:cf, the address taken symbols
@@ -1616,6 +1646,8 @@ void Writer::createGuardCFTables() {
// possibly address-taken.
if (file->hasGuardCF()) {
markSymbolsForRVATable(file, file->getGuardFidChunks(), addressTakenSyms);
+ markSymbolsForRVATable(file, file->getGuardIATChunks(), giatsRVASet);
+ getSymbolsFromSections(file, file->getGuardIATChunks(), giatsSymbols);
markSymbolsForRVATable(file, file->getGuardLJmpChunks(), longJmpTargets);
} else {
markSymbolsWithRelocations(file, addressTakenSyms);
@@ -1630,6 +1662,16 @@ void Writer::createGuardCFTables() {
for (Export &e : config->exports)
maybeAddAddressTakenFunction(addressTakenSyms, e.sym);
+ // For each entry in the .giats table, check if it has a corresponding load
+ // thunk (e.g. because the DLL that defines it will be delay-loaded) and, if
+ // so, add the load thunk to the address taken (.gfids) table.
+ for (Symbol *s : giatsSymbols) {
+ if (auto *di = dyn_cast<DefinedImportData>(s)) {
+ if (di->loadThunkSym)
+ addSymbolToRVASet(addressTakenSyms, di->loadThunkSym);
+ }
+ }
+
// Ensure sections referenced in the gfid table are 16-byte aligned.
for (const ChunkAndOffset &c : addressTakenSyms)
if (c.inputChunk->getAlignment() < 16)
@@ -1638,6 +1680,10 @@ void Writer::createGuardCFTables() {
maybeAddRVATable(std::move(addressTakenSyms), "__guard_fids_table",
"__guard_fids_count");
+ // Add the Guard Address Taken IAT Entry Table (.giats).
+ maybeAddRVATable(std::move(giatsRVASet), "__guard_iat_table",
+ "__guard_iat_count");
+
// Add the longjmp target table unless the user told us not to.
if (config->guardCF == GuardCFLevel::Full)
maybeAddRVATable(std::move(longJmpTargets), "__guard_longjmp_table",
@@ -1654,11 +1700,11 @@ void Writer::createGuardCFTables() {
}
// Take a list of input sections containing symbol table indices and add those
-// symbols to an RVA table. The challenge is that symbol RVAs are not known and
+// symbols to a vector. The challenge is that symbol RVAs are not known and
// depend on the table size, so we can't directly build a set of integers.
-void Writer::markSymbolsForRVATable(ObjFile *file,
+void Writer::getSymbolsFromSections(ObjFile *file,
ArrayRef<SectionChunk *> symIdxChunks,
- SymbolRVASet &tableSymbols) {
+ std::vector<Symbol *> &symbols) {
for (SectionChunk *c : symIdxChunks) {
// Skip sections discarded by linker GC. This comes up when a .gfids section
// is associated with something like a vtable and the vtable is discarded.
@@ -1676,7 +1722,7 @@ void Writer::markSymbolsForRVATable(ObjFile *file,
}
// Read each symbol table index and check if that symbol was included in the
- // final link. If so, add it to the table symbol set.
+ // final link. If so, add it to the vector of symbols.
ArrayRef<ulittle32_t> symIndices(
reinterpret_cast<const ulittle32_t *>(data.data()), data.size() / 4);
ArrayRef<Symbol *> objSymbols = file->getSymbols();
@@ -1688,12 +1734,24 @@ void Writer::markSymbolsForRVATable(ObjFile *file,
}
if (Symbol *s = objSymbols[symIndex]) {
if (s->isLive())
- addSymbolToRVASet(tableSymbols, cast<Defined>(s));
+ symbols.push_back(cast<Symbol>(s));
}
}
}
}
+// Take a list of input sections containing symbol table indices and add those
+// symbols to an RVA table.
+void Writer::markSymbolsForRVATable(ObjFile *file,
+ ArrayRef<SectionChunk *> symIdxChunks,
+ SymbolRVASet &tableSymbols) {
+ std::vector<Symbol *> syms;
+ getSymbolsFromSections(file, symIdxChunks, syms);
+
+ for (Symbol *s : syms)
+ addSymbolToRVASet(tableSymbols, cast<Defined>(s));
+}
+
// Replace the absolute table symbol with a synthetic symbol pointing to
// tableChunk so that we can emit base relocations for it and resolve section
// relative relocations.
@@ -1993,3 +2051,33 @@ PartialSection *Writer::findPartialSection(StringRef name, uint32_t outChars) {
return it->second;
return nullptr;
}
+
+void Writer::fixTlsAlignment() {
+ Defined *tlsSym =
+ dyn_cast_or_null<Defined>(symtab->findUnderscore("_tls_used"));
+ if (!tlsSym)
+ return;
+
+ OutputSection *sec = tlsSym->getChunk()->getOutputSection();
+ assert(sec && tlsSym->getRVA() >= sec->getRVA() &&
+ "no output section for _tls_used");
+
+ uint8_t *secBuf = buffer->getBufferStart() + sec->getFileOff();
+ uint64_t tlsOffset = tlsSym->getRVA() - sec->getRVA();
+ uint64_t directorySize = 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()) {
+ object::coff_tls_directory64 *tlsDir =
+ reinterpret_cast<object::coff_tls_directory64 *>(&secBuf[tlsOffset]);
+ tlsDir->setAlignment(tlsAlignment);
+ } else {
+ object::coff_tls_directory32 *tlsDir =
+ reinterpret_cast<object::coff_tls_directory32 *>(&secBuf[tlsOffset]);
+ tlsDir->setAlignment(tlsAlignment);
+ }
+}