diff options
Diffstat (limited to 'contrib/llvm-project/lld/COFF/Writer.cpp')
-rw-r--r-- | contrib/llvm-project/lld/COFF/Writer.cpp | 128 |
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); + } +} |