1*0b57cec5SDimitry Andric //===- Writer.cpp ---------------------------------------------------------===// 2*0b57cec5SDimitry Andric // 3*0b57cec5SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4*0b57cec5SDimitry Andric // See https://llvm.org/LICENSE.txt for license information. 5*0b57cec5SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6*0b57cec5SDimitry Andric // 7*0b57cec5SDimitry Andric //===----------------------------------------------------------------------===// 8*0b57cec5SDimitry Andric 9*0b57cec5SDimitry Andric #include "Writer.h" 10*0b57cec5SDimitry Andric #include "Config.h" 11*0b57cec5SDimitry Andric #include "DLL.h" 12*0b57cec5SDimitry Andric #include "InputFiles.h" 13*0b57cec5SDimitry Andric #include "MapFile.h" 14*0b57cec5SDimitry Andric #include "PDB.h" 15*0b57cec5SDimitry Andric #include "SymbolTable.h" 16*0b57cec5SDimitry Andric #include "Symbols.h" 17*0b57cec5SDimitry Andric #include "lld/Common/ErrorHandler.h" 18*0b57cec5SDimitry Andric #include "lld/Common/Memory.h" 19*0b57cec5SDimitry Andric #include "lld/Common/Threads.h" 20*0b57cec5SDimitry Andric #include "lld/Common/Timer.h" 21*0b57cec5SDimitry Andric #include "llvm/ADT/DenseMap.h" 22*0b57cec5SDimitry Andric #include "llvm/ADT/STLExtras.h" 23*0b57cec5SDimitry Andric #include "llvm/ADT/StringSwitch.h" 24*0b57cec5SDimitry Andric #include "llvm/Support/BinaryStreamReader.h" 25*0b57cec5SDimitry Andric #include "llvm/Support/Debug.h" 26*0b57cec5SDimitry Andric #include "llvm/Support/Endian.h" 27*0b57cec5SDimitry Andric #include "llvm/Support/FileOutputBuffer.h" 28*0b57cec5SDimitry Andric #include "llvm/Support/Parallel.h" 29*0b57cec5SDimitry Andric #include "llvm/Support/Path.h" 30*0b57cec5SDimitry Andric #include "llvm/Support/RandomNumberGenerator.h" 31*0b57cec5SDimitry Andric #include "llvm/Support/xxhash.h" 32*0b57cec5SDimitry Andric #include <algorithm> 33*0b57cec5SDimitry Andric #include <cstdio> 34*0b57cec5SDimitry Andric #include <map> 35*0b57cec5SDimitry Andric #include <memory> 36*0b57cec5SDimitry Andric #include <utility> 37*0b57cec5SDimitry Andric 38*0b57cec5SDimitry Andric using namespace llvm; 39*0b57cec5SDimitry Andric using namespace llvm::COFF; 40*0b57cec5SDimitry Andric using namespace llvm::object; 41*0b57cec5SDimitry Andric using namespace llvm::support; 42*0b57cec5SDimitry Andric using namespace llvm::support::endian; 43*0b57cec5SDimitry Andric using namespace lld; 44*0b57cec5SDimitry Andric using namespace lld::coff; 45*0b57cec5SDimitry Andric 46*0b57cec5SDimitry Andric /* To re-generate DOSProgram: 47*0b57cec5SDimitry Andric $ cat > /tmp/DOSProgram.asm 48*0b57cec5SDimitry Andric org 0 49*0b57cec5SDimitry Andric ; Copy cs to ds. 50*0b57cec5SDimitry Andric push cs 51*0b57cec5SDimitry Andric pop ds 52*0b57cec5SDimitry Andric ; Point ds:dx at the $-terminated string. 53*0b57cec5SDimitry Andric mov dx, str 54*0b57cec5SDimitry Andric ; Int 21/AH=09h: Write string to standard output. 55*0b57cec5SDimitry Andric mov ah, 0x9 56*0b57cec5SDimitry Andric int 0x21 57*0b57cec5SDimitry Andric ; Int 21/AH=4Ch: Exit with return code (in AL). 58*0b57cec5SDimitry Andric mov ax, 0x4C01 59*0b57cec5SDimitry Andric int 0x21 60*0b57cec5SDimitry Andric str: 61*0b57cec5SDimitry Andric db 'This program cannot be run in DOS mode.$' 62*0b57cec5SDimitry Andric align 8, db 0 63*0b57cec5SDimitry Andric $ nasm -fbin /tmp/DOSProgram.asm -o /tmp/DOSProgram.bin 64*0b57cec5SDimitry Andric $ xxd -i /tmp/DOSProgram.bin 65*0b57cec5SDimitry Andric */ 66*0b57cec5SDimitry Andric static unsigned char dosProgram[] = { 67*0b57cec5SDimitry Andric 0x0e, 0x1f, 0xba, 0x0e, 0x00, 0xb4, 0x09, 0xcd, 0x21, 0xb8, 0x01, 0x4c, 68*0b57cec5SDimitry Andric 0xcd, 0x21, 0x54, 0x68, 0x69, 0x73, 0x20, 0x70, 0x72, 0x6f, 0x67, 0x72, 69*0b57cec5SDimitry Andric 0x61, 0x6d, 0x20, 0x63, 0x61, 0x6e, 0x6e, 0x6f, 0x74, 0x20, 0x62, 0x65, 70*0b57cec5SDimitry Andric 0x20, 0x72, 0x75, 0x6e, 0x20, 0x69, 0x6e, 0x20, 0x44, 0x4f, 0x53, 0x20, 71*0b57cec5SDimitry Andric 0x6d, 0x6f, 0x64, 0x65, 0x2e, 0x24, 0x00, 0x00 72*0b57cec5SDimitry Andric }; 73*0b57cec5SDimitry Andric static_assert(sizeof(dosProgram) % 8 == 0, 74*0b57cec5SDimitry Andric "DOSProgram size must be multiple of 8"); 75*0b57cec5SDimitry Andric 76*0b57cec5SDimitry Andric static const int dosStubSize = sizeof(dos_header) + sizeof(dosProgram); 77*0b57cec5SDimitry Andric static_assert(dosStubSize % 8 == 0, "DOSStub size must be multiple of 8"); 78*0b57cec5SDimitry Andric 79*0b57cec5SDimitry Andric static const int numberOfDataDirectory = 16; 80*0b57cec5SDimitry Andric 81*0b57cec5SDimitry Andric // Global vector of all output sections. After output sections are finalized, 82*0b57cec5SDimitry Andric // this can be indexed by Chunk::getOutputSection. 83*0b57cec5SDimitry Andric static std::vector<OutputSection *> outputSections; 84*0b57cec5SDimitry Andric 85*0b57cec5SDimitry Andric OutputSection *Chunk::getOutputSection() const { 86*0b57cec5SDimitry Andric return osidx == 0 ? nullptr : outputSections[osidx - 1]; 87*0b57cec5SDimitry Andric } 88*0b57cec5SDimitry Andric 89*0b57cec5SDimitry Andric namespace { 90*0b57cec5SDimitry Andric 91*0b57cec5SDimitry Andric class DebugDirectoryChunk : public NonSectionChunk { 92*0b57cec5SDimitry Andric public: 93*0b57cec5SDimitry Andric DebugDirectoryChunk(const std::vector<Chunk *> &r, bool writeRepro) 94*0b57cec5SDimitry Andric : records(r), writeRepro(writeRepro) {} 95*0b57cec5SDimitry Andric 96*0b57cec5SDimitry Andric size_t getSize() const override { 97*0b57cec5SDimitry Andric return (records.size() + int(writeRepro)) * sizeof(debug_directory); 98*0b57cec5SDimitry Andric } 99*0b57cec5SDimitry Andric 100*0b57cec5SDimitry Andric void writeTo(uint8_t *b) const override { 101*0b57cec5SDimitry Andric auto *d = reinterpret_cast<debug_directory *>(b); 102*0b57cec5SDimitry Andric 103*0b57cec5SDimitry Andric for (const Chunk *record : records) { 104*0b57cec5SDimitry Andric OutputSection *os = record->getOutputSection(); 105*0b57cec5SDimitry Andric uint64_t offs = os->getFileOff() + (record->getRVA() - os->getRVA()); 106*0b57cec5SDimitry Andric fillEntry(d, COFF::IMAGE_DEBUG_TYPE_CODEVIEW, record->getSize(), 107*0b57cec5SDimitry Andric record->getRVA(), offs); 108*0b57cec5SDimitry Andric ++d; 109*0b57cec5SDimitry Andric } 110*0b57cec5SDimitry Andric 111*0b57cec5SDimitry Andric if (writeRepro) { 112*0b57cec5SDimitry Andric // FIXME: The COFF spec allows either a 0-sized entry to just say 113*0b57cec5SDimitry Andric // "the timestamp field is really a hash", or a 4-byte size field 114*0b57cec5SDimitry Andric // followed by that many bytes containing a longer hash (with the 115*0b57cec5SDimitry Andric // lowest 4 bytes usually being the timestamp in little-endian order). 116*0b57cec5SDimitry Andric // Consider storing the full 8 bytes computed by xxHash64 here. 117*0b57cec5SDimitry Andric fillEntry(d, COFF::IMAGE_DEBUG_TYPE_REPRO, 0, 0, 0); 118*0b57cec5SDimitry Andric } 119*0b57cec5SDimitry Andric } 120*0b57cec5SDimitry Andric 121*0b57cec5SDimitry Andric void setTimeDateStamp(uint32_t timeDateStamp) { 122*0b57cec5SDimitry Andric for (support::ulittle32_t *tds : timeDateStamps) 123*0b57cec5SDimitry Andric *tds = timeDateStamp; 124*0b57cec5SDimitry Andric } 125*0b57cec5SDimitry Andric 126*0b57cec5SDimitry Andric private: 127*0b57cec5SDimitry Andric void fillEntry(debug_directory *d, COFF::DebugType debugType, size_t size, 128*0b57cec5SDimitry Andric uint64_t rva, uint64_t offs) const { 129*0b57cec5SDimitry Andric d->Characteristics = 0; 130*0b57cec5SDimitry Andric d->TimeDateStamp = 0; 131*0b57cec5SDimitry Andric d->MajorVersion = 0; 132*0b57cec5SDimitry Andric d->MinorVersion = 0; 133*0b57cec5SDimitry Andric d->Type = debugType; 134*0b57cec5SDimitry Andric d->SizeOfData = size; 135*0b57cec5SDimitry Andric d->AddressOfRawData = rva; 136*0b57cec5SDimitry Andric d->PointerToRawData = offs; 137*0b57cec5SDimitry Andric 138*0b57cec5SDimitry Andric timeDateStamps.push_back(&d->TimeDateStamp); 139*0b57cec5SDimitry Andric } 140*0b57cec5SDimitry Andric 141*0b57cec5SDimitry Andric mutable std::vector<support::ulittle32_t *> timeDateStamps; 142*0b57cec5SDimitry Andric const std::vector<Chunk *> &records; 143*0b57cec5SDimitry Andric bool writeRepro; 144*0b57cec5SDimitry Andric }; 145*0b57cec5SDimitry Andric 146*0b57cec5SDimitry Andric class CVDebugRecordChunk : public NonSectionChunk { 147*0b57cec5SDimitry Andric public: 148*0b57cec5SDimitry Andric size_t getSize() const override { 149*0b57cec5SDimitry Andric return sizeof(codeview::DebugInfo) + config->pdbAltPath.size() + 1; 150*0b57cec5SDimitry Andric } 151*0b57cec5SDimitry Andric 152*0b57cec5SDimitry Andric void writeTo(uint8_t *b) const override { 153*0b57cec5SDimitry Andric // Save off the DebugInfo entry to backfill the file signature (build id) 154*0b57cec5SDimitry Andric // in Writer::writeBuildId 155*0b57cec5SDimitry Andric buildId = reinterpret_cast<codeview::DebugInfo *>(b); 156*0b57cec5SDimitry Andric 157*0b57cec5SDimitry Andric // variable sized field (PDB Path) 158*0b57cec5SDimitry Andric char *p = reinterpret_cast<char *>(b + sizeof(*buildId)); 159*0b57cec5SDimitry Andric if (!config->pdbAltPath.empty()) 160*0b57cec5SDimitry Andric memcpy(p, config->pdbAltPath.data(), config->pdbAltPath.size()); 161*0b57cec5SDimitry Andric p[config->pdbAltPath.size()] = '\0'; 162*0b57cec5SDimitry Andric } 163*0b57cec5SDimitry Andric 164*0b57cec5SDimitry Andric mutable codeview::DebugInfo *buildId = nullptr; 165*0b57cec5SDimitry Andric }; 166*0b57cec5SDimitry Andric 167*0b57cec5SDimitry Andric // PartialSection represents a group of chunks that contribute to an 168*0b57cec5SDimitry Andric // OutputSection. Collating a collection of PartialSections of same name and 169*0b57cec5SDimitry Andric // characteristics constitutes the OutputSection. 170*0b57cec5SDimitry Andric class PartialSectionKey { 171*0b57cec5SDimitry Andric public: 172*0b57cec5SDimitry Andric StringRef name; 173*0b57cec5SDimitry Andric unsigned characteristics; 174*0b57cec5SDimitry Andric 175*0b57cec5SDimitry Andric bool operator<(const PartialSectionKey &other) const { 176*0b57cec5SDimitry Andric int c = name.compare(other.name); 177*0b57cec5SDimitry Andric if (c == 1) 178*0b57cec5SDimitry Andric return false; 179*0b57cec5SDimitry Andric if (c == 0) 180*0b57cec5SDimitry Andric return characteristics < other.characteristics; 181*0b57cec5SDimitry Andric return true; 182*0b57cec5SDimitry Andric } 183*0b57cec5SDimitry Andric }; 184*0b57cec5SDimitry Andric 185*0b57cec5SDimitry Andric // The writer writes a SymbolTable result to a file. 186*0b57cec5SDimitry Andric class Writer { 187*0b57cec5SDimitry Andric public: 188*0b57cec5SDimitry Andric Writer() : buffer(errorHandler().outputBuffer) {} 189*0b57cec5SDimitry Andric void run(); 190*0b57cec5SDimitry Andric 191*0b57cec5SDimitry Andric private: 192*0b57cec5SDimitry Andric void createSections(); 193*0b57cec5SDimitry Andric void createMiscChunks(); 194*0b57cec5SDimitry Andric void createImportTables(); 195*0b57cec5SDimitry Andric void appendImportThunks(); 196*0b57cec5SDimitry Andric void locateImportTables(); 197*0b57cec5SDimitry Andric void createExportTable(); 198*0b57cec5SDimitry Andric void mergeSections(); 199*0b57cec5SDimitry Andric void removeUnusedSections(); 200*0b57cec5SDimitry Andric void assignAddresses(); 201*0b57cec5SDimitry Andric void finalizeAddresses(); 202*0b57cec5SDimitry Andric void removeEmptySections(); 203*0b57cec5SDimitry Andric void assignOutputSectionIndices(); 204*0b57cec5SDimitry Andric void createSymbolAndStringTable(); 205*0b57cec5SDimitry Andric void openFile(StringRef outputPath); 206*0b57cec5SDimitry Andric template <typename PEHeaderTy> void writeHeader(); 207*0b57cec5SDimitry Andric void createSEHTable(); 208*0b57cec5SDimitry Andric void createRuntimePseudoRelocs(); 209*0b57cec5SDimitry Andric void insertCtorDtorSymbols(); 210*0b57cec5SDimitry Andric void createGuardCFTables(); 211*0b57cec5SDimitry Andric void markSymbolsForRVATable(ObjFile *file, 212*0b57cec5SDimitry Andric ArrayRef<SectionChunk *> symIdxChunks, 213*0b57cec5SDimitry Andric SymbolRVASet &tableSymbols); 214*0b57cec5SDimitry Andric void maybeAddRVATable(SymbolRVASet tableSymbols, StringRef tableSym, 215*0b57cec5SDimitry Andric StringRef countSym); 216*0b57cec5SDimitry Andric void setSectionPermissions(); 217*0b57cec5SDimitry Andric void writeSections(); 218*0b57cec5SDimitry Andric void writeBuildId(); 219*0b57cec5SDimitry Andric void sortExceptionTable(); 220*0b57cec5SDimitry Andric void sortCRTSectionChunks(std::vector<Chunk *> &chunks); 221*0b57cec5SDimitry Andric void addSyntheticIdata(); 222*0b57cec5SDimitry Andric void fixPartialSectionChars(StringRef name, uint32_t chars); 223*0b57cec5SDimitry Andric bool fixGnuImportChunks(); 224*0b57cec5SDimitry Andric PartialSection *createPartialSection(StringRef name, uint32_t outChars); 225*0b57cec5SDimitry Andric PartialSection *findPartialSection(StringRef name, uint32_t outChars); 226*0b57cec5SDimitry Andric 227*0b57cec5SDimitry Andric llvm::Optional<coff_symbol16> createSymbol(Defined *d); 228*0b57cec5SDimitry Andric size_t addEntryToStringTable(StringRef str); 229*0b57cec5SDimitry Andric 230*0b57cec5SDimitry Andric OutputSection *findSection(StringRef name); 231*0b57cec5SDimitry Andric void addBaserels(); 232*0b57cec5SDimitry Andric void addBaserelBlocks(std::vector<Baserel> &v); 233*0b57cec5SDimitry Andric 234*0b57cec5SDimitry Andric uint32_t getSizeOfInitializedData(); 235*0b57cec5SDimitry Andric 236*0b57cec5SDimitry Andric std::unique_ptr<FileOutputBuffer> &buffer; 237*0b57cec5SDimitry Andric std::map<PartialSectionKey, PartialSection *> partialSections; 238*0b57cec5SDimitry Andric std::vector<char> strtab; 239*0b57cec5SDimitry Andric std::vector<llvm::object::coff_symbol16> outputSymtab; 240*0b57cec5SDimitry Andric IdataContents idata; 241*0b57cec5SDimitry Andric Chunk *importTableStart = nullptr; 242*0b57cec5SDimitry Andric uint64_t importTableSize = 0; 243*0b57cec5SDimitry Andric Chunk *iatStart = nullptr; 244*0b57cec5SDimitry Andric uint64_t iatSize = 0; 245*0b57cec5SDimitry Andric DelayLoadContents delayIdata; 246*0b57cec5SDimitry Andric EdataContents edata; 247*0b57cec5SDimitry Andric bool setNoSEHCharacteristic = false; 248*0b57cec5SDimitry Andric 249*0b57cec5SDimitry Andric DebugDirectoryChunk *debugDirectory = nullptr; 250*0b57cec5SDimitry Andric std::vector<Chunk *> debugRecords; 251*0b57cec5SDimitry Andric CVDebugRecordChunk *buildId = nullptr; 252*0b57cec5SDimitry Andric ArrayRef<uint8_t> sectionTable; 253*0b57cec5SDimitry Andric 254*0b57cec5SDimitry Andric uint64_t fileSize; 255*0b57cec5SDimitry Andric uint32_t pointerToSymbolTable = 0; 256*0b57cec5SDimitry Andric uint64_t sizeOfImage; 257*0b57cec5SDimitry Andric uint64_t sizeOfHeaders; 258*0b57cec5SDimitry Andric 259*0b57cec5SDimitry Andric OutputSection *textSec; 260*0b57cec5SDimitry Andric OutputSection *rdataSec; 261*0b57cec5SDimitry Andric OutputSection *buildidSec; 262*0b57cec5SDimitry Andric OutputSection *dataSec; 263*0b57cec5SDimitry Andric OutputSection *pdataSec; 264*0b57cec5SDimitry Andric OutputSection *idataSec; 265*0b57cec5SDimitry Andric OutputSection *edataSec; 266*0b57cec5SDimitry Andric OutputSection *didatSec; 267*0b57cec5SDimitry Andric OutputSection *rsrcSec; 268*0b57cec5SDimitry Andric OutputSection *relocSec; 269*0b57cec5SDimitry Andric OutputSection *ctorsSec; 270*0b57cec5SDimitry Andric OutputSection *dtorsSec; 271*0b57cec5SDimitry Andric 272*0b57cec5SDimitry Andric // The first and last .pdata sections in the output file. 273*0b57cec5SDimitry Andric // 274*0b57cec5SDimitry Andric // We need to keep track of the location of .pdata in whichever section it 275*0b57cec5SDimitry Andric // gets merged into so that we can sort its contents and emit a correct data 276*0b57cec5SDimitry Andric // directory entry for the exception table. This is also the case for some 277*0b57cec5SDimitry Andric // other sections (such as .edata) but because the contents of those sections 278*0b57cec5SDimitry Andric // are entirely linker-generated we can keep track of their locations using 279*0b57cec5SDimitry Andric // the chunks that the linker creates. All .pdata chunks come from input 280*0b57cec5SDimitry Andric // files, so we need to keep track of them separately. 281*0b57cec5SDimitry Andric Chunk *firstPdata = nullptr; 282*0b57cec5SDimitry Andric Chunk *lastPdata; 283*0b57cec5SDimitry Andric }; 284*0b57cec5SDimitry Andric } // anonymous namespace 285*0b57cec5SDimitry Andric 286*0b57cec5SDimitry Andric namespace lld { 287*0b57cec5SDimitry Andric namespace coff { 288*0b57cec5SDimitry Andric 289*0b57cec5SDimitry Andric static Timer codeLayoutTimer("Code Layout", Timer::root()); 290*0b57cec5SDimitry Andric static Timer diskCommitTimer("Commit Output File", Timer::root()); 291*0b57cec5SDimitry Andric 292*0b57cec5SDimitry Andric void writeResult() { Writer().run(); } 293*0b57cec5SDimitry Andric 294*0b57cec5SDimitry Andric void OutputSection::addChunk(Chunk *c) { 295*0b57cec5SDimitry Andric chunks.push_back(c); 296*0b57cec5SDimitry Andric } 297*0b57cec5SDimitry Andric 298*0b57cec5SDimitry Andric void OutputSection::insertChunkAtStart(Chunk *c) { 299*0b57cec5SDimitry Andric chunks.insert(chunks.begin(), c); 300*0b57cec5SDimitry Andric } 301*0b57cec5SDimitry Andric 302*0b57cec5SDimitry Andric void OutputSection::setPermissions(uint32_t c) { 303*0b57cec5SDimitry Andric header.Characteristics &= ~permMask; 304*0b57cec5SDimitry Andric header.Characteristics |= c; 305*0b57cec5SDimitry Andric } 306*0b57cec5SDimitry Andric 307*0b57cec5SDimitry Andric void OutputSection::merge(OutputSection *other) { 308*0b57cec5SDimitry Andric chunks.insert(chunks.end(), other->chunks.begin(), other->chunks.end()); 309*0b57cec5SDimitry Andric other->chunks.clear(); 310*0b57cec5SDimitry Andric contribSections.insert(contribSections.end(), other->contribSections.begin(), 311*0b57cec5SDimitry Andric other->contribSections.end()); 312*0b57cec5SDimitry Andric other->contribSections.clear(); 313*0b57cec5SDimitry Andric } 314*0b57cec5SDimitry Andric 315*0b57cec5SDimitry Andric // Write the section header to a given buffer. 316*0b57cec5SDimitry Andric void OutputSection::writeHeaderTo(uint8_t *buf) { 317*0b57cec5SDimitry Andric auto *hdr = reinterpret_cast<coff_section *>(buf); 318*0b57cec5SDimitry Andric *hdr = header; 319*0b57cec5SDimitry Andric if (stringTableOff) { 320*0b57cec5SDimitry Andric // If name is too long, write offset into the string table as a name. 321*0b57cec5SDimitry Andric sprintf(hdr->Name, "/%d", stringTableOff); 322*0b57cec5SDimitry Andric } else { 323*0b57cec5SDimitry Andric assert(!config->debug || name.size() <= COFF::NameSize || 324*0b57cec5SDimitry Andric (hdr->Characteristics & IMAGE_SCN_MEM_DISCARDABLE) == 0); 325*0b57cec5SDimitry Andric strncpy(hdr->Name, name.data(), 326*0b57cec5SDimitry Andric std::min(name.size(), (size_t)COFF::NameSize)); 327*0b57cec5SDimitry Andric } 328*0b57cec5SDimitry Andric } 329*0b57cec5SDimitry Andric 330*0b57cec5SDimitry Andric void OutputSection::addContributingPartialSection(PartialSection *sec) { 331*0b57cec5SDimitry Andric contribSections.push_back(sec); 332*0b57cec5SDimitry Andric } 333*0b57cec5SDimitry Andric 334*0b57cec5SDimitry Andric } // namespace coff 335*0b57cec5SDimitry Andric } // namespace lld 336*0b57cec5SDimitry Andric 337*0b57cec5SDimitry Andric // Check whether the target address S is in range from a relocation 338*0b57cec5SDimitry Andric // of type relType at address P. 339*0b57cec5SDimitry Andric static bool isInRange(uint16_t relType, uint64_t s, uint64_t p, int margin) { 340*0b57cec5SDimitry Andric if (config->machine == ARMNT) { 341*0b57cec5SDimitry Andric int64_t diff = AbsoluteDifference(s, p + 4) + margin; 342*0b57cec5SDimitry Andric switch (relType) { 343*0b57cec5SDimitry Andric case IMAGE_REL_ARM_BRANCH20T: 344*0b57cec5SDimitry Andric return isInt<21>(diff); 345*0b57cec5SDimitry Andric case IMAGE_REL_ARM_BRANCH24T: 346*0b57cec5SDimitry Andric case IMAGE_REL_ARM_BLX23T: 347*0b57cec5SDimitry Andric return isInt<25>(diff); 348*0b57cec5SDimitry Andric default: 349*0b57cec5SDimitry Andric return true; 350*0b57cec5SDimitry Andric } 351*0b57cec5SDimitry Andric } else if (config->machine == ARM64) { 352*0b57cec5SDimitry Andric int64_t diff = AbsoluteDifference(s, p) + margin; 353*0b57cec5SDimitry Andric switch (relType) { 354*0b57cec5SDimitry Andric case IMAGE_REL_ARM64_BRANCH26: 355*0b57cec5SDimitry Andric return isInt<28>(diff); 356*0b57cec5SDimitry Andric case IMAGE_REL_ARM64_BRANCH19: 357*0b57cec5SDimitry Andric return isInt<21>(diff); 358*0b57cec5SDimitry Andric case IMAGE_REL_ARM64_BRANCH14: 359*0b57cec5SDimitry Andric return isInt<16>(diff); 360*0b57cec5SDimitry Andric default: 361*0b57cec5SDimitry Andric return true; 362*0b57cec5SDimitry Andric } 363*0b57cec5SDimitry Andric } else { 364*0b57cec5SDimitry Andric llvm_unreachable("Unexpected architecture"); 365*0b57cec5SDimitry Andric } 366*0b57cec5SDimitry Andric } 367*0b57cec5SDimitry Andric 368*0b57cec5SDimitry Andric // Return the last thunk for the given target if it is in range, 369*0b57cec5SDimitry Andric // or create a new one. 370*0b57cec5SDimitry Andric static std::pair<Defined *, bool> 371*0b57cec5SDimitry Andric getThunk(DenseMap<uint64_t, Defined *> &lastThunks, Defined *target, uint64_t p, 372*0b57cec5SDimitry Andric uint16_t type, int margin) { 373*0b57cec5SDimitry Andric Defined *&lastThunk = lastThunks[target->getRVA()]; 374*0b57cec5SDimitry Andric if (lastThunk && isInRange(type, lastThunk->getRVA(), p, margin)) 375*0b57cec5SDimitry Andric return {lastThunk, false}; 376*0b57cec5SDimitry Andric Chunk *c; 377*0b57cec5SDimitry Andric switch (config->machine) { 378*0b57cec5SDimitry Andric case ARMNT: 379*0b57cec5SDimitry Andric c = make<RangeExtensionThunkARM>(target); 380*0b57cec5SDimitry Andric break; 381*0b57cec5SDimitry Andric case ARM64: 382*0b57cec5SDimitry Andric c = make<RangeExtensionThunkARM64>(target); 383*0b57cec5SDimitry Andric break; 384*0b57cec5SDimitry Andric default: 385*0b57cec5SDimitry Andric llvm_unreachable("Unexpected architecture"); 386*0b57cec5SDimitry Andric } 387*0b57cec5SDimitry Andric Defined *d = make<DefinedSynthetic>("", c); 388*0b57cec5SDimitry Andric lastThunk = d; 389*0b57cec5SDimitry Andric return {d, true}; 390*0b57cec5SDimitry Andric } 391*0b57cec5SDimitry Andric 392*0b57cec5SDimitry Andric // This checks all relocations, and for any relocation which isn't in range 393*0b57cec5SDimitry Andric // it adds a thunk after the section chunk that contains the relocation. 394*0b57cec5SDimitry Andric // If the latest thunk for the specific target is in range, that is used 395*0b57cec5SDimitry Andric // instead of creating a new thunk. All range checks are done with the 396*0b57cec5SDimitry Andric // specified margin, to make sure that relocations that originally are in 397*0b57cec5SDimitry Andric // range, but only barely, also get thunks - in case other added thunks makes 398*0b57cec5SDimitry Andric // the target go out of range. 399*0b57cec5SDimitry Andric // 400*0b57cec5SDimitry Andric // After adding thunks, we verify that all relocations are in range (with 401*0b57cec5SDimitry Andric // no extra margin requirements). If this failed, we restart (throwing away 402*0b57cec5SDimitry Andric // the previously created thunks) and retry with a wider margin. 403*0b57cec5SDimitry Andric static bool createThunks(OutputSection *os, int margin) { 404*0b57cec5SDimitry Andric bool addressesChanged = false; 405*0b57cec5SDimitry Andric DenseMap<uint64_t, Defined *> lastThunks; 406*0b57cec5SDimitry Andric DenseMap<std::pair<ObjFile *, Defined *>, uint32_t> thunkSymtabIndices; 407*0b57cec5SDimitry Andric size_t thunksSize = 0; 408*0b57cec5SDimitry Andric // Recheck Chunks.size() each iteration, since we can insert more 409*0b57cec5SDimitry Andric // elements into it. 410*0b57cec5SDimitry Andric for (size_t i = 0; i != os->chunks.size(); ++i) { 411*0b57cec5SDimitry Andric SectionChunk *sc = dyn_cast_or_null<SectionChunk>(os->chunks[i]); 412*0b57cec5SDimitry Andric if (!sc) 413*0b57cec5SDimitry Andric continue; 414*0b57cec5SDimitry Andric size_t thunkInsertionSpot = i + 1; 415*0b57cec5SDimitry Andric 416*0b57cec5SDimitry Andric // Try to get a good enough estimate of where new thunks will be placed. 417*0b57cec5SDimitry Andric // Offset this by the size of the new thunks added so far, to make the 418*0b57cec5SDimitry Andric // estimate slightly better. 419*0b57cec5SDimitry Andric size_t thunkInsertionRVA = sc->getRVA() + sc->getSize() + thunksSize; 420*0b57cec5SDimitry Andric ObjFile *file = sc->file; 421*0b57cec5SDimitry Andric std::vector<std::pair<uint32_t, uint32_t>> relocReplacements; 422*0b57cec5SDimitry Andric ArrayRef<coff_relocation> originalRelocs = 423*0b57cec5SDimitry Andric file->getCOFFObj()->getRelocations(sc->header); 424*0b57cec5SDimitry Andric for (size_t j = 0, e = originalRelocs.size(); j < e; ++j) { 425*0b57cec5SDimitry Andric const coff_relocation &rel = originalRelocs[j]; 426*0b57cec5SDimitry Andric Symbol *relocTarget = file->getSymbol(rel.SymbolTableIndex); 427*0b57cec5SDimitry Andric 428*0b57cec5SDimitry Andric // The estimate of the source address P should be pretty accurate, 429*0b57cec5SDimitry Andric // but we don't know whether the target Symbol address should be 430*0b57cec5SDimitry Andric // offset by thunksSize or not (or by some of thunksSize but not all of 431*0b57cec5SDimitry Andric // it), giving us some uncertainty once we have added one thunk. 432*0b57cec5SDimitry Andric uint64_t p = sc->getRVA() + rel.VirtualAddress + thunksSize; 433*0b57cec5SDimitry Andric 434*0b57cec5SDimitry Andric Defined *sym = dyn_cast_or_null<Defined>(relocTarget); 435*0b57cec5SDimitry Andric if (!sym) 436*0b57cec5SDimitry Andric continue; 437*0b57cec5SDimitry Andric 438*0b57cec5SDimitry Andric uint64_t s = sym->getRVA(); 439*0b57cec5SDimitry Andric 440*0b57cec5SDimitry Andric if (isInRange(rel.Type, s, p, margin)) 441*0b57cec5SDimitry Andric continue; 442*0b57cec5SDimitry Andric 443*0b57cec5SDimitry Andric // If the target isn't in range, hook it up to an existing or new 444*0b57cec5SDimitry Andric // thunk. 445*0b57cec5SDimitry Andric Defined *thunk; 446*0b57cec5SDimitry Andric bool wasNew; 447*0b57cec5SDimitry Andric std::tie(thunk, wasNew) = getThunk(lastThunks, sym, p, rel.Type, margin); 448*0b57cec5SDimitry Andric if (wasNew) { 449*0b57cec5SDimitry Andric Chunk *thunkChunk = thunk->getChunk(); 450*0b57cec5SDimitry Andric thunkChunk->setRVA( 451*0b57cec5SDimitry Andric thunkInsertionRVA); // Estimate of where it will be located. 452*0b57cec5SDimitry Andric os->chunks.insert(os->chunks.begin() + thunkInsertionSpot, thunkChunk); 453*0b57cec5SDimitry Andric thunkInsertionSpot++; 454*0b57cec5SDimitry Andric thunksSize += thunkChunk->getSize(); 455*0b57cec5SDimitry Andric thunkInsertionRVA += thunkChunk->getSize(); 456*0b57cec5SDimitry Andric addressesChanged = true; 457*0b57cec5SDimitry Andric } 458*0b57cec5SDimitry Andric 459*0b57cec5SDimitry Andric // To redirect the relocation, add a symbol to the parent object file's 460*0b57cec5SDimitry Andric // symbol table, and replace the relocation symbol table index with the 461*0b57cec5SDimitry Andric // new index. 462*0b57cec5SDimitry Andric auto insertion = thunkSymtabIndices.insert({{file, thunk}, ~0U}); 463*0b57cec5SDimitry Andric uint32_t &thunkSymbolIndex = insertion.first->second; 464*0b57cec5SDimitry Andric if (insertion.second) 465*0b57cec5SDimitry Andric thunkSymbolIndex = file->addRangeThunkSymbol(thunk); 466*0b57cec5SDimitry Andric relocReplacements.push_back({j, thunkSymbolIndex}); 467*0b57cec5SDimitry Andric } 468*0b57cec5SDimitry Andric 469*0b57cec5SDimitry Andric // Get a writable copy of this section's relocations so they can be 470*0b57cec5SDimitry Andric // modified. If the relocations point into the object file, allocate new 471*0b57cec5SDimitry Andric // memory. Otherwise, this must be previously allocated memory that can be 472*0b57cec5SDimitry Andric // modified in place. 473*0b57cec5SDimitry Andric ArrayRef<coff_relocation> curRelocs = sc->getRelocs(); 474*0b57cec5SDimitry Andric MutableArrayRef<coff_relocation> newRelocs; 475*0b57cec5SDimitry Andric if (originalRelocs.data() == curRelocs.data()) { 476*0b57cec5SDimitry Andric newRelocs = makeMutableArrayRef( 477*0b57cec5SDimitry Andric bAlloc.Allocate<coff_relocation>(originalRelocs.size()), 478*0b57cec5SDimitry Andric originalRelocs.size()); 479*0b57cec5SDimitry Andric } else { 480*0b57cec5SDimitry Andric newRelocs = makeMutableArrayRef( 481*0b57cec5SDimitry Andric const_cast<coff_relocation *>(curRelocs.data()), curRelocs.size()); 482*0b57cec5SDimitry Andric } 483*0b57cec5SDimitry Andric 484*0b57cec5SDimitry Andric // Copy each relocation, but replace the symbol table indices which need 485*0b57cec5SDimitry Andric // thunks. 486*0b57cec5SDimitry Andric auto nextReplacement = relocReplacements.begin(); 487*0b57cec5SDimitry Andric auto endReplacement = relocReplacements.end(); 488*0b57cec5SDimitry Andric for (size_t i = 0, e = originalRelocs.size(); i != e; ++i) { 489*0b57cec5SDimitry Andric newRelocs[i] = originalRelocs[i]; 490*0b57cec5SDimitry Andric if (nextReplacement != endReplacement && nextReplacement->first == i) { 491*0b57cec5SDimitry Andric newRelocs[i].SymbolTableIndex = nextReplacement->second; 492*0b57cec5SDimitry Andric ++nextReplacement; 493*0b57cec5SDimitry Andric } 494*0b57cec5SDimitry Andric } 495*0b57cec5SDimitry Andric 496*0b57cec5SDimitry Andric sc->setRelocs(newRelocs); 497*0b57cec5SDimitry Andric } 498*0b57cec5SDimitry Andric return addressesChanged; 499*0b57cec5SDimitry Andric } 500*0b57cec5SDimitry Andric 501*0b57cec5SDimitry Andric // Verify that all relocations are in range, with no extra margin requirements. 502*0b57cec5SDimitry Andric static bool verifyRanges(const std::vector<Chunk *> chunks) { 503*0b57cec5SDimitry Andric for (Chunk *c : chunks) { 504*0b57cec5SDimitry Andric SectionChunk *sc = dyn_cast_or_null<SectionChunk>(c); 505*0b57cec5SDimitry Andric if (!sc) 506*0b57cec5SDimitry Andric continue; 507*0b57cec5SDimitry Andric 508*0b57cec5SDimitry Andric ArrayRef<coff_relocation> relocs = sc->getRelocs(); 509*0b57cec5SDimitry Andric for (size_t j = 0, e = relocs.size(); j < e; ++j) { 510*0b57cec5SDimitry Andric const coff_relocation &rel = relocs[j]; 511*0b57cec5SDimitry Andric Symbol *relocTarget = sc->file->getSymbol(rel.SymbolTableIndex); 512*0b57cec5SDimitry Andric 513*0b57cec5SDimitry Andric Defined *sym = dyn_cast_or_null<Defined>(relocTarget); 514*0b57cec5SDimitry Andric if (!sym) 515*0b57cec5SDimitry Andric continue; 516*0b57cec5SDimitry Andric 517*0b57cec5SDimitry Andric uint64_t p = sc->getRVA() + rel.VirtualAddress; 518*0b57cec5SDimitry Andric uint64_t s = sym->getRVA(); 519*0b57cec5SDimitry Andric 520*0b57cec5SDimitry Andric if (!isInRange(rel.Type, s, p, 0)) 521*0b57cec5SDimitry Andric return false; 522*0b57cec5SDimitry Andric } 523*0b57cec5SDimitry Andric } 524*0b57cec5SDimitry Andric return true; 525*0b57cec5SDimitry Andric } 526*0b57cec5SDimitry Andric 527*0b57cec5SDimitry Andric // Assign addresses and add thunks if necessary. 528*0b57cec5SDimitry Andric void Writer::finalizeAddresses() { 529*0b57cec5SDimitry Andric assignAddresses(); 530*0b57cec5SDimitry Andric if (config->machine != ARMNT && config->machine != ARM64) 531*0b57cec5SDimitry Andric return; 532*0b57cec5SDimitry Andric 533*0b57cec5SDimitry Andric size_t origNumChunks = 0; 534*0b57cec5SDimitry Andric for (OutputSection *sec : outputSections) { 535*0b57cec5SDimitry Andric sec->origChunks = sec->chunks; 536*0b57cec5SDimitry Andric origNumChunks += sec->chunks.size(); 537*0b57cec5SDimitry Andric } 538*0b57cec5SDimitry Andric 539*0b57cec5SDimitry Andric int pass = 0; 540*0b57cec5SDimitry Andric int margin = 1024 * 100; 541*0b57cec5SDimitry Andric while (true) { 542*0b57cec5SDimitry Andric // First check whether we need thunks at all, or if the previous pass of 543*0b57cec5SDimitry Andric // adding them turned out ok. 544*0b57cec5SDimitry Andric bool rangesOk = true; 545*0b57cec5SDimitry Andric size_t numChunks = 0; 546*0b57cec5SDimitry Andric for (OutputSection *sec : outputSections) { 547*0b57cec5SDimitry Andric if (!verifyRanges(sec->chunks)) { 548*0b57cec5SDimitry Andric rangesOk = false; 549*0b57cec5SDimitry Andric break; 550*0b57cec5SDimitry Andric } 551*0b57cec5SDimitry Andric numChunks += sec->chunks.size(); 552*0b57cec5SDimitry Andric } 553*0b57cec5SDimitry Andric if (rangesOk) { 554*0b57cec5SDimitry Andric if (pass > 0) 555*0b57cec5SDimitry Andric log("Added " + Twine(numChunks - origNumChunks) + " thunks with " + 556*0b57cec5SDimitry Andric "margin " + Twine(margin) + " in " + Twine(pass) + " passes"); 557*0b57cec5SDimitry Andric return; 558*0b57cec5SDimitry Andric } 559*0b57cec5SDimitry Andric 560*0b57cec5SDimitry Andric if (pass >= 10) 561*0b57cec5SDimitry Andric fatal("adding thunks hasn't converged after " + Twine(pass) + " passes"); 562*0b57cec5SDimitry Andric 563*0b57cec5SDimitry Andric if (pass > 0) { 564*0b57cec5SDimitry Andric // If the previous pass didn't work out, reset everything back to the 565*0b57cec5SDimitry Andric // original conditions before retrying with a wider margin. This should 566*0b57cec5SDimitry Andric // ideally never happen under real circumstances. 567*0b57cec5SDimitry Andric for (OutputSection *sec : outputSections) 568*0b57cec5SDimitry Andric sec->chunks = sec->origChunks; 569*0b57cec5SDimitry Andric margin *= 2; 570*0b57cec5SDimitry Andric } 571*0b57cec5SDimitry Andric 572*0b57cec5SDimitry Andric // Try adding thunks everywhere where it is needed, with a margin 573*0b57cec5SDimitry Andric // to avoid things going out of range due to the added thunks. 574*0b57cec5SDimitry Andric bool addressesChanged = false; 575*0b57cec5SDimitry Andric for (OutputSection *sec : outputSections) 576*0b57cec5SDimitry Andric addressesChanged |= createThunks(sec, margin); 577*0b57cec5SDimitry Andric // If the verification above thought we needed thunks, we should have 578*0b57cec5SDimitry Andric // added some. 579*0b57cec5SDimitry Andric assert(addressesChanged); 580*0b57cec5SDimitry Andric 581*0b57cec5SDimitry Andric // Recalculate the layout for the whole image (and verify the ranges at 582*0b57cec5SDimitry Andric // the start of the next round). 583*0b57cec5SDimitry Andric assignAddresses(); 584*0b57cec5SDimitry Andric 585*0b57cec5SDimitry Andric pass++; 586*0b57cec5SDimitry Andric } 587*0b57cec5SDimitry Andric } 588*0b57cec5SDimitry Andric 589*0b57cec5SDimitry Andric // The main function of the writer. 590*0b57cec5SDimitry Andric void Writer::run() { 591*0b57cec5SDimitry Andric ScopedTimer t1(codeLayoutTimer); 592*0b57cec5SDimitry Andric 593*0b57cec5SDimitry Andric createImportTables(); 594*0b57cec5SDimitry Andric createSections(); 595*0b57cec5SDimitry Andric createMiscChunks(); 596*0b57cec5SDimitry Andric appendImportThunks(); 597*0b57cec5SDimitry Andric createExportTable(); 598*0b57cec5SDimitry Andric mergeSections(); 599*0b57cec5SDimitry Andric removeUnusedSections(); 600*0b57cec5SDimitry Andric finalizeAddresses(); 601*0b57cec5SDimitry Andric removeEmptySections(); 602*0b57cec5SDimitry Andric assignOutputSectionIndices(); 603*0b57cec5SDimitry Andric setSectionPermissions(); 604*0b57cec5SDimitry Andric createSymbolAndStringTable(); 605*0b57cec5SDimitry Andric 606*0b57cec5SDimitry Andric if (fileSize > UINT32_MAX) 607*0b57cec5SDimitry Andric fatal("image size (" + Twine(fileSize) + ") " + 608*0b57cec5SDimitry Andric "exceeds maximum allowable size (" + Twine(UINT32_MAX) + ")"); 609*0b57cec5SDimitry Andric 610*0b57cec5SDimitry Andric openFile(config->outputFile); 611*0b57cec5SDimitry Andric if (config->is64()) { 612*0b57cec5SDimitry Andric writeHeader<pe32plus_header>(); 613*0b57cec5SDimitry Andric } else { 614*0b57cec5SDimitry Andric writeHeader<pe32_header>(); 615*0b57cec5SDimitry Andric } 616*0b57cec5SDimitry Andric writeSections(); 617*0b57cec5SDimitry Andric sortExceptionTable(); 618*0b57cec5SDimitry Andric 619*0b57cec5SDimitry Andric t1.stop(); 620*0b57cec5SDimitry Andric 621*0b57cec5SDimitry Andric if (!config->pdbPath.empty() && config->debug) { 622*0b57cec5SDimitry Andric assert(buildId); 623*0b57cec5SDimitry Andric createPDB(symtab, outputSections, sectionTable, buildId->buildId); 624*0b57cec5SDimitry Andric } 625*0b57cec5SDimitry Andric writeBuildId(); 626*0b57cec5SDimitry Andric 627*0b57cec5SDimitry Andric writeMapFile(outputSections); 628*0b57cec5SDimitry Andric 629*0b57cec5SDimitry Andric if (errorCount()) 630*0b57cec5SDimitry Andric return; 631*0b57cec5SDimitry Andric 632*0b57cec5SDimitry Andric ScopedTimer t2(diskCommitTimer); 633*0b57cec5SDimitry Andric if (auto e = buffer->commit()) 634*0b57cec5SDimitry Andric fatal("failed to write the output file: " + toString(std::move(e))); 635*0b57cec5SDimitry Andric } 636*0b57cec5SDimitry Andric 637*0b57cec5SDimitry Andric static StringRef getOutputSectionName(StringRef name) { 638*0b57cec5SDimitry Andric StringRef s = name.split('$').first; 639*0b57cec5SDimitry Andric 640*0b57cec5SDimitry Andric // Treat a later period as a separator for MinGW, for sections like 641*0b57cec5SDimitry Andric // ".ctors.01234". 642*0b57cec5SDimitry Andric return s.substr(0, s.find('.', 1)); 643*0b57cec5SDimitry Andric } 644*0b57cec5SDimitry Andric 645*0b57cec5SDimitry Andric // For /order. 646*0b57cec5SDimitry Andric static void sortBySectionOrder(std::vector<Chunk *> &chunks) { 647*0b57cec5SDimitry Andric auto getPriority = [](const Chunk *c) { 648*0b57cec5SDimitry Andric if (auto *sec = dyn_cast<SectionChunk>(c)) 649*0b57cec5SDimitry Andric if (sec->sym) 650*0b57cec5SDimitry Andric return config->order.lookup(sec->sym->getName()); 651*0b57cec5SDimitry Andric return 0; 652*0b57cec5SDimitry Andric }; 653*0b57cec5SDimitry Andric 654*0b57cec5SDimitry Andric llvm::stable_sort(chunks, [=](const Chunk *a, const Chunk *b) { 655*0b57cec5SDimitry Andric return getPriority(a) < getPriority(b); 656*0b57cec5SDimitry Andric }); 657*0b57cec5SDimitry Andric } 658*0b57cec5SDimitry Andric 659*0b57cec5SDimitry Andric // Change the characteristics of existing PartialSections that belong to the 660*0b57cec5SDimitry Andric // section Name to Chars. 661*0b57cec5SDimitry Andric void Writer::fixPartialSectionChars(StringRef name, uint32_t chars) { 662*0b57cec5SDimitry Andric for (auto it : partialSections) { 663*0b57cec5SDimitry Andric PartialSection *pSec = it.second; 664*0b57cec5SDimitry Andric StringRef curName = pSec->name; 665*0b57cec5SDimitry Andric if (!curName.consume_front(name) || 666*0b57cec5SDimitry Andric (!curName.empty() && !curName.startswith("$"))) 667*0b57cec5SDimitry Andric continue; 668*0b57cec5SDimitry Andric if (pSec->characteristics == chars) 669*0b57cec5SDimitry Andric continue; 670*0b57cec5SDimitry Andric PartialSection *destSec = createPartialSection(pSec->name, chars); 671*0b57cec5SDimitry Andric destSec->chunks.insert(destSec->chunks.end(), pSec->chunks.begin(), 672*0b57cec5SDimitry Andric pSec->chunks.end()); 673*0b57cec5SDimitry Andric pSec->chunks.clear(); 674*0b57cec5SDimitry Andric } 675*0b57cec5SDimitry Andric } 676*0b57cec5SDimitry Andric 677*0b57cec5SDimitry Andric // Sort concrete section chunks from GNU import libraries. 678*0b57cec5SDimitry Andric // 679*0b57cec5SDimitry Andric // GNU binutils doesn't use short import files, but instead produces import 680*0b57cec5SDimitry Andric // libraries that consist of object files, with section chunks for the .idata$* 681*0b57cec5SDimitry Andric // sections. These are linked just as regular static libraries. Each import 682*0b57cec5SDimitry Andric // library consists of one header object, one object file for every imported 683*0b57cec5SDimitry Andric // symbol, and one trailer object. In order for the .idata tables/lists to 684*0b57cec5SDimitry Andric // be formed correctly, the section chunks within each .idata$* section need 685*0b57cec5SDimitry Andric // to be grouped by library, and sorted alphabetically within each library 686*0b57cec5SDimitry Andric // (which makes sure the header comes first and the trailer last). 687*0b57cec5SDimitry Andric bool Writer::fixGnuImportChunks() { 688*0b57cec5SDimitry Andric uint32_t rdata = IMAGE_SCN_CNT_INITIALIZED_DATA | IMAGE_SCN_MEM_READ; 689*0b57cec5SDimitry Andric 690*0b57cec5SDimitry Andric // Make sure all .idata$* section chunks are mapped as RDATA in order to 691*0b57cec5SDimitry Andric // be sorted into the same sections as our own synthesized .idata chunks. 692*0b57cec5SDimitry Andric fixPartialSectionChars(".idata", rdata); 693*0b57cec5SDimitry Andric 694*0b57cec5SDimitry Andric bool hasIdata = false; 695*0b57cec5SDimitry Andric // Sort all .idata$* chunks, grouping chunks from the same library, 696*0b57cec5SDimitry Andric // with alphabetical ordering of the object fils within a library. 697*0b57cec5SDimitry Andric for (auto it : partialSections) { 698*0b57cec5SDimitry Andric PartialSection *pSec = it.second; 699*0b57cec5SDimitry Andric if (!pSec->name.startswith(".idata")) 700*0b57cec5SDimitry Andric continue; 701*0b57cec5SDimitry Andric 702*0b57cec5SDimitry Andric if (!pSec->chunks.empty()) 703*0b57cec5SDimitry Andric hasIdata = true; 704*0b57cec5SDimitry Andric llvm::stable_sort(pSec->chunks, [&](Chunk *s, Chunk *t) { 705*0b57cec5SDimitry Andric SectionChunk *sc1 = dyn_cast_or_null<SectionChunk>(s); 706*0b57cec5SDimitry Andric SectionChunk *sc2 = dyn_cast_or_null<SectionChunk>(t); 707*0b57cec5SDimitry Andric if (!sc1 || !sc2) { 708*0b57cec5SDimitry Andric // if SC1, order them ascending. If SC2 or both null, 709*0b57cec5SDimitry Andric // S is not less than T. 710*0b57cec5SDimitry Andric return sc1 != nullptr; 711*0b57cec5SDimitry Andric } 712*0b57cec5SDimitry Andric // Make a string with "libraryname/objectfile" for sorting, achieving 713*0b57cec5SDimitry Andric // both grouping by library and sorting of objects within a library, 714*0b57cec5SDimitry Andric // at once. 715*0b57cec5SDimitry Andric std::string key1 = 716*0b57cec5SDimitry Andric (sc1->file->parentName + "/" + sc1->file->getName()).str(); 717*0b57cec5SDimitry Andric std::string key2 = 718*0b57cec5SDimitry Andric (sc2->file->parentName + "/" + sc2->file->getName()).str(); 719*0b57cec5SDimitry Andric return key1 < key2; 720*0b57cec5SDimitry Andric }); 721*0b57cec5SDimitry Andric } 722*0b57cec5SDimitry Andric return hasIdata; 723*0b57cec5SDimitry Andric } 724*0b57cec5SDimitry Andric 725*0b57cec5SDimitry Andric // Add generated idata chunks, for imported symbols and DLLs, and a 726*0b57cec5SDimitry Andric // terminator in .idata$2. 727*0b57cec5SDimitry Andric void Writer::addSyntheticIdata() { 728*0b57cec5SDimitry Andric uint32_t rdata = IMAGE_SCN_CNT_INITIALIZED_DATA | IMAGE_SCN_MEM_READ; 729*0b57cec5SDimitry Andric idata.create(); 730*0b57cec5SDimitry Andric 731*0b57cec5SDimitry Andric // Add the .idata content in the right section groups, to allow 732*0b57cec5SDimitry Andric // chunks from other linked in object files to be grouped together. 733*0b57cec5SDimitry Andric // See Microsoft PE/COFF spec 5.4 for details. 734*0b57cec5SDimitry Andric auto add = [&](StringRef n, std::vector<Chunk *> &v) { 735*0b57cec5SDimitry Andric PartialSection *pSec = createPartialSection(n, rdata); 736*0b57cec5SDimitry Andric pSec->chunks.insert(pSec->chunks.end(), v.begin(), v.end()); 737*0b57cec5SDimitry Andric }; 738*0b57cec5SDimitry Andric 739*0b57cec5SDimitry Andric // The loader assumes a specific order of data. 740*0b57cec5SDimitry Andric // Add each type in the correct order. 741*0b57cec5SDimitry Andric add(".idata$2", idata.dirs); 742*0b57cec5SDimitry Andric add(".idata$4", idata.lookups); 743*0b57cec5SDimitry Andric add(".idata$5", idata.addresses); 744*0b57cec5SDimitry Andric add(".idata$6", idata.hints); 745*0b57cec5SDimitry Andric add(".idata$7", idata.dllNames); 746*0b57cec5SDimitry Andric } 747*0b57cec5SDimitry Andric 748*0b57cec5SDimitry Andric // Locate the first Chunk and size of the import directory list and the 749*0b57cec5SDimitry Andric // IAT. 750*0b57cec5SDimitry Andric void Writer::locateImportTables() { 751*0b57cec5SDimitry Andric uint32_t rdata = IMAGE_SCN_CNT_INITIALIZED_DATA | IMAGE_SCN_MEM_READ; 752*0b57cec5SDimitry Andric 753*0b57cec5SDimitry Andric if (PartialSection *importDirs = findPartialSection(".idata$2", rdata)) { 754*0b57cec5SDimitry Andric if (!importDirs->chunks.empty()) 755*0b57cec5SDimitry Andric importTableStart = importDirs->chunks.front(); 756*0b57cec5SDimitry Andric for (Chunk *c : importDirs->chunks) 757*0b57cec5SDimitry Andric importTableSize += c->getSize(); 758*0b57cec5SDimitry Andric } 759*0b57cec5SDimitry Andric 760*0b57cec5SDimitry Andric if (PartialSection *importAddresses = findPartialSection(".idata$5", rdata)) { 761*0b57cec5SDimitry Andric if (!importAddresses->chunks.empty()) 762*0b57cec5SDimitry Andric iatStart = importAddresses->chunks.front(); 763*0b57cec5SDimitry Andric for (Chunk *c : importAddresses->chunks) 764*0b57cec5SDimitry Andric iatSize += c->getSize(); 765*0b57cec5SDimitry Andric } 766*0b57cec5SDimitry Andric } 767*0b57cec5SDimitry Andric 768*0b57cec5SDimitry Andric // Return whether a SectionChunk's suffix (the dollar and any trailing 769*0b57cec5SDimitry Andric // suffix) should be removed and sorted into the main suffixless 770*0b57cec5SDimitry Andric // PartialSection. 771*0b57cec5SDimitry Andric static bool shouldStripSectionSuffix(SectionChunk *sc, StringRef name) { 772*0b57cec5SDimitry Andric // On MinGW, comdat groups are formed by putting the comdat group name 773*0b57cec5SDimitry Andric // after the '$' in the section name. For .eh_frame$<symbol>, that must 774*0b57cec5SDimitry Andric // still be sorted before the .eh_frame trailer from crtend.o, thus just 775*0b57cec5SDimitry Andric // strip the section name trailer. For other sections, such as 776*0b57cec5SDimitry Andric // .tls$$<symbol> (where non-comdat .tls symbols are otherwise stored in 777*0b57cec5SDimitry Andric // ".tls$"), they must be strictly sorted after .tls. And for the 778*0b57cec5SDimitry Andric // hypothetical case of comdat .CRT$XCU, we definitely need to keep the 779*0b57cec5SDimitry Andric // suffix for sorting. Thus, to play it safe, only strip the suffix for 780*0b57cec5SDimitry Andric // the standard sections. 781*0b57cec5SDimitry Andric if (!config->mingw) 782*0b57cec5SDimitry Andric return false; 783*0b57cec5SDimitry Andric if (!sc || !sc->isCOMDAT()) 784*0b57cec5SDimitry Andric return false; 785*0b57cec5SDimitry Andric return name.startswith(".text$") || name.startswith(".data$") || 786*0b57cec5SDimitry Andric name.startswith(".rdata$") || name.startswith(".pdata$") || 787*0b57cec5SDimitry Andric name.startswith(".xdata$") || name.startswith(".eh_frame$"); 788*0b57cec5SDimitry Andric } 789*0b57cec5SDimitry Andric 790*0b57cec5SDimitry Andric // Create output section objects and add them to OutputSections. 791*0b57cec5SDimitry Andric void Writer::createSections() { 792*0b57cec5SDimitry Andric // First, create the builtin sections. 793*0b57cec5SDimitry Andric const uint32_t data = IMAGE_SCN_CNT_INITIALIZED_DATA; 794*0b57cec5SDimitry Andric const uint32_t bss = IMAGE_SCN_CNT_UNINITIALIZED_DATA; 795*0b57cec5SDimitry Andric const uint32_t code = IMAGE_SCN_CNT_CODE; 796*0b57cec5SDimitry Andric const uint32_t discardable = IMAGE_SCN_MEM_DISCARDABLE; 797*0b57cec5SDimitry Andric const uint32_t r = IMAGE_SCN_MEM_READ; 798*0b57cec5SDimitry Andric const uint32_t w = IMAGE_SCN_MEM_WRITE; 799*0b57cec5SDimitry Andric const uint32_t x = IMAGE_SCN_MEM_EXECUTE; 800*0b57cec5SDimitry Andric 801*0b57cec5SDimitry Andric SmallDenseMap<std::pair<StringRef, uint32_t>, OutputSection *> sections; 802*0b57cec5SDimitry Andric auto createSection = [&](StringRef name, uint32_t outChars) { 803*0b57cec5SDimitry Andric OutputSection *&sec = sections[{name, outChars}]; 804*0b57cec5SDimitry Andric if (!sec) { 805*0b57cec5SDimitry Andric sec = make<OutputSection>(name, outChars); 806*0b57cec5SDimitry Andric outputSections.push_back(sec); 807*0b57cec5SDimitry Andric } 808*0b57cec5SDimitry Andric return sec; 809*0b57cec5SDimitry Andric }; 810*0b57cec5SDimitry Andric 811*0b57cec5SDimitry Andric // Try to match the section order used by link.exe. 812*0b57cec5SDimitry Andric textSec = createSection(".text", code | r | x); 813*0b57cec5SDimitry Andric createSection(".bss", bss | r | w); 814*0b57cec5SDimitry Andric rdataSec = createSection(".rdata", data | r); 815*0b57cec5SDimitry Andric buildidSec = createSection(".buildid", data | r); 816*0b57cec5SDimitry Andric dataSec = createSection(".data", data | r | w); 817*0b57cec5SDimitry Andric pdataSec = createSection(".pdata", data | r); 818*0b57cec5SDimitry Andric idataSec = createSection(".idata", data | r); 819*0b57cec5SDimitry Andric edataSec = createSection(".edata", data | r); 820*0b57cec5SDimitry Andric didatSec = createSection(".didat", data | r); 821*0b57cec5SDimitry Andric rsrcSec = createSection(".rsrc", data | r); 822*0b57cec5SDimitry Andric relocSec = createSection(".reloc", data | discardable | r); 823*0b57cec5SDimitry Andric ctorsSec = createSection(".ctors", data | r | w); 824*0b57cec5SDimitry Andric dtorsSec = createSection(".dtors", data | r | w); 825*0b57cec5SDimitry Andric 826*0b57cec5SDimitry Andric // Then bin chunks by name and output characteristics. 827*0b57cec5SDimitry Andric for (Chunk *c : symtab->getChunks()) { 828*0b57cec5SDimitry Andric auto *sc = dyn_cast<SectionChunk>(c); 829*0b57cec5SDimitry Andric if (sc && !sc->live) { 830*0b57cec5SDimitry Andric if (config->verbose) 831*0b57cec5SDimitry Andric sc->printDiscardedMessage(); 832*0b57cec5SDimitry Andric continue; 833*0b57cec5SDimitry Andric } 834*0b57cec5SDimitry Andric StringRef name = c->getSectionName(); 835*0b57cec5SDimitry Andric if (shouldStripSectionSuffix(sc, name)) 836*0b57cec5SDimitry Andric name = name.split('$').first; 837*0b57cec5SDimitry Andric PartialSection *pSec = createPartialSection(name, 838*0b57cec5SDimitry Andric c->getOutputCharacteristics()); 839*0b57cec5SDimitry Andric pSec->chunks.push_back(c); 840*0b57cec5SDimitry Andric } 841*0b57cec5SDimitry Andric 842*0b57cec5SDimitry Andric fixPartialSectionChars(".rsrc", data | r); 843*0b57cec5SDimitry Andric // Even in non MinGW cases, we might need to link against GNU import 844*0b57cec5SDimitry Andric // libraries. 845*0b57cec5SDimitry Andric bool hasIdata = fixGnuImportChunks(); 846*0b57cec5SDimitry Andric if (!idata.empty()) 847*0b57cec5SDimitry Andric hasIdata = true; 848*0b57cec5SDimitry Andric 849*0b57cec5SDimitry Andric if (hasIdata) 850*0b57cec5SDimitry Andric addSyntheticIdata(); 851*0b57cec5SDimitry Andric 852*0b57cec5SDimitry Andric // Process an /order option. 853*0b57cec5SDimitry Andric if (!config->order.empty()) 854*0b57cec5SDimitry Andric for (auto it : partialSections) 855*0b57cec5SDimitry Andric sortBySectionOrder(it.second->chunks); 856*0b57cec5SDimitry Andric 857*0b57cec5SDimitry Andric if (hasIdata) 858*0b57cec5SDimitry Andric locateImportTables(); 859*0b57cec5SDimitry Andric 860*0b57cec5SDimitry Andric // Then create an OutputSection for each section. 861*0b57cec5SDimitry Andric // '$' and all following characters in input section names are 862*0b57cec5SDimitry Andric // discarded when determining output section. So, .text$foo 863*0b57cec5SDimitry Andric // contributes to .text, for example. See PE/COFF spec 3.2. 864*0b57cec5SDimitry Andric for (auto it : partialSections) { 865*0b57cec5SDimitry Andric PartialSection *pSec = it.second; 866*0b57cec5SDimitry Andric StringRef name = getOutputSectionName(pSec->name); 867*0b57cec5SDimitry Andric uint32_t outChars = pSec->characteristics; 868*0b57cec5SDimitry Andric 869*0b57cec5SDimitry Andric if (name == ".CRT") { 870*0b57cec5SDimitry Andric // In link.exe, there is a special case for the I386 target where .CRT 871*0b57cec5SDimitry Andric // sections are treated as if they have output characteristics DATA | R if 872*0b57cec5SDimitry Andric // their characteristics are DATA | R | W. This implements the same 873*0b57cec5SDimitry Andric // special case for all architectures. 874*0b57cec5SDimitry Andric outChars = data | r; 875*0b57cec5SDimitry Andric 876*0b57cec5SDimitry Andric log("Processing section " + pSec->name + " -> " + name); 877*0b57cec5SDimitry Andric 878*0b57cec5SDimitry Andric sortCRTSectionChunks(pSec->chunks); 879*0b57cec5SDimitry Andric } 880*0b57cec5SDimitry Andric 881*0b57cec5SDimitry Andric OutputSection *sec = createSection(name, outChars); 882*0b57cec5SDimitry Andric for (Chunk *c : pSec->chunks) 883*0b57cec5SDimitry Andric sec->addChunk(c); 884*0b57cec5SDimitry Andric 885*0b57cec5SDimitry Andric sec->addContributingPartialSection(pSec); 886*0b57cec5SDimitry Andric } 887*0b57cec5SDimitry Andric 888*0b57cec5SDimitry Andric // Finally, move some output sections to the end. 889*0b57cec5SDimitry Andric auto sectionOrder = [&](const OutputSection *s) { 890*0b57cec5SDimitry Andric // Move DISCARDABLE (or non-memory-mapped) sections to the end of file 891*0b57cec5SDimitry Andric // because the loader cannot handle holes. Stripping can remove other 892*0b57cec5SDimitry Andric // discardable ones than .reloc, which is first of them (created early). 893*0b57cec5SDimitry Andric if (s->header.Characteristics & IMAGE_SCN_MEM_DISCARDABLE) 894*0b57cec5SDimitry Andric return 2; 895*0b57cec5SDimitry Andric // .rsrc should come at the end of the non-discardable sections because its 896*0b57cec5SDimitry Andric // size may change by the Win32 UpdateResources() function, causing 897*0b57cec5SDimitry Andric // subsequent sections to move (see https://crbug.com/827082). 898*0b57cec5SDimitry Andric if (s == rsrcSec) 899*0b57cec5SDimitry Andric return 1; 900*0b57cec5SDimitry Andric return 0; 901*0b57cec5SDimitry Andric }; 902*0b57cec5SDimitry Andric llvm::stable_sort(outputSections, 903*0b57cec5SDimitry Andric [&](const OutputSection *s, const OutputSection *t) { 904*0b57cec5SDimitry Andric return sectionOrder(s) < sectionOrder(t); 905*0b57cec5SDimitry Andric }); 906*0b57cec5SDimitry Andric } 907*0b57cec5SDimitry Andric 908*0b57cec5SDimitry Andric void Writer::createMiscChunks() { 909*0b57cec5SDimitry Andric for (MergeChunk *p : MergeChunk::instances) { 910*0b57cec5SDimitry Andric if (p) { 911*0b57cec5SDimitry Andric p->finalizeContents(); 912*0b57cec5SDimitry Andric rdataSec->addChunk(p); 913*0b57cec5SDimitry Andric } 914*0b57cec5SDimitry Andric } 915*0b57cec5SDimitry Andric 916*0b57cec5SDimitry Andric // Create thunks for locally-dllimported symbols. 917*0b57cec5SDimitry Andric if (!symtab->localImportChunks.empty()) { 918*0b57cec5SDimitry Andric for (Chunk *c : symtab->localImportChunks) 919*0b57cec5SDimitry Andric rdataSec->addChunk(c); 920*0b57cec5SDimitry Andric } 921*0b57cec5SDimitry Andric 922*0b57cec5SDimitry Andric // Create Debug Information Chunks 923*0b57cec5SDimitry Andric OutputSection *debugInfoSec = config->mingw ? buildidSec : rdataSec; 924*0b57cec5SDimitry Andric if (config->debug || config->repro) { 925*0b57cec5SDimitry Andric debugDirectory = make<DebugDirectoryChunk>(debugRecords, config->repro); 926*0b57cec5SDimitry Andric debugInfoSec->addChunk(debugDirectory); 927*0b57cec5SDimitry Andric } 928*0b57cec5SDimitry Andric 929*0b57cec5SDimitry Andric if (config->debug) { 930*0b57cec5SDimitry Andric // Make a CVDebugRecordChunk even when /DEBUG:CV is not specified. We 931*0b57cec5SDimitry Andric // output a PDB no matter what, and this chunk provides the only means of 932*0b57cec5SDimitry Andric // allowing a debugger to match a PDB and an executable. So we need it even 933*0b57cec5SDimitry Andric // if we're ultimately not going to write CodeView data to the PDB. 934*0b57cec5SDimitry Andric buildId = make<CVDebugRecordChunk>(); 935*0b57cec5SDimitry Andric debugRecords.push_back(buildId); 936*0b57cec5SDimitry Andric 937*0b57cec5SDimitry Andric for (Chunk *c : debugRecords) 938*0b57cec5SDimitry Andric debugInfoSec->addChunk(c); 939*0b57cec5SDimitry Andric } 940*0b57cec5SDimitry Andric 941*0b57cec5SDimitry Andric // Create SEH table. x86-only. 942*0b57cec5SDimitry Andric if (config->safeSEH) 943*0b57cec5SDimitry Andric createSEHTable(); 944*0b57cec5SDimitry Andric 945*0b57cec5SDimitry Andric // Create /guard:cf tables if requested. 946*0b57cec5SDimitry Andric if (config->guardCF != GuardCFLevel::Off) 947*0b57cec5SDimitry Andric createGuardCFTables(); 948*0b57cec5SDimitry Andric 949*0b57cec5SDimitry Andric if (config->mingw) { 950*0b57cec5SDimitry Andric createRuntimePseudoRelocs(); 951*0b57cec5SDimitry Andric 952*0b57cec5SDimitry Andric insertCtorDtorSymbols(); 953*0b57cec5SDimitry Andric } 954*0b57cec5SDimitry Andric } 955*0b57cec5SDimitry Andric 956*0b57cec5SDimitry Andric // Create .idata section for the DLL-imported symbol table. 957*0b57cec5SDimitry Andric // The format of this section is inherently Windows-specific. 958*0b57cec5SDimitry Andric // IdataContents class abstracted away the details for us, 959*0b57cec5SDimitry Andric // so we just let it create chunks and add them to the section. 960*0b57cec5SDimitry Andric void Writer::createImportTables() { 961*0b57cec5SDimitry Andric // Initialize DLLOrder so that import entries are ordered in 962*0b57cec5SDimitry Andric // the same order as in the command line. (That affects DLL 963*0b57cec5SDimitry Andric // initialization order, and this ordering is MSVC-compatible.) 964*0b57cec5SDimitry Andric for (ImportFile *file : ImportFile::instances) { 965*0b57cec5SDimitry Andric if (!file->live) 966*0b57cec5SDimitry Andric continue; 967*0b57cec5SDimitry Andric 968*0b57cec5SDimitry Andric std::string dll = StringRef(file->dllName).lower(); 969*0b57cec5SDimitry Andric if (config->dllOrder.count(dll) == 0) 970*0b57cec5SDimitry Andric config->dllOrder[dll] = config->dllOrder.size(); 971*0b57cec5SDimitry Andric 972*0b57cec5SDimitry Andric if (file->impSym && !isa<DefinedImportData>(file->impSym)) 973*0b57cec5SDimitry Andric fatal(toString(*file->impSym) + " was replaced"); 974*0b57cec5SDimitry Andric DefinedImportData *impSym = cast_or_null<DefinedImportData>(file->impSym); 975*0b57cec5SDimitry Andric if (config->delayLoads.count(StringRef(file->dllName).lower())) { 976*0b57cec5SDimitry Andric if (!file->thunkSym) 977*0b57cec5SDimitry Andric fatal("cannot delay-load " + toString(file) + 978*0b57cec5SDimitry Andric " due to import of data: " + toString(*impSym)); 979*0b57cec5SDimitry Andric delayIdata.add(impSym); 980*0b57cec5SDimitry Andric } else { 981*0b57cec5SDimitry Andric idata.add(impSym); 982*0b57cec5SDimitry Andric } 983*0b57cec5SDimitry Andric } 984*0b57cec5SDimitry Andric } 985*0b57cec5SDimitry Andric 986*0b57cec5SDimitry Andric void Writer::appendImportThunks() { 987*0b57cec5SDimitry Andric if (ImportFile::instances.empty()) 988*0b57cec5SDimitry Andric return; 989*0b57cec5SDimitry Andric 990*0b57cec5SDimitry Andric for (ImportFile *file : ImportFile::instances) { 991*0b57cec5SDimitry Andric if (!file->live) 992*0b57cec5SDimitry Andric continue; 993*0b57cec5SDimitry Andric 994*0b57cec5SDimitry Andric if (!file->thunkSym) 995*0b57cec5SDimitry Andric continue; 996*0b57cec5SDimitry Andric 997*0b57cec5SDimitry Andric if (!isa<DefinedImportThunk>(file->thunkSym)) 998*0b57cec5SDimitry Andric fatal(toString(*file->thunkSym) + " was replaced"); 999*0b57cec5SDimitry Andric DefinedImportThunk *thunk = cast<DefinedImportThunk>(file->thunkSym); 1000*0b57cec5SDimitry Andric if (file->thunkLive) 1001*0b57cec5SDimitry Andric textSec->addChunk(thunk->getChunk()); 1002*0b57cec5SDimitry Andric } 1003*0b57cec5SDimitry Andric 1004*0b57cec5SDimitry Andric if (!delayIdata.empty()) { 1005*0b57cec5SDimitry Andric Defined *helper = cast<Defined>(config->delayLoadHelper); 1006*0b57cec5SDimitry Andric delayIdata.create(helper); 1007*0b57cec5SDimitry Andric for (Chunk *c : delayIdata.getChunks()) 1008*0b57cec5SDimitry Andric didatSec->addChunk(c); 1009*0b57cec5SDimitry Andric for (Chunk *c : delayIdata.getDataChunks()) 1010*0b57cec5SDimitry Andric dataSec->addChunk(c); 1011*0b57cec5SDimitry Andric for (Chunk *c : delayIdata.getCodeChunks()) 1012*0b57cec5SDimitry Andric textSec->addChunk(c); 1013*0b57cec5SDimitry Andric } 1014*0b57cec5SDimitry Andric } 1015*0b57cec5SDimitry Andric 1016*0b57cec5SDimitry Andric void Writer::createExportTable() { 1017*0b57cec5SDimitry Andric if (config->exports.empty()) 1018*0b57cec5SDimitry Andric return; 1019*0b57cec5SDimitry Andric for (Chunk *c : edata.chunks) 1020*0b57cec5SDimitry Andric edataSec->addChunk(c); 1021*0b57cec5SDimitry Andric } 1022*0b57cec5SDimitry Andric 1023*0b57cec5SDimitry Andric void Writer::removeUnusedSections() { 1024*0b57cec5SDimitry Andric // Remove sections that we can be sure won't get content, to avoid 1025*0b57cec5SDimitry Andric // allocating space for their section headers. 1026*0b57cec5SDimitry Andric auto isUnused = [this](OutputSection *s) { 1027*0b57cec5SDimitry Andric if (s == relocSec) 1028*0b57cec5SDimitry Andric return false; // This section is populated later. 1029*0b57cec5SDimitry Andric // MergeChunks have zero size at this point, as their size is finalized 1030*0b57cec5SDimitry Andric // later. Only remove sections that have no Chunks at all. 1031*0b57cec5SDimitry Andric return s->chunks.empty(); 1032*0b57cec5SDimitry Andric }; 1033*0b57cec5SDimitry Andric outputSections.erase( 1034*0b57cec5SDimitry Andric std::remove_if(outputSections.begin(), outputSections.end(), isUnused), 1035*0b57cec5SDimitry Andric outputSections.end()); 1036*0b57cec5SDimitry Andric } 1037*0b57cec5SDimitry Andric 1038*0b57cec5SDimitry Andric // The Windows loader doesn't seem to like empty sections, 1039*0b57cec5SDimitry Andric // so we remove them if any. 1040*0b57cec5SDimitry Andric void Writer::removeEmptySections() { 1041*0b57cec5SDimitry Andric auto isEmpty = [](OutputSection *s) { return s->getVirtualSize() == 0; }; 1042*0b57cec5SDimitry Andric outputSections.erase( 1043*0b57cec5SDimitry Andric std::remove_if(outputSections.begin(), outputSections.end(), isEmpty), 1044*0b57cec5SDimitry Andric outputSections.end()); 1045*0b57cec5SDimitry Andric } 1046*0b57cec5SDimitry Andric 1047*0b57cec5SDimitry Andric void Writer::assignOutputSectionIndices() { 1048*0b57cec5SDimitry Andric // Assign final output section indices, and assign each chunk to its output 1049*0b57cec5SDimitry Andric // section. 1050*0b57cec5SDimitry Andric uint32_t idx = 1; 1051*0b57cec5SDimitry Andric for (OutputSection *os : outputSections) { 1052*0b57cec5SDimitry Andric os->sectionIndex = idx; 1053*0b57cec5SDimitry Andric for (Chunk *c : os->chunks) 1054*0b57cec5SDimitry Andric c->setOutputSectionIdx(idx); 1055*0b57cec5SDimitry Andric ++idx; 1056*0b57cec5SDimitry Andric } 1057*0b57cec5SDimitry Andric 1058*0b57cec5SDimitry Andric // Merge chunks are containers of chunks, so assign those an output section 1059*0b57cec5SDimitry Andric // too. 1060*0b57cec5SDimitry Andric for (MergeChunk *mc : MergeChunk::instances) 1061*0b57cec5SDimitry Andric if (mc) 1062*0b57cec5SDimitry Andric for (SectionChunk *sc : mc->sections) 1063*0b57cec5SDimitry Andric if (sc && sc->live) 1064*0b57cec5SDimitry Andric sc->setOutputSectionIdx(mc->getOutputSectionIdx()); 1065*0b57cec5SDimitry Andric } 1066*0b57cec5SDimitry Andric 1067*0b57cec5SDimitry Andric size_t Writer::addEntryToStringTable(StringRef str) { 1068*0b57cec5SDimitry Andric assert(str.size() > COFF::NameSize); 1069*0b57cec5SDimitry Andric size_t offsetOfEntry = strtab.size() + 4; // +4 for the size field 1070*0b57cec5SDimitry Andric strtab.insert(strtab.end(), str.begin(), str.end()); 1071*0b57cec5SDimitry Andric strtab.push_back('\0'); 1072*0b57cec5SDimitry Andric return offsetOfEntry; 1073*0b57cec5SDimitry Andric } 1074*0b57cec5SDimitry Andric 1075*0b57cec5SDimitry Andric Optional<coff_symbol16> Writer::createSymbol(Defined *def) { 1076*0b57cec5SDimitry Andric coff_symbol16 sym; 1077*0b57cec5SDimitry Andric switch (def->kind()) { 1078*0b57cec5SDimitry Andric case Symbol::DefinedAbsoluteKind: 1079*0b57cec5SDimitry Andric sym.Value = def->getRVA(); 1080*0b57cec5SDimitry Andric sym.SectionNumber = IMAGE_SYM_ABSOLUTE; 1081*0b57cec5SDimitry Andric break; 1082*0b57cec5SDimitry Andric case Symbol::DefinedSyntheticKind: 1083*0b57cec5SDimitry Andric // Relative symbols are unrepresentable in a COFF symbol table. 1084*0b57cec5SDimitry Andric return None; 1085*0b57cec5SDimitry Andric default: { 1086*0b57cec5SDimitry Andric // Don't write symbols that won't be written to the output to the symbol 1087*0b57cec5SDimitry Andric // table. 1088*0b57cec5SDimitry Andric Chunk *c = def->getChunk(); 1089*0b57cec5SDimitry Andric if (!c) 1090*0b57cec5SDimitry Andric return None; 1091*0b57cec5SDimitry Andric OutputSection *os = c->getOutputSection(); 1092*0b57cec5SDimitry Andric if (!os) 1093*0b57cec5SDimitry Andric return None; 1094*0b57cec5SDimitry Andric 1095*0b57cec5SDimitry Andric sym.Value = def->getRVA() - os->getRVA(); 1096*0b57cec5SDimitry Andric sym.SectionNumber = os->sectionIndex; 1097*0b57cec5SDimitry Andric break; 1098*0b57cec5SDimitry Andric } 1099*0b57cec5SDimitry Andric } 1100*0b57cec5SDimitry Andric 1101*0b57cec5SDimitry Andric // Symbols that are runtime pseudo relocations don't point to the actual 1102*0b57cec5SDimitry Andric // symbol data itself (as they are imported), but points to the IAT entry 1103*0b57cec5SDimitry Andric // instead. Avoid emitting them to the symbol table, as they can confuse 1104*0b57cec5SDimitry Andric // debuggers. 1105*0b57cec5SDimitry Andric if (def->isRuntimePseudoReloc) 1106*0b57cec5SDimitry Andric return None; 1107*0b57cec5SDimitry Andric 1108*0b57cec5SDimitry Andric StringRef name = def->getName(); 1109*0b57cec5SDimitry Andric if (name.size() > COFF::NameSize) { 1110*0b57cec5SDimitry Andric sym.Name.Offset.Zeroes = 0; 1111*0b57cec5SDimitry Andric sym.Name.Offset.Offset = addEntryToStringTable(name); 1112*0b57cec5SDimitry Andric } else { 1113*0b57cec5SDimitry Andric memset(sym.Name.ShortName, 0, COFF::NameSize); 1114*0b57cec5SDimitry Andric memcpy(sym.Name.ShortName, name.data(), name.size()); 1115*0b57cec5SDimitry Andric } 1116*0b57cec5SDimitry Andric 1117*0b57cec5SDimitry Andric if (auto *d = dyn_cast<DefinedCOFF>(def)) { 1118*0b57cec5SDimitry Andric COFFSymbolRef ref = d->getCOFFSymbol(); 1119*0b57cec5SDimitry Andric sym.Type = ref.getType(); 1120*0b57cec5SDimitry Andric sym.StorageClass = ref.getStorageClass(); 1121*0b57cec5SDimitry Andric } else { 1122*0b57cec5SDimitry Andric sym.Type = IMAGE_SYM_TYPE_NULL; 1123*0b57cec5SDimitry Andric sym.StorageClass = IMAGE_SYM_CLASS_EXTERNAL; 1124*0b57cec5SDimitry Andric } 1125*0b57cec5SDimitry Andric sym.NumberOfAuxSymbols = 0; 1126*0b57cec5SDimitry Andric return sym; 1127*0b57cec5SDimitry Andric } 1128*0b57cec5SDimitry Andric 1129*0b57cec5SDimitry Andric void Writer::createSymbolAndStringTable() { 1130*0b57cec5SDimitry Andric // PE/COFF images are limited to 8 byte section names. Longer names can be 1131*0b57cec5SDimitry Andric // supported by writing a non-standard string table, but this string table is 1132*0b57cec5SDimitry Andric // not mapped at runtime and the long names will therefore be inaccessible. 1133*0b57cec5SDimitry Andric // link.exe always truncates section names to 8 bytes, whereas binutils always 1134*0b57cec5SDimitry Andric // preserves long section names via the string table. LLD adopts a hybrid 1135*0b57cec5SDimitry Andric // solution where discardable sections have long names preserved and 1136*0b57cec5SDimitry Andric // non-discardable sections have their names truncated, to ensure that any 1137*0b57cec5SDimitry Andric // section which is mapped at runtime also has its name mapped at runtime. 1138*0b57cec5SDimitry Andric for (OutputSection *sec : outputSections) { 1139*0b57cec5SDimitry Andric if (sec->name.size() <= COFF::NameSize) 1140*0b57cec5SDimitry Andric continue; 1141*0b57cec5SDimitry Andric if ((sec->header.Characteristics & IMAGE_SCN_MEM_DISCARDABLE) == 0) 1142*0b57cec5SDimitry Andric continue; 1143*0b57cec5SDimitry Andric sec->setStringTableOff(addEntryToStringTable(sec->name)); 1144*0b57cec5SDimitry Andric } 1145*0b57cec5SDimitry Andric 1146*0b57cec5SDimitry Andric if (config->debugDwarf || config->debugSymtab) { 1147*0b57cec5SDimitry Andric for (ObjFile *file : ObjFile::instances) { 1148*0b57cec5SDimitry Andric for (Symbol *b : file->getSymbols()) { 1149*0b57cec5SDimitry Andric auto *d = dyn_cast_or_null<Defined>(b); 1150*0b57cec5SDimitry Andric if (!d || d->writtenToSymtab) 1151*0b57cec5SDimitry Andric continue; 1152*0b57cec5SDimitry Andric d->writtenToSymtab = true; 1153*0b57cec5SDimitry Andric 1154*0b57cec5SDimitry Andric if (Optional<coff_symbol16> sym = createSymbol(d)) 1155*0b57cec5SDimitry Andric outputSymtab.push_back(*sym); 1156*0b57cec5SDimitry Andric } 1157*0b57cec5SDimitry Andric } 1158*0b57cec5SDimitry Andric } 1159*0b57cec5SDimitry Andric 1160*0b57cec5SDimitry Andric if (outputSymtab.empty() && strtab.empty()) 1161*0b57cec5SDimitry Andric return; 1162*0b57cec5SDimitry Andric 1163*0b57cec5SDimitry Andric // We position the symbol table to be adjacent to the end of the last section. 1164*0b57cec5SDimitry Andric uint64_t fileOff = fileSize; 1165*0b57cec5SDimitry Andric pointerToSymbolTable = fileOff; 1166*0b57cec5SDimitry Andric fileOff += outputSymtab.size() * sizeof(coff_symbol16); 1167*0b57cec5SDimitry Andric fileOff += 4 + strtab.size(); 1168*0b57cec5SDimitry Andric fileSize = alignTo(fileOff, config->fileAlign); 1169*0b57cec5SDimitry Andric } 1170*0b57cec5SDimitry Andric 1171*0b57cec5SDimitry Andric void Writer::mergeSections() { 1172*0b57cec5SDimitry Andric if (!pdataSec->chunks.empty()) { 1173*0b57cec5SDimitry Andric firstPdata = pdataSec->chunks.front(); 1174*0b57cec5SDimitry Andric lastPdata = pdataSec->chunks.back(); 1175*0b57cec5SDimitry Andric } 1176*0b57cec5SDimitry Andric 1177*0b57cec5SDimitry Andric for (auto &p : config->merge) { 1178*0b57cec5SDimitry Andric StringRef toName = p.second; 1179*0b57cec5SDimitry Andric if (p.first == toName) 1180*0b57cec5SDimitry Andric continue; 1181*0b57cec5SDimitry Andric StringSet<> names; 1182*0b57cec5SDimitry Andric while (1) { 1183*0b57cec5SDimitry Andric if (!names.insert(toName).second) 1184*0b57cec5SDimitry Andric fatal("/merge: cycle found for section '" + p.first + "'"); 1185*0b57cec5SDimitry Andric auto i = config->merge.find(toName); 1186*0b57cec5SDimitry Andric if (i == config->merge.end()) 1187*0b57cec5SDimitry Andric break; 1188*0b57cec5SDimitry Andric toName = i->second; 1189*0b57cec5SDimitry Andric } 1190*0b57cec5SDimitry Andric OutputSection *from = findSection(p.first); 1191*0b57cec5SDimitry Andric OutputSection *to = findSection(toName); 1192*0b57cec5SDimitry Andric if (!from) 1193*0b57cec5SDimitry Andric continue; 1194*0b57cec5SDimitry Andric if (!to) { 1195*0b57cec5SDimitry Andric from->name = toName; 1196*0b57cec5SDimitry Andric continue; 1197*0b57cec5SDimitry Andric } 1198*0b57cec5SDimitry Andric to->merge(from); 1199*0b57cec5SDimitry Andric } 1200*0b57cec5SDimitry Andric } 1201*0b57cec5SDimitry Andric 1202*0b57cec5SDimitry Andric // Visits all sections to assign incremental, non-overlapping RVAs and 1203*0b57cec5SDimitry Andric // file offsets. 1204*0b57cec5SDimitry Andric void Writer::assignAddresses() { 1205*0b57cec5SDimitry Andric sizeOfHeaders = dosStubSize + sizeof(PEMagic) + sizeof(coff_file_header) + 1206*0b57cec5SDimitry Andric sizeof(data_directory) * numberOfDataDirectory + 1207*0b57cec5SDimitry Andric sizeof(coff_section) * outputSections.size(); 1208*0b57cec5SDimitry Andric sizeOfHeaders += 1209*0b57cec5SDimitry Andric config->is64() ? sizeof(pe32plus_header) : sizeof(pe32_header); 1210*0b57cec5SDimitry Andric sizeOfHeaders = alignTo(sizeOfHeaders, config->fileAlign); 1211*0b57cec5SDimitry Andric fileSize = sizeOfHeaders; 1212*0b57cec5SDimitry Andric 1213*0b57cec5SDimitry Andric // The first page is kept unmapped. 1214*0b57cec5SDimitry Andric uint64_t rva = alignTo(sizeOfHeaders, config->align); 1215*0b57cec5SDimitry Andric 1216*0b57cec5SDimitry Andric for (OutputSection *sec : outputSections) { 1217*0b57cec5SDimitry Andric if (sec == relocSec) 1218*0b57cec5SDimitry Andric addBaserels(); 1219*0b57cec5SDimitry Andric uint64_t rawSize = 0, virtualSize = 0; 1220*0b57cec5SDimitry Andric sec->header.VirtualAddress = rva; 1221*0b57cec5SDimitry Andric 1222*0b57cec5SDimitry Andric // If /FUNCTIONPADMIN is used, functions are padded in order to create a 1223*0b57cec5SDimitry Andric // hotpatchable image. 1224*0b57cec5SDimitry Andric const bool isCodeSection = 1225*0b57cec5SDimitry Andric (sec->header.Characteristics & IMAGE_SCN_CNT_CODE) && 1226*0b57cec5SDimitry Andric (sec->header.Characteristics & IMAGE_SCN_MEM_READ) && 1227*0b57cec5SDimitry Andric (sec->header.Characteristics & IMAGE_SCN_MEM_EXECUTE); 1228*0b57cec5SDimitry Andric uint32_t padding = isCodeSection ? config->functionPadMin : 0; 1229*0b57cec5SDimitry Andric 1230*0b57cec5SDimitry Andric for (Chunk *c : sec->chunks) { 1231*0b57cec5SDimitry Andric if (padding && c->isHotPatchable()) 1232*0b57cec5SDimitry Andric virtualSize += padding; 1233*0b57cec5SDimitry Andric virtualSize = alignTo(virtualSize, c->getAlignment()); 1234*0b57cec5SDimitry Andric c->setRVA(rva + virtualSize); 1235*0b57cec5SDimitry Andric virtualSize += c->getSize(); 1236*0b57cec5SDimitry Andric if (c->hasData) 1237*0b57cec5SDimitry Andric rawSize = alignTo(virtualSize, config->fileAlign); 1238*0b57cec5SDimitry Andric } 1239*0b57cec5SDimitry Andric if (virtualSize > UINT32_MAX) 1240*0b57cec5SDimitry Andric error("section larger than 4 GiB: " + sec->name); 1241*0b57cec5SDimitry Andric sec->header.VirtualSize = virtualSize; 1242*0b57cec5SDimitry Andric sec->header.SizeOfRawData = rawSize; 1243*0b57cec5SDimitry Andric if (rawSize != 0) 1244*0b57cec5SDimitry Andric sec->header.PointerToRawData = fileSize; 1245*0b57cec5SDimitry Andric rva += alignTo(virtualSize, config->align); 1246*0b57cec5SDimitry Andric fileSize += alignTo(rawSize, config->fileAlign); 1247*0b57cec5SDimitry Andric } 1248*0b57cec5SDimitry Andric sizeOfImage = alignTo(rva, config->align); 1249*0b57cec5SDimitry Andric 1250*0b57cec5SDimitry Andric // Assign addresses to sections in MergeChunks. 1251*0b57cec5SDimitry Andric for (MergeChunk *mc : MergeChunk::instances) 1252*0b57cec5SDimitry Andric if (mc) 1253*0b57cec5SDimitry Andric mc->assignSubsectionRVAs(); 1254*0b57cec5SDimitry Andric } 1255*0b57cec5SDimitry Andric 1256*0b57cec5SDimitry Andric template <typename PEHeaderTy> void Writer::writeHeader() { 1257*0b57cec5SDimitry Andric // Write DOS header. For backwards compatibility, the first part of a PE/COFF 1258*0b57cec5SDimitry Andric // executable consists of an MS-DOS MZ executable. If the executable is run 1259*0b57cec5SDimitry Andric // under DOS, that program gets run (usually to just print an error message). 1260*0b57cec5SDimitry Andric // When run under Windows, the loader looks at AddressOfNewExeHeader and uses 1261*0b57cec5SDimitry Andric // the PE header instead. 1262*0b57cec5SDimitry Andric uint8_t *buf = buffer->getBufferStart(); 1263*0b57cec5SDimitry Andric auto *dos = reinterpret_cast<dos_header *>(buf); 1264*0b57cec5SDimitry Andric buf += sizeof(dos_header); 1265*0b57cec5SDimitry Andric dos->Magic[0] = 'M'; 1266*0b57cec5SDimitry Andric dos->Magic[1] = 'Z'; 1267*0b57cec5SDimitry Andric dos->UsedBytesInTheLastPage = dosStubSize % 512; 1268*0b57cec5SDimitry Andric dos->FileSizeInPages = divideCeil(dosStubSize, 512); 1269*0b57cec5SDimitry Andric dos->HeaderSizeInParagraphs = sizeof(dos_header) / 16; 1270*0b57cec5SDimitry Andric 1271*0b57cec5SDimitry Andric dos->AddressOfRelocationTable = sizeof(dos_header); 1272*0b57cec5SDimitry Andric dos->AddressOfNewExeHeader = dosStubSize; 1273*0b57cec5SDimitry Andric 1274*0b57cec5SDimitry Andric // Write DOS program. 1275*0b57cec5SDimitry Andric memcpy(buf, dosProgram, sizeof(dosProgram)); 1276*0b57cec5SDimitry Andric buf += sizeof(dosProgram); 1277*0b57cec5SDimitry Andric 1278*0b57cec5SDimitry Andric // Write PE magic 1279*0b57cec5SDimitry Andric memcpy(buf, PEMagic, sizeof(PEMagic)); 1280*0b57cec5SDimitry Andric buf += sizeof(PEMagic); 1281*0b57cec5SDimitry Andric 1282*0b57cec5SDimitry Andric // Write COFF header 1283*0b57cec5SDimitry Andric auto *coff = reinterpret_cast<coff_file_header *>(buf); 1284*0b57cec5SDimitry Andric buf += sizeof(*coff); 1285*0b57cec5SDimitry Andric coff->Machine = config->machine; 1286*0b57cec5SDimitry Andric coff->NumberOfSections = outputSections.size(); 1287*0b57cec5SDimitry Andric coff->Characteristics = IMAGE_FILE_EXECUTABLE_IMAGE; 1288*0b57cec5SDimitry Andric if (config->largeAddressAware) 1289*0b57cec5SDimitry Andric coff->Characteristics |= IMAGE_FILE_LARGE_ADDRESS_AWARE; 1290*0b57cec5SDimitry Andric if (!config->is64()) 1291*0b57cec5SDimitry Andric coff->Characteristics |= IMAGE_FILE_32BIT_MACHINE; 1292*0b57cec5SDimitry Andric if (config->dll) 1293*0b57cec5SDimitry Andric coff->Characteristics |= IMAGE_FILE_DLL; 1294*0b57cec5SDimitry Andric if (!config->relocatable) 1295*0b57cec5SDimitry Andric coff->Characteristics |= IMAGE_FILE_RELOCS_STRIPPED; 1296*0b57cec5SDimitry Andric if (config->swaprunCD) 1297*0b57cec5SDimitry Andric coff->Characteristics |= IMAGE_FILE_REMOVABLE_RUN_FROM_SWAP; 1298*0b57cec5SDimitry Andric if (config->swaprunNet) 1299*0b57cec5SDimitry Andric coff->Characteristics |= IMAGE_FILE_NET_RUN_FROM_SWAP; 1300*0b57cec5SDimitry Andric coff->SizeOfOptionalHeader = 1301*0b57cec5SDimitry Andric sizeof(PEHeaderTy) + sizeof(data_directory) * numberOfDataDirectory; 1302*0b57cec5SDimitry Andric 1303*0b57cec5SDimitry Andric // Write PE header 1304*0b57cec5SDimitry Andric auto *pe = reinterpret_cast<PEHeaderTy *>(buf); 1305*0b57cec5SDimitry Andric buf += sizeof(*pe); 1306*0b57cec5SDimitry Andric pe->Magic = config->is64() ? PE32Header::PE32_PLUS : PE32Header::PE32; 1307*0b57cec5SDimitry Andric 1308*0b57cec5SDimitry Andric // If {Major,Minor}LinkerVersion is left at 0.0, then for some 1309*0b57cec5SDimitry Andric // reason signing the resulting PE file with Authenticode produces a 1310*0b57cec5SDimitry Andric // signature that fails to validate on Windows 7 (but is OK on 10). 1311*0b57cec5SDimitry Andric // Set it to 14.0, which is what VS2015 outputs, and which avoids 1312*0b57cec5SDimitry Andric // that problem. 1313*0b57cec5SDimitry Andric pe->MajorLinkerVersion = 14; 1314*0b57cec5SDimitry Andric pe->MinorLinkerVersion = 0; 1315*0b57cec5SDimitry Andric 1316*0b57cec5SDimitry Andric pe->ImageBase = config->imageBase; 1317*0b57cec5SDimitry Andric pe->SectionAlignment = config->align; 1318*0b57cec5SDimitry Andric pe->FileAlignment = config->fileAlign; 1319*0b57cec5SDimitry Andric pe->MajorImageVersion = config->majorImageVersion; 1320*0b57cec5SDimitry Andric pe->MinorImageVersion = config->minorImageVersion; 1321*0b57cec5SDimitry Andric pe->MajorOperatingSystemVersion = config->majorOSVersion; 1322*0b57cec5SDimitry Andric pe->MinorOperatingSystemVersion = config->minorOSVersion; 1323*0b57cec5SDimitry Andric pe->MajorSubsystemVersion = config->majorOSVersion; 1324*0b57cec5SDimitry Andric pe->MinorSubsystemVersion = config->minorOSVersion; 1325*0b57cec5SDimitry Andric pe->Subsystem = config->subsystem; 1326*0b57cec5SDimitry Andric pe->SizeOfImage = sizeOfImage; 1327*0b57cec5SDimitry Andric pe->SizeOfHeaders = sizeOfHeaders; 1328*0b57cec5SDimitry Andric if (!config->noEntry) { 1329*0b57cec5SDimitry Andric Defined *entry = cast<Defined>(config->entry); 1330*0b57cec5SDimitry Andric pe->AddressOfEntryPoint = entry->getRVA(); 1331*0b57cec5SDimitry Andric // Pointer to thumb code must have the LSB set, so adjust it. 1332*0b57cec5SDimitry Andric if (config->machine == ARMNT) 1333*0b57cec5SDimitry Andric pe->AddressOfEntryPoint |= 1; 1334*0b57cec5SDimitry Andric } 1335*0b57cec5SDimitry Andric pe->SizeOfStackReserve = config->stackReserve; 1336*0b57cec5SDimitry Andric pe->SizeOfStackCommit = config->stackCommit; 1337*0b57cec5SDimitry Andric pe->SizeOfHeapReserve = config->heapReserve; 1338*0b57cec5SDimitry Andric pe->SizeOfHeapCommit = config->heapCommit; 1339*0b57cec5SDimitry Andric if (config->appContainer) 1340*0b57cec5SDimitry Andric pe->DLLCharacteristics |= IMAGE_DLL_CHARACTERISTICS_APPCONTAINER; 1341*0b57cec5SDimitry Andric if (config->dynamicBase) 1342*0b57cec5SDimitry Andric pe->DLLCharacteristics |= IMAGE_DLL_CHARACTERISTICS_DYNAMIC_BASE; 1343*0b57cec5SDimitry Andric if (config->highEntropyVA) 1344*0b57cec5SDimitry Andric pe->DLLCharacteristics |= IMAGE_DLL_CHARACTERISTICS_HIGH_ENTROPY_VA; 1345*0b57cec5SDimitry Andric if (!config->allowBind) 1346*0b57cec5SDimitry Andric pe->DLLCharacteristics |= IMAGE_DLL_CHARACTERISTICS_NO_BIND; 1347*0b57cec5SDimitry Andric if (config->nxCompat) 1348*0b57cec5SDimitry Andric pe->DLLCharacteristics |= IMAGE_DLL_CHARACTERISTICS_NX_COMPAT; 1349*0b57cec5SDimitry Andric if (!config->allowIsolation) 1350*0b57cec5SDimitry Andric pe->DLLCharacteristics |= IMAGE_DLL_CHARACTERISTICS_NO_ISOLATION; 1351*0b57cec5SDimitry Andric if (config->guardCF != GuardCFLevel::Off) 1352*0b57cec5SDimitry Andric pe->DLLCharacteristics |= IMAGE_DLL_CHARACTERISTICS_GUARD_CF; 1353*0b57cec5SDimitry Andric if (config->integrityCheck) 1354*0b57cec5SDimitry Andric pe->DLLCharacteristics |= IMAGE_DLL_CHARACTERISTICS_FORCE_INTEGRITY; 1355*0b57cec5SDimitry Andric if (setNoSEHCharacteristic) 1356*0b57cec5SDimitry Andric pe->DLLCharacteristics |= IMAGE_DLL_CHARACTERISTICS_NO_SEH; 1357*0b57cec5SDimitry Andric if (config->terminalServerAware) 1358*0b57cec5SDimitry Andric pe->DLLCharacteristics |= IMAGE_DLL_CHARACTERISTICS_TERMINAL_SERVER_AWARE; 1359*0b57cec5SDimitry Andric pe->NumberOfRvaAndSize = numberOfDataDirectory; 1360*0b57cec5SDimitry Andric if (textSec->getVirtualSize()) { 1361*0b57cec5SDimitry Andric pe->BaseOfCode = textSec->getRVA(); 1362*0b57cec5SDimitry Andric pe->SizeOfCode = textSec->getRawSize(); 1363*0b57cec5SDimitry Andric } 1364*0b57cec5SDimitry Andric pe->SizeOfInitializedData = getSizeOfInitializedData(); 1365*0b57cec5SDimitry Andric 1366*0b57cec5SDimitry Andric // Write data directory 1367*0b57cec5SDimitry Andric auto *dir = reinterpret_cast<data_directory *>(buf); 1368*0b57cec5SDimitry Andric buf += sizeof(*dir) * numberOfDataDirectory; 1369*0b57cec5SDimitry Andric if (!config->exports.empty()) { 1370*0b57cec5SDimitry Andric dir[EXPORT_TABLE].RelativeVirtualAddress = edata.getRVA(); 1371*0b57cec5SDimitry Andric dir[EXPORT_TABLE].Size = edata.getSize(); 1372*0b57cec5SDimitry Andric } 1373*0b57cec5SDimitry Andric if (importTableStart) { 1374*0b57cec5SDimitry Andric dir[IMPORT_TABLE].RelativeVirtualAddress = importTableStart->getRVA(); 1375*0b57cec5SDimitry Andric dir[IMPORT_TABLE].Size = importTableSize; 1376*0b57cec5SDimitry Andric } 1377*0b57cec5SDimitry Andric if (iatStart) { 1378*0b57cec5SDimitry Andric dir[IAT].RelativeVirtualAddress = iatStart->getRVA(); 1379*0b57cec5SDimitry Andric dir[IAT].Size = iatSize; 1380*0b57cec5SDimitry Andric } 1381*0b57cec5SDimitry Andric if (rsrcSec->getVirtualSize()) { 1382*0b57cec5SDimitry Andric dir[RESOURCE_TABLE].RelativeVirtualAddress = rsrcSec->getRVA(); 1383*0b57cec5SDimitry Andric dir[RESOURCE_TABLE].Size = rsrcSec->getVirtualSize(); 1384*0b57cec5SDimitry Andric } 1385*0b57cec5SDimitry Andric if (firstPdata) { 1386*0b57cec5SDimitry Andric dir[EXCEPTION_TABLE].RelativeVirtualAddress = firstPdata->getRVA(); 1387*0b57cec5SDimitry Andric dir[EXCEPTION_TABLE].Size = 1388*0b57cec5SDimitry Andric lastPdata->getRVA() + lastPdata->getSize() - firstPdata->getRVA(); 1389*0b57cec5SDimitry Andric } 1390*0b57cec5SDimitry Andric if (relocSec->getVirtualSize()) { 1391*0b57cec5SDimitry Andric dir[BASE_RELOCATION_TABLE].RelativeVirtualAddress = relocSec->getRVA(); 1392*0b57cec5SDimitry Andric dir[BASE_RELOCATION_TABLE].Size = relocSec->getVirtualSize(); 1393*0b57cec5SDimitry Andric } 1394*0b57cec5SDimitry Andric if (Symbol *sym = symtab->findUnderscore("_tls_used")) { 1395*0b57cec5SDimitry Andric if (Defined *b = dyn_cast<Defined>(sym)) { 1396*0b57cec5SDimitry Andric dir[TLS_TABLE].RelativeVirtualAddress = b->getRVA(); 1397*0b57cec5SDimitry Andric dir[TLS_TABLE].Size = config->is64() 1398*0b57cec5SDimitry Andric ? sizeof(object::coff_tls_directory64) 1399*0b57cec5SDimitry Andric : sizeof(object::coff_tls_directory32); 1400*0b57cec5SDimitry Andric } 1401*0b57cec5SDimitry Andric } 1402*0b57cec5SDimitry Andric if (debugDirectory) { 1403*0b57cec5SDimitry Andric dir[DEBUG_DIRECTORY].RelativeVirtualAddress = debugDirectory->getRVA(); 1404*0b57cec5SDimitry Andric dir[DEBUG_DIRECTORY].Size = debugDirectory->getSize(); 1405*0b57cec5SDimitry Andric } 1406*0b57cec5SDimitry Andric if (Symbol *sym = symtab->findUnderscore("_load_config_used")) { 1407*0b57cec5SDimitry Andric if (auto *b = dyn_cast<DefinedRegular>(sym)) { 1408*0b57cec5SDimitry Andric SectionChunk *sc = b->getChunk(); 1409*0b57cec5SDimitry Andric assert(b->getRVA() >= sc->getRVA()); 1410*0b57cec5SDimitry Andric uint64_t offsetInChunk = b->getRVA() - sc->getRVA(); 1411*0b57cec5SDimitry Andric if (!sc->hasData || offsetInChunk + 4 > sc->getSize()) 1412*0b57cec5SDimitry Andric fatal("_load_config_used is malformed"); 1413*0b57cec5SDimitry Andric 1414*0b57cec5SDimitry Andric ArrayRef<uint8_t> secContents = sc->getContents(); 1415*0b57cec5SDimitry Andric uint32_t loadConfigSize = 1416*0b57cec5SDimitry Andric *reinterpret_cast<const ulittle32_t *>(&secContents[offsetInChunk]); 1417*0b57cec5SDimitry Andric if (offsetInChunk + loadConfigSize > sc->getSize()) 1418*0b57cec5SDimitry Andric fatal("_load_config_used is too large"); 1419*0b57cec5SDimitry Andric dir[LOAD_CONFIG_TABLE].RelativeVirtualAddress = b->getRVA(); 1420*0b57cec5SDimitry Andric dir[LOAD_CONFIG_TABLE].Size = loadConfigSize; 1421*0b57cec5SDimitry Andric } 1422*0b57cec5SDimitry Andric } 1423*0b57cec5SDimitry Andric if (!delayIdata.empty()) { 1424*0b57cec5SDimitry Andric dir[DELAY_IMPORT_DESCRIPTOR].RelativeVirtualAddress = 1425*0b57cec5SDimitry Andric delayIdata.getDirRVA(); 1426*0b57cec5SDimitry Andric dir[DELAY_IMPORT_DESCRIPTOR].Size = delayIdata.getDirSize(); 1427*0b57cec5SDimitry Andric } 1428*0b57cec5SDimitry Andric 1429*0b57cec5SDimitry Andric // Write section table 1430*0b57cec5SDimitry Andric for (OutputSection *sec : outputSections) { 1431*0b57cec5SDimitry Andric sec->writeHeaderTo(buf); 1432*0b57cec5SDimitry Andric buf += sizeof(coff_section); 1433*0b57cec5SDimitry Andric } 1434*0b57cec5SDimitry Andric sectionTable = ArrayRef<uint8_t>( 1435*0b57cec5SDimitry Andric buf - outputSections.size() * sizeof(coff_section), buf); 1436*0b57cec5SDimitry Andric 1437*0b57cec5SDimitry Andric if (outputSymtab.empty() && strtab.empty()) 1438*0b57cec5SDimitry Andric return; 1439*0b57cec5SDimitry Andric 1440*0b57cec5SDimitry Andric coff->PointerToSymbolTable = pointerToSymbolTable; 1441*0b57cec5SDimitry Andric uint32_t numberOfSymbols = outputSymtab.size(); 1442*0b57cec5SDimitry Andric coff->NumberOfSymbols = numberOfSymbols; 1443*0b57cec5SDimitry Andric auto *symbolTable = reinterpret_cast<coff_symbol16 *>( 1444*0b57cec5SDimitry Andric buffer->getBufferStart() + coff->PointerToSymbolTable); 1445*0b57cec5SDimitry Andric for (size_t i = 0; i != numberOfSymbols; ++i) 1446*0b57cec5SDimitry Andric symbolTable[i] = outputSymtab[i]; 1447*0b57cec5SDimitry Andric // Create the string table, it follows immediately after the symbol table. 1448*0b57cec5SDimitry Andric // The first 4 bytes is length including itself. 1449*0b57cec5SDimitry Andric buf = reinterpret_cast<uint8_t *>(&symbolTable[numberOfSymbols]); 1450*0b57cec5SDimitry Andric write32le(buf, strtab.size() + 4); 1451*0b57cec5SDimitry Andric if (!strtab.empty()) 1452*0b57cec5SDimitry Andric memcpy(buf + 4, strtab.data(), strtab.size()); 1453*0b57cec5SDimitry Andric } 1454*0b57cec5SDimitry Andric 1455*0b57cec5SDimitry Andric void Writer::openFile(StringRef path) { 1456*0b57cec5SDimitry Andric buffer = CHECK( 1457*0b57cec5SDimitry Andric FileOutputBuffer::create(path, fileSize, FileOutputBuffer::F_executable), 1458*0b57cec5SDimitry Andric "failed to open " + path); 1459*0b57cec5SDimitry Andric } 1460*0b57cec5SDimitry Andric 1461*0b57cec5SDimitry Andric void Writer::createSEHTable() { 1462*0b57cec5SDimitry Andric SymbolRVASet handlers; 1463*0b57cec5SDimitry Andric for (ObjFile *file : ObjFile::instances) { 1464*0b57cec5SDimitry Andric if (!file->hasSafeSEH()) 1465*0b57cec5SDimitry Andric error("/safeseh: " + file->getName() + " is not compatible with SEH"); 1466*0b57cec5SDimitry Andric markSymbolsForRVATable(file, file->getSXDataChunks(), handlers); 1467*0b57cec5SDimitry Andric } 1468*0b57cec5SDimitry Andric 1469*0b57cec5SDimitry Andric // Set the "no SEH" characteristic if there really were no handlers, or if 1470*0b57cec5SDimitry Andric // there is no load config object to point to the table of handlers. 1471*0b57cec5SDimitry Andric setNoSEHCharacteristic = 1472*0b57cec5SDimitry Andric handlers.empty() || !symtab->findUnderscore("_load_config_used"); 1473*0b57cec5SDimitry Andric 1474*0b57cec5SDimitry Andric maybeAddRVATable(std::move(handlers), "__safe_se_handler_table", 1475*0b57cec5SDimitry Andric "__safe_se_handler_count"); 1476*0b57cec5SDimitry Andric } 1477*0b57cec5SDimitry Andric 1478*0b57cec5SDimitry Andric // Add a symbol to an RVA set. Two symbols may have the same RVA, but an RVA set 1479*0b57cec5SDimitry Andric // cannot contain duplicates. Therefore, the set is uniqued by Chunk and the 1480*0b57cec5SDimitry Andric // symbol's offset into that Chunk. 1481*0b57cec5SDimitry Andric static void addSymbolToRVASet(SymbolRVASet &rvaSet, Defined *s) { 1482*0b57cec5SDimitry Andric Chunk *c = s->getChunk(); 1483*0b57cec5SDimitry Andric if (auto *sc = dyn_cast<SectionChunk>(c)) 1484*0b57cec5SDimitry Andric c = sc->repl; // Look through ICF replacement. 1485*0b57cec5SDimitry Andric uint32_t off = s->getRVA() - (c ? c->getRVA() : 0); 1486*0b57cec5SDimitry Andric rvaSet.insert({c, off}); 1487*0b57cec5SDimitry Andric } 1488*0b57cec5SDimitry Andric 1489*0b57cec5SDimitry Andric // Given a symbol, add it to the GFIDs table if it is a live, defined, function 1490*0b57cec5SDimitry Andric // symbol in an executable section. 1491*0b57cec5SDimitry Andric static void maybeAddAddressTakenFunction(SymbolRVASet &addressTakenSyms, 1492*0b57cec5SDimitry Andric Symbol *s) { 1493*0b57cec5SDimitry Andric if (!s) 1494*0b57cec5SDimitry Andric return; 1495*0b57cec5SDimitry Andric 1496*0b57cec5SDimitry Andric switch (s->kind()) { 1497*0b57cec5SDimitry Andric case Symbol::DefinedLocalImportKind: 1498*0b57cec5SDimitry Andric case Symbol::DefinedImportDataKind: 1499*0b57cec5SDimitry Andric // Defines an __imp_ pointer, so it is data, so it is ignored. 1500*0b57cec5SDimitry Andric break; 1501*0b57cec5SDimitry Andric case Symbol::DefinedCommonKind: 1502*0b57cec5SDimitry Andric // Common is always data, so it is ignored. 1503*0b57cec5SDimitry Andric break; 1504*0b57cec5SDimitry Andric case Symbol::DefinedAbsoluteKind: 1505*0b57cec5SDimitry Andric case Symbol::DefinedSyntheticKind: 1506*0b57cec5SDimitry Andric // Absolute is never code, synthetic generally isn't and usually isn't 1507*0b57cec5SDimitry Andric // determinable. 1508*0b57cec5SDimitry Andric break; 1509*0b57cec5SDimitry Andric case Symbol::LazyKind: 1510*0b57cec5SDimitry Andric case Symbol::UndefinedKind: 1511*0b57cec5SDimitry Andric // Undefined symbols resolve to zero, so they don't have an RVA. Lazy 1512*0b57cec5SDimitry Andric // symbols shouldn't have relocations. 1513*0b57cec5SDimitry Andric break; 1514*0b57cec5SDimitry Andric 1515*0b57cec5SDimitry Andric case Symbol::DefinedImportThunkKind: 1516*0b57cec5SDimitry Andric // Thunks are always code, include them. 1517*0b57cec5SDimitry Andric addSymbolToRVASet(addressTakenSyms, cast<Defined>(s)); 1518*0b57cec5SDimitry Andric break; 1519*0b57cec5SDimitry Andric 1520*0b57cec5SDimitry Andric case Symbol::DefinedRegularKind: { 1521*0b57cec5SDimitry Andric // This is a regular, defined, symbol from a COFF file. Mark the symbol as 1522*0b57cec5SDimitry Andric // address taken if the symbol type is function and it's in an executable 1523*0b57cec5SDimitry Andric // section. 1524*0b57cec5SDimitry Andric auto *d = cast<DefinedRegular>(s); 1525*0b57cec5SDimitry Andric if (d->getCOFFSymbol().getComplexType() == COFF::IMAGE_SYM_DTYPE_FUNCTION) { 1526*0b57cec5SDimitry Andric SectionChunk *sc = dyn_cast<SectionChunk>(d->getChunk()); 1527*0b57cec5SDimitry Andric if (sc && sc->live && 1528*0b57cec5SDimitry Andric sc->getOutputCharacteristics() & IMAGE_SCN_MEM_EXECUTE) 1529*0b57cec5SDimitry Andric addSymbolToRVASet(addressTakenSyms, d); 1530*0b57cec5SDimitry Andric } 1531*0b57cec5SDimitry Andric break; 1532*0b57cec5SDimitry Andric } 1533*0b57cec5SDimitry Andric } 1534*0b57cec5SDimitry Andric } 1535*0b57cec5SDimitry Andric 1536*0b57cec5SDimitry Andric // Visit all relocations from all section contributions of this object file and 1537*0b57cec5SDimitry Andric // mark the relocation target as address-taken. 1538*0b57cec5SDimitry Andric static void markSymbolsWithRelocations(ObjFile *file, 1539*0b57cec5SDimitry Andric SymbolRVASet &usedSymbols) { 1540*0b57cec5SDimitry Andric for (Chunk *c : file->getChunks()) { 1541*0b57cec5SDimitry Andric // We only care about live section chunks. Common chunks and other chunks 1542*0b57cec5SDimitry Andric // don't generally contain relocations. 1543*0b57cec5SDimitry Andric SectionChunk *sc = dyn_cast<SectionChunk>(c); 1544*0b57cec5SDimitry Andric if (!sc || !sc->live) 1545*0b57cec5SDimitry Andric continue; 1546*0b57cec5SDimitry Andric 1547*0b57cec5SDimitry Andric for (const coff_relocation &reloc : sc->getRelocs()) { 1548*0b57cec5SDimitry Andric if (config->machine == I386 && reloc.Type == COFF::IMAGE_REL_I386_REL32) 1549*0b57cec5SDimitry Andric // Ignore relative relocations on x86. On x86_64 they can't be ignored 1550*0b57cec5SDimitry Andric // since they're also used to compute absolute addresses. 1551*0b57cec5SDimitry Andric continue; 1552*0b57cec5SDimitry Andric 1553*0b57cec5SDimitry Andric Symbol *ref = sc->file->getSymbol(reloc.SymbolTableIndex); 1554*0b57cec5SDimitry Andric maybeAddAddressTakenFunction(usedSymbols, ref); 1555*0b57cec5SDimitry Andric } 1556*0b57cec5SDimitry Andric } 1557*0b57cec5SDimitry Andric } 1558*0b57cec5SDimitry Andric 1559*0b57cec5SDimitry Andric // Create the guard function id table. This is a table of RVAs of all 1560*0b57cec5SDimitry Andric // address-taken functions. It is sorted and uniqued, just like the safe SEH 1561*0b57cec5SDimitry Andric // table. 1562*0b57cec5SDimitry Andric void Writer::createGuardCFTables() { 1563*0b57cec5SDimitry Andric SymbolRVASet addressTakenSyms; 1564*0b57cec5SDimitry Andric SymbolRVASet longJmpTargets; 1565*0b57cec5SDimitry Andric for (ObjFile *file : ObjFile::instances) { 1566*0b57cec5SDimitry Andric // If the object was compiled with /guard:cf, the address taken symbols 1567*0b57cec5SDimitry Andric // are in .gfids$y sections, and the longjmp targets are in .gljmp$y 1568*0b57cec5SDimitry Andric // sections. If the object was not compiled with /guard:cf, we assume there 1569*0b57cec5SDimitry Andric // were no setjmp targets, and that all code symbols with relocations are 1570*0b57cec5SDimitry Andric // possibly address-taken. 1571*0b57cec5SDimitry Andric if (file->hasGuardCF()) { 1572*0b57cec5SDimitry Andric markSymbolsForRVATable(file, file->getGuardFidChunks(), addressTakenSyms); 1573*0b57cec5SDimitry Andric markSymbolsForRVATable(file, file->getGuardLJmpChunks(), longJmpTargets); 1574*0b57cec5SDimitry Andric } else { 1575*0b57cec5SDimitry Andric markSymbolsWithRelocations(file, addressTakenSyms); 1576*0b57cec5SDimitry Andric } 1577*0b57cec5SDimitry Andric } 1578*0b57cec5SDimitry Andric 1579*0b57cec5SDimitry Andric // Mark the image entry as address-taken. 1580*0b57cec5SDimitry Andric if (config->entry) 1581*0b57cec5SDimitry Andric maybeAddAddressTakenFunction(addressTakenSyms, config->entry); 1582*0b57cec5SDimitry Andric 1583*0b57cec5SDimitry Andric // Mark exported symbols in executable sections as address-taken. 1584*0b57cec5SDimitry Andric for (Export &e : config->exports) 1585*0b57cec5SDimitry Andric maybeAddAddressTakenFunction(addressTakenSyms, e.sym); 1586*0b57cec5SDimitry Andric 1587*0b57cec5SDimitry Andric // Ensure sections referenced in the gfid table are 16-byte aligned. 1588*0b57cec5SDimitry Andric for (const ChunkAndOffset &c : addressTakenSyms) 1589*0b57cec5SDimitry Andric if (c.inputChunk->getAlignment() < 16) 1590*0b57cec5SDimitry Andric c.inputChunk->setAlignment(16); 1591*0b57cec5SDimitry Andric 1592*0b57cec5SDimitry Andric maybeAddRVATable(std::move(addressTakenSyms), "__guard_fids_table", 1593*0b57cec5SDimitry Andric "__guard_fids_count"); 1594*0b57cec5SDimitry Andric 1595*0b57cec5SDimitry Andric // Add the longjmp target table unless the user told us not to. 1596*0b57cec5SDimitry Andric if (config->guardCF == GuardCFLevel::Full) 1597*0b57cec5SDimitry Andric maybeAddRVATable(std::move(longJmpTargets), "__guard_longjmp_table", 1598*0b57cec5SDimitry Andric "__guard_longjmp_count"); 1599*0b57cec5SDimitry Andric 1600*0b57cec5SDimitry Andric // Set __guard_flags, which will be used in the load config to indicate that 1601*0b57cec5SDimitry Andric // /guard:cf was enabled. 1602*0b57cec5SDimitry Andric uint32_t guardFlags = uint32_t(coff_guard_flags::CFInstrumented) | 1603*0b57cec5SDimitry Andric uint32_t(coff_guard_flags::HasFidTable); 1604*0b57cec5SDimitry Andric if (config->guardCF == GuardCFLevel::Full) 1605*0b57cec5SDimitry Andric guardFlags |= uint32_t(coff_guard_flags::HasLongJmpTable); 1606*0b57cec5SDimitry Andric Symbol *flagSym = symtab->findUnderscore("__guard_flags"); 1607*0b57cec5SDimitry Andric cast<DefinedAbsolute>(flagSym)->setVA(guardFlags); 1608*0b57cec5SDimitry Andric } 1609*0b57cec5SDimitry Andric 1610*0b57cec5SDimitry Andric // Take a list of input sections containing symbol table indices and add those 1611*0b57cec5SDimitry Andric // symbols to an RVA table. The challenge is that symbol RVAs are not known and 1612*0b57cec5SDimitry Andric // depend on the table size, so we can't directly build a set of integers. 1613*0b57cec5SDimitry Andric void Writer::markSymbolsForRVATable(ObjFile *file, 1614*0b57cec5SDimitry Andric ArrayRef<SectionChunk *> symIdxChunks, 1615*0b57cec5SDimitry Andric SymbolRVASet &tableSymbols) { 1616*0b57cec5SDimitry Andric for (SectionChunk *c : symIdxChunks) { 1617*0b57cec5SDimitry Andric // Skip sections discarded by linker GC. This comes up when a .gfids section 1618*0b57cec5SDimitry Andric // is associated with something like a vtable and the vtable is discarded. 1619*0b57cec5SDimitry Andric // In this case, the associated gfids section is discarded, and we don't 1620*0b57cec5SDimitry Andric // mark the virtual member functions as address-taken by the vtable. 1621*0b57cec5SDimitry Andric if (!c->live) 1622*0b57cec5SDimitry Andric continue; 1623*0b57cec5SDimitry Andric 1624*0b57cec5SDimitry Andric // Validate that the contents look like symbol table indices. 1625*0b57cec5SDimitry Andric ArrayRef<uint8_t> data = c->getContents(); 1626*0b57cec5SDimitry Andric if (data.size() % 4 != 0) { 1627*0b57cec5SDimitry Andric warn("ignoring " + c->getSectionName() + 1628*0b57cec5SDimitry Andric " symbol table index section in object " + toString(file)); 1629*0b57cec5SDimitry Andric continue; 1630*0b57cec5SDimitry Andric } 1631*0b57cec5SDimitry Andric 1632*0b57cec5SDimitry Andric // Read each symbol table index and check if that symbol was included in the 1633*0b57cec5SDimitry Andric // final link. If so, add it to the table symbol set. 1634*0b57cec5SDimitry Andric ArrayRef<ulittle32_t> symIndices( 1635*0b57cec5SDimitry Andric reinterpret_cast<const ulittle32_t *>(data.data()), data.size() / 4); 1636*0b57cec5SDimitry Andric ArrayRef<Symbol *> objSymbols = file->getSymbols(); 1637*0b57cec5SDimitry Andric for (uint32_t symIndex : symIndices) { 1638*0b57cec5SDimitry Andric if (symIndex >= objSymbols.size()) { 1639*0b57cec5SDimitry Andric warn("ignoring invalid symbol table index in section " + 1640*0b57cec5SDimitry Andric c->getSectionName() + " in object " + toString(file)); 1641*0b57cec5SDimitry Andric continue; 1642*0b57cec5SDimitry Andric } 1643*0b57cec5SDimitry Andric if (Symbol *s = objSymbols[symIndex]) { 1644*0b57cec5SDimitry Andric if (s->isLive()) 1645*0b57cec5SDimitry Andric addSymbolToRVASet(tableSymbols, cast<Defined>(s)); 1646*0b57cec5SDimitry Andric } 1647*0b57cec5SDimitry Andric } 1648*0b57cec5SDimitry Andric } 1649*0b57cec5SDimitry Andric } 1650*0b57cec5SDimitry Andric 1651*0b57cec5SDimitry Andric // Replace the absolute table symbol with a synthetic symbol pointing to 1652*0b57cec5SDimitry Andric // tableChunk so that we can emit base relocations for it and resolve section 1653*0b57cec5SDimitry Andric // relative relocations. 1654*0b57cec5SDimitry Andric void Writer::maybeAddRVATable(SymbolRVASet tableSymbols, StringRef tableSym, 1655*0b57cec5SDimitry Andric StringRef countSym) { 1656*0b57cec5SDimitry Andric if (tableSymbols.empty()) 1657*0b57cec5SDimitry Andric return; 1658*0b57cec5SDimitry Andric 1659*0b57cec5SDimitry Andric RVATableChunk *tableChunk = make<RVATableChunk>(std::move(tableSymbols)); 1660*0b57cec5SDimitry Andric rdataSec->addChunk(tableChunk); 1661*0b57cec5SDimitry Andric 1662*0b57cec5SDimitry Andric Symbol *t = symtab->findUnderscore(tableSym); 1663*0b57cec5SDimitry Andric Symbol *c = symtab->findUnderscore(countSym); 1664*0b57cec5SDimitry Andric replaceSymbol<DefinedSynthetic>(t, t->getName(), tableChunk); 1665*0b57cec5SDimitry Andric cast<DefinedAbsolute>(c)->setVA(tableChunk->getSize() / 4); 1666*0b57cec5SDimitry Andric } 1667*0b57cec5SDimitry Andric 1668*0b57cec5SDimitry Andric // MinGW specific. Gather all relocations that are imported from a DLL even 1669*0b57cec5SDimitry Andric // though the code didn't expect it to, produce the table that the runtime 1670*0b57cec5SDimitry Andric // uses for fixing them up, and provide the synthetic symbols that the 1671*0b57cec5SDimitry Andric // runtime uses for finding the table. 1672*0b57cec5SDimitry Andric void Writer::createRuntimePseudoRelocs() { 1673*0b57cec5SDimitry Andric std::vector<RuntimePseudoReloc> rels; 1674*0b57cec5SDimitry Andric 1675*0b57cec5SDimitry Andric for (Chunk *c : symtab->getChunks()) { 1676*0b57cec5SDimitry Andric auto *sc = dyn_cast<SectionChunk>(c); 1677*0b57cec5SDimitry Andric if (!sc || !sc->live) 1678*0b57cec5SDimitry Andric continue; 1679*0b57cec5SDimitry Andric sc->getRuntimePseudoRelocs(rels); 1680*0b57cec5SDimitry Andric } 1681*0b57cec5SDimitry Andric 1682*0b57cec5SDimitry Andric if (!rels.empty()) 1683*0b57cec5SDimitry Andric log("Writing " + Twine(rels.size()) + " runtime pseudo relocations"); 1684*0b57cec5SDimitry Andric PseudoRelocTableChunk *table = make<PseudoRelocTableChunk>(rels); 1685*0b57cec5SDimitry Andric rdataSec->addChunk(table); 1686*0b57cec5SDimitry Andric EmptyChunk *endOfList = make<EmptyChunk>(); 1687*0b57cec5SDimitry Andric rdataSec->addChunk(endOfList); 1688*0b57cec5SDimitry Andric 1689*0b57cec5SDimitry Andric Symbol *headSym = symtab->findUnderscore("__RUNTIME_PSEUDO_RELOC_LIST__"); 1690*0b57cec5SDimitry Andric Symbol *endSym = symtab->findUnderscore("__RUNTIME_PSEUDO_RELOC_LIST_END__"); 1691*0b57cec5SDimitry Andric replaceSymbol<DefinedSynthetic>(headSym, headSym->getName(), table); 1692*0b57cec5SDimitry Andric replaceSymbol<DefinedSynthetic>(endSym, endSym->getName(), endOfList); 1693*0b57cec5SDimitry Andric } 1694*0b57cec5SDimitry Andric 1695*0b57cec5SDimitry Andric // MinGW specific. 1696*0b57cec5SDimitry Andric // The MinGW .ctors and .dtors lists have sentinels at each end; 1697*0b57cec5SDimitry Andric // a (uintptr_t)-1 at the start and a (uintptr_t)0 at the end. 1698*0b57cec5SDimitry Andric // There's a symbol pointing to the start sentinel pointer, __CTOR_LIST__ 1699*0b57cec5SDimitry Andric // and __DTOR_LIST__ respectively. 1700*0b57cec5SDimitry Andric void Writer::insertCtorDtorSymbols() { 1701*0b57cec5SDimitry Andric AbsolutePointerChunk *ctorListHead = make<AbsolutePointerChunk>(-1); 1702*0b57cec5SDimitry Andric AbsolutePointerChunk *ctorListEnd = make<AbsolutePointerChunk>(0); 1703*0b57cec5SDimitry Andric AbsolutePointerChunk *dtorListHead = make<AbsolutePointerChunk>(-1); 1704*0b57cec5SDimitry Andric AbsolutePointerChunk *dtorListEnd = make<AbsolutePointerChunk>(0); 1705*0b57cec5SDimitry Andric ctorsSec->insertChunkAtStart(ctorListHead); 1706*0b57cec5SDimitry Andric ctorsSec->addChunk(ctorListEnd); 1707*0b57cec5SDimitry Andric dtorsSec->insertChunkAtStart(dtorListHead); 1708*0b57cec5SDimitry Andric dtorsSec->addChunk(dtorListEnd); 1709*0b57cec5SDimitry Andric 1710*0b57cec5SDimitry Andric Symbol *ctorListSym = symtab->findUnderscore("__CTOR_LIST__"); 1711*0b57cec5SDimitry Andric Symbol *dtorListSym = symtab->findUnderscore("__DTOR_LIST__"); 1712*0b57cec5SDimitry Andric replaceSymbol<DefinedSynthetic>(ctorListSym, ctorListSym->getName(), 1713*0b57cec5SDimitry Andric ctorListHead); 1714*0b57cec5SDimitry Andric replaceSymbol<DefinedSynthetic>(dtorListSym, dtorListSym->getName(), 1715*0b57cec5SDimitry Andric dtorListHead); 1716*0b57cec5SDimitry Andric } 1717*0b57cec5SDimitry Andric 1718*0b57cec5SDimitry Andric // Handles /section options to allow users to overwrite 1719*0b57cec5SDimitry Andric // section attributes. 1720*0b57cec5SDimitry Andric void Writer::setSectionPermissions() { 1721*0b57cec5SDimitry Andric for (auto &p : config->section) { 1722*0b57cec5SDimitry Andric StringRef name = p.first; 1723*0b57cec5SDimitry Andric uint32_t perm = p.second; 1724*0b57cec5SDimitry Andric for (OutputSection *sec : outputSections) 1725*0b57cec5SDimitry Andric if (sec->name == name) 1726*0b57cec5SDimitry Andric sec->setPermissions(perm); 1727*0b57cec5SDimitry Andric } 1728*0b57cec5SDimitry Andric } 1729*0b57cec5SDimitry Andric 1730*0b57cec5SDimitry Andric // Write section contents to a mmap'ed file. 1731*0b57cec5SDimitry Andric void Writer::writeSections() { 1732*0b57cec5SDimitry Andric // Record the number of sections to apply section index relocations 1733*0b57cec5SDimitry Andric // against absolute symbols. See applySecIdx in Chunks.cpp.. 1734*0b57cec5SDimitry Andric DefinedAbsolute::numOutputSections = outputSections.size(); 1735*0b57cec5SDimitry Andric 1736*0b57cec5SDimitry Andric uint8_t *buf = buffer->getBufferStart(); 1737*0b57cec5SDimitry Andric for (OutputSection *sec : outputSections) { 1738*0b57cec5SDimitry Andric uint8_t *secBuf = buf + sec->getFileOff(); 1739*0b57cec5SDimitry Andric // Fill gaps between functions in .text with INT3 instructions 1740*0b57cec5SDimitry Andric // instead of leaving as NUL bytes (which can be interpreted as 1741*0b57cec5SDimitry Andric // ADD instructions). 1742*0b57cec5SDimitry Andric if (sec->header.Characteristics & IMAGE_SCN_CNT_CODE) 1743*0b57cec5SDimitry Andric memset(secBuf, 0xCC, sec->getRawSize()); 1744*0b57cec5SDimitry Andric parallelForEach(sec->chunks, [&](Chunk *c) { 1745*0b57cec5SDimitry Andric c->writeTo(secBuf + c->getRVA() - sec->getRVA()); 1746*0b57cec5SDimitry Andric }); 1747*0b57cec5SDimitry Andric } 1748*0b57cec5SDimitry Andric } 1749*0b57cec5SDimitry Andric 1750*0b57cec5SDimitry Andric void Writer::writeBuildId() { 1751*0b57cec5SDimitry Andric // There are two important parts to the build ID. 1752*0b57cec5SDimitry Andric // 1) If building with debug info, the COFF debug directory contains a 1753*0b57cec5SDimitry Andric // timestamp as well as a Guid and Age of the PDB. 1754*0b57cec5SDimitry Andric // 2) In all cases, the PE COFF file header also contains a timestamp. 1755*0b57cec5SDimitry Andric // For reproducibility, instead of a timestamp we want to use a hash of the 1756*0b57cec5SDimitry Andric // PE contents. 1757*0b57cec5SDimitry Andric if (config->debug) { 1758*0b57cec5SDimitry Andric assert(buildId && "BuildId is not set!"); 1759*0b57cec5SDimitry Andric // BuildId->BuildId was filled in when the PDB was written. 1760*0b57cec5SDimitry Andric } 1761*0b57cec5SDimitry Andric 1762*0b57cec5SDimitry Andric // At this point the only fields in the COFF file which remain unset are the 1763*0b57cec5SDimitry Andric // "timestamp" in the COFF file header, and the ones in the coff debug 1764*0b57cec5SDimitry Andric // directory. Now we can hash the file and write that hash to the various 1765*0b57cec5SDimitry Andric // timestamp fields in the file. 1766*0b57cec5SDimitry Andric StringRef outputFileData( 1767*0b57cec5SDimitry Andric reinterpret_cast<const char *>(buffer->getBufferStart()), 1768*0b57cec5SDimitry Andric buffer->getBufferSize()); 1769*0b57cec5SDimitry Andric 1770*0b57cec5SDimitry Andric uint32_t timestamp = config->timestamp; 1771*0b57cec5SDimitry Andric uint64_t hash = 0; 1772*0b57cec5SDimitry Andric bool generateSyntheticBuildId = 1773*0b57cec5SDimitry Andric config->mingw && config->debug && config->pdbPath.empty(); 1774*0b57cec5SDimitry Andric 1775*0b57cec5SDimitry Andric if (config->repro || generateSyntheticBuildId) 1776*0b57cec5SDimitry Andric hash = xxHash64(outputFileData); 1777*0b57cec5SDimitry Andric 1778*0b57cec5SDimitry Andric if (config->repro) 1779*0b57cec5SDimitry Andric timestamp = static_cast<uint32_t>(hash); 1780*0b57cec5SDimitry Andric 1781*0b57cec5SDimitry Andric if (generateSyntheticBuildId) { 1782*0b57cec5SDimitry Andric // For MinGW builds without a PDB file, we still generate a build id 1783*0b57cec5SDimitry Andric // to allow associating a crash dump to the executable. 1784*0b57cec5SDimitry Andric buildId->buildId->PDB70.CVSignature = OMF::Signature::PDB70; 1785*0b57cec5SDimitry Andric buildId->buildId->PDB70.Age = 1; 1786*0b57cec5SDimitry Andric memcpy(buildId->buildId->PDB70.Signature, &hash, 8); 1787*0b57cec5SDimitry Andric // xxhash only gives us 8 bytes, so put some fixed data in the other half. 1788*0b57cec5SDimitry Andric memcpy(&buildId->buildId->PDB70.Signature[8], "LLD PDB.", 8); 1789*0b57cec5SDimitry Andric } 1790*0b57cec5SDimitry Andric 1791*0b57cec5SDimitry Andric if (debugDirectory) 1792*0b57cec5SDimitry Andric debugDirectory->setTimeDateStamp(timestamp); 1793*0b57cec5SDimitry Andric 1794*0b57cec5SDimitry Andric uint8_t *buf = buffer->getBufferStart(); 1795*0b57cec5SDimitry Andric buf += dosStubSize + sizeof(PEMagic); 1796*0b57cec5SDimitry Andric object::coff_file_header *coffHeader = 1797*0b57cec5SDimitry Andric reinterpret_cast<coff_file_header *>(buf); 1798*0b57cec5SDimitry Andric coffHeader->TimeDateStamp = timestamp; 1799*0b57cec5SDimitry Andric } 1800*0b57cec5SDimitry Andric 1801*0b57cec5SDimitry Andric // Sort .pdata section contents according to PE/COFF spec 5.5. 1802*0b57cec5SDimitry Andric void Writer::sortExceptionTable() { 1803*0b57cec5SDimitry Andric if (!firstPdata) 1804*0b57cec5SDimitry Andric return; 1805*0b57cec5SDimitry Andric // We assume .pdata contains function table entries only. 1806*0b57cec5SDimitry Andric auto bufAddr = [&](Chunk *c) { 1807*0b57cec5SDimitry Andric OutputSection *os = c->getOutputSection(); 1808*0b57cec5SDimitry Andric return buffer->getBufferStart() + os->getFileOff() + c->getRVA() - 1809*0b57cec5SDimitry Andric os->getRVA(); 1810*0b57cec5SDimitry Andric }; 1811*0b57cec5SDimitry Andric uint8_t *begin = bufAddr(firstPdata); 1812*0b57cec5SDimitry Andric uint8_t *end = bufAddr(lastPdata) + lastPdata->getSize(); 1813*0b57cec5SDimitry Andric if (config->machine == AMD64) { 1814*0b57cec5SDimitry Andric struct Entry { ulittle32_t begin, end, unwind; }; 1815*0b57cec5SDimitry Andric parallelSort( 1816*0b57cec5SDimitry Andric MutableArrayRef<Entry>((Entry *)begin, (Entry *)end), 1817*0b57cec5SDimitry Andric [](const Entry &a, const Entry &b) { return a.begin < b.begin; }); 1818*0b57cec5SDimitry Andric return; 1819*0b57cec5SDimitry Andric } 1820*0b57cec5SDimitry Andric if (config->machine == ARMNT || config->machine == ARM64) { 1821*0b57cec5SDimitry Andric struct Entry { ulittle32_t begin, unwind; }; 1822*0b57cec5SDimitry Andric parallelSort( 1823*0b57cec5SDimitry Andric MutableArrayRef<Entry>((Entry *)begin, (Entry *)end), 1824*0b57cec5SDimitry Andric [](const Entry &a, const Entry &b) { return a.begin < b.begin; }); 1825*0b57cec5SDimitry Andric return; 1826*0b57cec5SDimitry Andric } 1827*0b57cec5SDimitry Andric errs() << "warning: don't know how to handle .pdata.\n"; 1828*0b57cec5SDimitry Andric } 1829*0b57cec5SDimitry Andric 1830*0b57cec5SDimitry Andric // The CRT section contains, among other things, the array of function 1831*0b57cec5SDimitry Andric // pointers that initialize every global variable that is not trivially 1832*0b57cec5SDimitry Andric // constructed. The CRT calls them one after the other prior to invoking 1833*0b57cec5SDimitry Andric // main(). 1834*0b57cec5SDimitry Andric // 1835*0b57cec5SDimitry Andric // As per C++ spec, 3.6.2/2.3, 1836*0b57cec5SDimitry Andric // "Variables with ordered initialization defined within a single 1837*0b57cec5SDimitry Andric // translation unit shall be initialized in the order of their definitions 1838*0b57cec5SDimitry Andric // in the translation unit" 1839*0b57cec5SDimitry Andric // 1840*0b57cec5SDimitry Andric // It is therefore critical to sort the chunks containing the function 1841*0b57cec5SDimitry Andric // pointers in the order that they are listed in the object file (top to 1842*0b57cec5SDimitry Andric // bottom), otherwise global objects might not be initialized in the 1843*0b57cec5SDimitry Andric // correct order. 1844*0b57cec5SDimitry Andric void Writer::sortCRTSectionChunks(std::vector<Chunk *> &chunks) { 1845*0b57cec5SDimitry Andric auto sectionChunkOrder = [](const Chunk *a, const Chunk *b) { 1846*0b57cec5SDimitry Andric auto sa = dyn_cast<SectionChunk>(a); 1847*0b57cec5SDimitry Andric auto sb = dyn_cast<SectionChunk>(b); 1848*0b57cec5SDimitry Andric assert(sa && sb && "Non-section chunks in CRT section!"); 1849*0b57cec5SDimitry Andric 1850*0b57cec5SDimitry Andric StringRef sAObj = sa->file->mb.getBufferIdentifier(); 1851*0b57cec5SDimitry Andric StringRef sBObj = sb->file->mb.getBufferIdentifier(); 1852*0b57cec5SDimitry Andric 1853*0b57cec5SDimitry Andric return sAObj == sBObj && sa->getSectionNumber() < sb->getSectionNumber(); 1854*0b57cec5SDimitry Andric }; 1855*0b57cec5SDimitry Andric llvm::stable_sort(chunks, sectionChunkOrder); 1856*0b57cec5SDimitry Andric 1857*0b57cec5SDimitry Andric if (config->verbose) { 1858*0b57cec5SDimitry Andric for (auto &c : chunks) { 1859*0b57cec5SDimitry Andric auto sc = dyn_cast<SectionChunk>(c); 1860*0b57cec5SDimitry Andric log(" " + sc->file->mb.getBufferIdentifier().str() + 1861*0b57cec5SDimitry Andric ", SectionID: " + Twine(sc->getSectionNumber())); 1862*0b57cec5SDimitry Andric } 1863*0b57cec5SDimitry Andric } 1864*0b57cec5SDimitry Andric } 1865*0b57cec5SDimitry Andric 1866*0b57cec5SDimitry Andric OutputSection *Writer::findSection(StringRef name) { 1867*0b57cec5SDimitry Andric for (OutputSection *sec : outputSections) 1868*0b57cec5SDimitry Andric if (sec->name == name) 1869*0b57cec5SDimitry Andric return sec; 1870*0b57cec5SDimitry Andric return nullptr; 1871*0b57cec5SDimitry Andric } 1872*0b57cec5SDimitry Andric 1873*0b57cec5SDimitry Andric uint32_t Writer::getSizeOfInitializedData() { 1874*0b57cec5SDimitry Andric uint32_t res = 0; 1875*0b57cec5SDimitry Andric for (OutputSection *s : outputSections) 1876*0b57cec5SDimitry Andric if (s->header.Characteristics & IMAGE_SCN_CNT_INITIALIZED_DATA) 1877*0b57cec5SDimitry Andric res += s->getRawSize(); 1878*0b57cec5SDimitry Andric return res; 1879*0b57cec5SDimitry Andric } 1880*0b57cec5SDimitry Andric 1881*0b57cec5SDimitry Andric // Add base relocations to .reloc section. 1882*0b57cec5SDimitry Andric void Writer::addBaserels() { 1883*0b57cec5SDimitry Andric if (!config->relocatable) 1884*0b57cec5SDimitry Andric return; 1885*0b57cec5SDimitry Andric relocSec->chunks.clear(); 1886*0b57cec5SDimitry Andric std::vector<Baserel> v; 1887*0b57cec5SDimitry Andric for (OutputSection *sec : outputSections) { 1888*0b57cec5SDimitry Andric if (sec->header.Characteristics & IMAGE_SCN_MEM_DISCARDABLE) 1889*0b57cec5SDimitry Andric continue; 1890*0b57cec5SDimitry Andric // Collect all locations for base relocations. 1891*0b57cec5SDimitry Andric for (Chunk *c : sec->chunks) 1892*0b57cec5SDimitry Andric c->getBaserels(&v); 1893*0b57cec5SDimitry Andric // Add the addresses to .reloc section. 1894*0b57cec5SDimitry Andric if (!v.empty()) 1895*0b57cec5SDimitry Andric addBaserelBlocks(v); 1896*0b57cec5SDimitry Andric v.clear(); 1897*0b57cec5SDimitry Andric } 1898*0b57cec5SDimitry Andric } 1899*0b57cec5SDimitry Andric 1900*0b57cec5SDimitry Andric // Add addresses to .reloc section. Note that addresses are grouped by page. 1901*0b57cec5SDimitry Andric void Writer::addBaserelBlocks(std::vector<Baserel> &v) { 1902*0b57cec5SDimitry Andric const uint32_t mask = ~uint32_t(pageSize - 1); 1903*0b57cec5SDimitry Andric uint32_t page = v[0].rva & mask; 1904*0b57cec5SDimitry Andric size_t i = 0, j = 1; 1905*0b57cec5SDimitry Andric for (size_t e = v.size(); j < e; ++j) { 1906*0b57cec5SDimitry Andric uint32_t p = v[j].rva & mask; 1907*0b57cec5SDimitry Andric if (p == page) 1908*0b57cec5SDimitry Andric continue; 1909*0b57cec5SDimitry Andric relocSec->addChunk(make<BaserelChunk>(page, &v[i], &v[0] + j)); 1910*0b57cec5SDimitry Andric i = j; 1911*0b57cec5SDimitry Andric page = p; 1912*0b57cec5SDimitry Andric } 1913*0b57cec5SDimitry Andric if (i == j) 1914*0b57cec5SDimitry Andric return; 1915*0b57cec5SDimitry Andric relocSec->addChunk(make<BaserelChunk>(page, &v[i], &v[0] + j)); 1916*0b57cec5SDimitry Andric } 1917*0b57cec5SDimitry Andric 1918*0b57cec5SDimitry Andric PartialSection *Writer::createPartialSection(StringRef name, 1919*0b57cec5SDimitry Andric uint32_t outChars) { 1920*0b57cec5SDimitry Andric PartialSection *&pSec = partialSections[{name, outChars}]; 1921*0b57cec5SDimitry Andric if (pSec) 1922*0b57cec5SDimitry Andric return pSec; 1923*0b57cec5SDimitry Andric pSec = make<PartialSection>(name, outChars); 1924*0b57cec5SDimitry Andric return pSec; 1925*0b57cec5SDimitry Andric } 1926*0b57cec5SDimitry Andric 1927*0b57cec5SDimitry Andric PartialSection *Writer::findPartialSection(StringRef name, uint32_t outChars) { 1928*0b57cec5SDimitry Andric auto it = partialSections.find({name, outChars}); 1929*0b57cec5SDimitry Andric if (it != partialSections.end()) 1930*0b57cec5SDimitry Andric return it->second; 1931*0b57cec5SDimitry Andric return nullptr; 1932*0b57cec5SDimitry Andric } 1933