Path: blob/main/contrib/llvm-project/lld/COFF/Writer.cpp
34870 views
//===- Writer.cpp ---------------------------------------------------------===//1//2// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.3// See https://llvm.org/LICENSE.txt for license information.4// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception5//6//===----------------------------------------------------------------------===//78#include "Writer.h"9#include "COFFLinkerContext.h"10#include "CallGraphSort.h"11#include "Config.h"12#include "DLL.h"13#include "InputFiles.h"14#include "LLDMapFile.h"15#include "MapFile.h"16#include "PDB.h"17#include "SymbolTable.h"18#include "Symbols.h"19#include "lld/Common/ErrorHandler.h"20#include "lld/Common/Memory.h"21#include "lld/Common/Timer.h"22#include "llvm/ADT/DenseMap.h"23#include "llvm/ADT/STLExtras.h"24#include "llvm/ADT/StringSet.h"25#include "llvm/BinaryFormat/COFF.h"26#include "llvm/Support/BinaryStreamReader.h"27#include "llvm/Support/Debug.h"28#include "llvm/Support/Endian.h"29#include "llvm/Support/FileOutputBuffer.h"30#include "llvm/Support/Parallel.h"31#include "llvm/Support/Path.h"32#include "llvm/Support/RandomNumberGenerator.h"33#include "llvm/Support/TimeProfiler.h"34#include "llvm/Support/xxhash.h"35#include <algorithm>36#include <cstdio>37#include <map>38#include <memory>39#include <utility>4041using namespace llvm;42using namespace llvm::COFF;43using namespace llvm::object;44using namespace llvm::support;45using namespace llvm::support::endian;46using namespace lld;47using namespace lld::coff;4849/* To re-generate DOSProgram:50$ cat > /tmp/DOSProgram.asm51org 052; Copy cs to ds.53push cs54pop ds55; Point ds:dx at the $-terminated string.56mov dx, str57; Int 21/AH=09h: Write string to standard output.58mov ah, 0x959int 0x2160; Int 21/AH=4Ch: Exit with return code (in AL).61mov ax, 0x4C0162int 0x2163str:64db 'This program cannot be run in DOS mode.$'65align 8, db 066$ nasm -fbin /tmp/DOSProgram.asm -o /tmp/DOSProgram.bin67$ xxd -i /tmp/DOSProgram.bin68*/69static unsigned char dosProgram[] = {700x0e, 0x1f, 0xba, 0x0e, 0x00, 0xb4, 0x09, 0xcd, 0x21, 0xb8, 0x01, 0x4c,710xcd, 0x21, 0x54, 0x68, 0x69, 0x73, 0x20, 0x70, 0x72, 0x6f, 0x67, 0x72,720x61, 0x6d, 0x20, 0x63, 0x61, 0x6e, 0x6e, 0x6f, 0x74, 0x20, 0x62, 0x65,730x20, 0x72, 0x75, 0x6e, 0x20, 0x69, 0x6e, 0x20, 0x44, 0x4f, 0x53, 0x20,740x6d, 0x6f, 0x64, 0x65, 0x2e, 0x24, 0x00, 0x0075};76static_assert(sizeof(dosProgram) % 8 == 0,77"DOSProgram size must be multiple of 8");7879static const int dosStubSize = sizeof(dos_header) + sizeof(dosProgram);80static_assert(dosStubSize % 8 == 0, "DOSStub size must be multiple of 8");8182static const int numberOfDataDirectory = 16;8384namespace {8586class DebugDirectoryChunk : public NonSectionChunk {87public:88DebugDirectoryChunk(const COFFLinkerContext &c,89const std::vector<std::pair<COFF::DebugType, Chunk *>> &r,90bool writeRepro)91: records(r), writeRepro(writeRepro), ctx(c) {}9293size_t getSize() const override {94return (records.size() + int(writeRepro)) * sizeof(debug_directory);95}9697void writeTo(uint8_t *b) const override {98auto *d = reinterpret_cast<debug_directory *>(b);99100for (const std::pair<COFF::DebugType, Chunk *>& record : records) {101Chunk *c = record.second;102const OutputSection *os = ctx.getOutputSection(c);103uint64_t offs = os->getFileOff() + (c->getRVA() - os->getRVA());104fillEntry(d, record.first, c->getSize(), c->getRVA(), offs);105++d;106}107108if (writeRepro) {109// FIXME: The COFF spec allows either a 0-sized entry to just say110// "the timestamp field is really a hash", or a 4-byte size field111// followed by that many bytes containing a longer hash (with the112// lowest 4 bytes usually being the timestamp in little-endian order).113// Consider storing the full 8 bytes computed by xxh3_64bits here.114fillEntry(d, COFF::IMAGE_DEBUG_TYPE_REPRO, 0, 0, 0);115}116}117118void setTimeDateStamp(uint32_t timeDateStamp) {119for (support::ulittle32_t *tds : timeDateStamps)120*tds = timeDateStamp;121}122123private:124void fillEntry(debug_directory *d, COFF::DebugType debugType, size_t size,125uint64_t rva, uint64_t offs) const {126d->Characteristics = 0;127d->TimeDateStamp = 0;128d->MajorVersion = 0;129d->MinorVersion = 0;130d->Type = debugType;131d->SizeOfData = size;132d->AddressOfRawData = rva;133d->PointerToRawData = offs;134135timeDateStamps.push_back(&d->TimeDateStamp);136}137138mutable std::vector<support::ulittle32_t *> timeDateStamps;139const std::vector<std::pair<COFF::DebugType, Chunk *>> &records;140bool writeRepro;141const COFFLinkerContext &ctx;142};143144class CVDebugRecordChunk : public NonSectionChunk {145public:146CVDebugRecordChunk(const COFFLinkerContext &c) : ctx(c) {}147148size_t getSize() const override {149return sizeof(codeview::DebugInfo) + ctx.config.pdbAltPath.size() + 1;150}151152void writeTo(uint8_t *b) const override {153// Save off the DebugInfo entry to backfill the file signature (build id)154// in Writer::writeBuildId155buildId = reinterpret_cast<codeview::DebugInfo *>(b);156157// variable sized field (PDB Path)158char *p = reinterpret_cast<char *>(b + sizeof(*buildId));159if (!ctx.config.pdbAltPath.empty())160memcpy(p, ctx.config.pdbAltPath.data(), ctx.config.pdbAltPath.size());161p[ctx.config.pdbAltPath.size()] = '\0';162}163164mutable codeview::DebugInfo *buildId = nullptr;165166private:167const COFFLinkerContext &ctx;168};169170class ExtendedDllCharacteristicsChunk : public NonSectionChunk {171public:172ExtendedDllCharacteristicsChunk(uint32_t c) : characteristics(c) {}173174size_t getSize() const override { return 4; }175176void writeTo(uint8_t *buf) const override { write32le(buf, characteristics); }177178uint32_t characteristics = 0;179};180181// PartialSection represents a group of chunks that contribute to an182// OutputSection. Collating a collection of PartialSections of same name and183// characteristics constitutes the OutputSection.184class PartialSectionKey {185public:186StringRef name;187unsigned characteristics;188189bool operator<(const PartialSectionKey &other) const {190int c = name.compare(other.name);191if (c > 0)192return false;193if (c == 0)194return characteristics < other.characteristics;195return true;196}197};198199struct ChunkRange {200Chunk *first = nullptr, *last;201};202203// The writer writes a SymbolTable result to a file.204class Writer {205public:206Writer(COFFLinkerContext &c)207: buffer(errorHandler().outputBuffer), delayIdata(c), edata(c), ctx(c) {}208void run();209210private:211void createSections();212void createMiscChunks();213void createImportTables();214void appendImportThunks();215void locateImportTables();216void createExportTable();217void mergeSections();218void sortECChunks();219void removeUnusedSections();220void assignAddresses();221bool isInRange(uint16_t relType, uint64_t s, uint64_t p, int margin);222std::pair<Defined *, bool> getThunk(DenseMap<uint64_t, Defined *> &lastThunks,223Defined *target, uint64_t p,224uint16_t type, int margin);225bool createThunks(OutputSection *os, int margin);226bool verifyRanges(const std::vector<Chunk *> chunks);227void createECCodeMap();228void finalizeAddresses();229void removeEmptySections();230void assignOutputSectionIndices();231void createSymbolAndStringTable();232void openFile(StringRef outputPath);233template <typename PEHeaderTy> void writeHeader();234void createSEHTable();235void createRuntimePseudoRelocs();236void createECChunks();237void insertCtorDtorSymbols();238void markSymbolsWithRelocations(ObjFile *file, SymbolRVASet &usedSymbols);239void createGuardCFTables();240void markSymbolsForRVATable(ObjFile *file,241ArrayRef<SectionChunk *> symIdxChunks,242SymbolRVASet &tableSymbols);243void getSymbolsFromSections(ObjFile *file,244ArrayRef<SectionChunk *> symIdxChunks,245std::vector<Symbol *> &symbols);246void maybeAddRVATable(SymbolRVASet tableSymbols, StringRef tableSym,247StringRef countSym, bool hasFlag=false);248void setSectionPermissions();249void setECSymbols();250void writeSections();251void writeBuildId();252void writePEChecksum();253void sortSections();254template <typename T> void sortExceptionTable(ChunkRange &exceptionTable);255void sortExceptionTables();256void sortCRTSectionChunks(std::vector<Chunk *> &chunks);257void addSyntheticIdata();258void sortBySectionOrder(std::vector<Chunk *> &chunks);259void fixPartialSectionChars(StringRef name, uint32_t chars);260bool fixGnuImportChunks();261void fixTlsAlignment();262PartialSection *createPartialSection(StringRef name, uint32_t outChars);263PartialSection *findPartialSection(StringRef name, uint32_t outChars);264265std::optional<coff_symbol16> createSymbol(Defined *d);266size_t addEntryToStringTable(StringRef str);267268OutputSection *findSection(StringRef name);269void addBaserels();270void addBaserelBlocks(std::vector<Baserel> &v);271272uint32_t getSizeOfInitializedData();273274void prepareLoadConfig();275template <typename T> void prepareLoadConfig(T *loadConfig);276template <typename T> void checkLoadConfigGuardData(const T *loadConfig);277278std::unique_ptr<FileOutputBuffer> &buffer;279std::map<PartialSectionKey, PartialSection *> partialSections;280std::vector<char> strtab;281std::vector<llvm::object::coff_symbol16> outputSymtab;282std::vector<ECCodeMapEntry> codeMap;283IdataContents idata;284Chunk *importTableStart = nullptr;285uint64_t importTableSize = 0;286Chunk *edataStart = nullptr;287Chunk *edataEnd = nullptr;288Chunk *iatStart = nullptr;289uint64_t iatSize = 0;290DelayLoadContents delayIdata;291EdataContents edata;292bool setNoSEHCharacteristic = false;293uint32_t tlsAlignment = 0;294295DebugDirectoryChunk *debugDirectory = nullptr;296std::vector<std::pair<COFF::DebugType, Chunk *>> debugRecords;297CVDebugRecordChunk *buildId = nullptr;298ArrayRef<uint8_t> sectionTable;299300uint64_t fileSize;301uint32_t pointerToSymbolTable = 0;302uint64_t sizeOfImage;303uint64_t sizeOfHeaders;304305OutputSection *textSec;306OutputSection *rdataSec;307OutputSection *buildidSec;308OutputSection *dataSec;309OutputSection *pdataSec;310OutputSection *idataSec;311OutputSection *edataSec;312OutputSection *didatSec;313OutputSection *rsrcSec;314OutputSection *relocSec;315OutputSection *ctorsSec;316OutputSection *dtorsSec;317// Either .rdata section or .buildid section.318OutputSection *debugInfoSec;319320// The range of .pdata sections in the output file.321//322// We need to keep track of the location of .pdata in whichever section it323// gets merged into so that we can sort its contents and emit a correct data324// directory entry for the exception table. This is also the case for some325// other sections (such as .edata) but because the contents of those sections326// are entirely linker-generated we can keep track of their locations using327// the chunks that the linker creates. All .pdata chunks come from input328// files, so we need to keep track of them separately.329ChunkRange pdata;330331// x86_64 .pdata sections on ARM64EC/ARM64X targets.332ChunkRange hybridPdata;333334COFFLinkerContext &ctx;335};336} // anonymous namespace337338void lld::coff::writeResult(COFFLinkerContext &ctx) {339llvm::TimeTraceScope timeScope("Write output(s)");340Writer(ctx).run();341}342343void OutputSection::addChunk(Chunk *c) {344chunks.push_back(c);345}346347void OutputSection::insertChunkAtStart(Chunk *c) {348chunks.insert(chunks.begin(), c);349}350351void OutputSection::setPermissions(uint32_t c) {352header.Characteristics &= ~permMask;353header.Characteristics |= c;354}355356void OutputSection::merge(OutputSection *other) {357chunks.insert(chunks.end(), other->chunks.begin(), other->chunks.end());358other->chunks.clear();359contribSections.insert(contribSections.end(), other->contribSections.begin(),360other->contribSections.end());361other->contribSections.clear();362363// MS link.exe compatibility: when merging a code section into a data section,364// mark the target section as a code section.365if (other->header.Characteristics & IMAGE_SCN_CNT_CODE) {366header.Characteristics |= IMAGE_SCN_CNT_CODE;367header.Characteristics &=368~(IMAGE_SCN_CNT_INITIALIZED_DATA | IMAGE_SCN_CNT_UNINITIALIZED_DATA);369}370}371372// Write the section header to a given buffer.373void OutputSection::writeHeaderTo(uint8_t *buf, bool isDebug) {374auto *hdr = reinterpret_cast<coff_section *>(buf);375*hdr = header;376if (stringTableOff) {377// If name is too long, write offset into the string table as a name.378encodeSectionName(hdr->Name, stringTableOff);379} else {380assert(!isDebug || name.size() <= COFF::NameSize ||381(hdr->Characteristics & IMAGE_SCN_MEM_DISCARDABLE) == 0);382strncpy(hdr->Name, name.data(),383std::min(name.size(), (size_t)COFF::NameSize));384}385}386387void OutputSection::addContributingPartialSection(PartialSection *sec) {388contribSections.push_back(sec);389}390391// Check whether the target address S is in range from a relocation392// of type relType at address P.393bool Writer::isInRange(uint16_t relType, uint64_t s, uint64_t p, int margin) {394if (ctx.config.machine == ARMNT) {395int64_t diff = AbsoluteDifference(s, p + 4) + margin;396switch (relType) {397case IMAGE_REL_ARM_BRANCH20T:398return isInt<21>(diff);399case IMAGE_REL_ARM_BRANCH24T:400case IMAGE_REL_ARM_BLX23T:401return isInt<25>(diff);402default:403return true;404}405} else if (ctx.config.machine == ARM64) {406int64_t diff = AbsoluteDifference(s, p) + margin;407switch (relType) {408case IMAGE_REL_ARM64_BRANCH26:409return isInt<28>(diff);410case IMAGE_REL_ARM64_BRANCH19:411return isInt<21>(diff);412case IMAGE_REL_ARM64_BRANCH14:413return isInt<16>(diff);414default:415return true;416}417} else {418llvm_unreachable("Unexpected architecture");419}420}421422// Return the last thunk for the given target if it is in range,423// or create a new one.424std::pair<Defined *, bool>425Writer::getThunk(DenseMap<uint64_t, Defined *> &lastThunks, Defined *target,426uint64_t p, uint16_t type, int margin) {427Defined *&lastThunk = lastThunks[target->getRVA()];428if (lastThunk && isInRange(type, lastThunk->getRVA(), p, margin))429return {lastThunk, false};430Chunk *c;431switch (ctx.config.machine) {432case ARMNT:433c = make<RangeExtensionThunkARM>(ctx, target);434break;435case ARM64:436c = make<RangeExtensionThunkARM64>(ctx, target);437break;438default:439llvm_unreachable("Unexpected architecture");440}441Defined *d = make<DefinedSynthetic>("range_extension_thunk", c);442lastThunk = d;443return {d, true};444}445446// This checks all relocations, and for any relocation which isn't in range447// it adds a thunk after the section chunk that contains the relocation.448// If the latest thunk for the specific target is in range, that is used449// instead of creating a new thunk. All range checks are done with the450// specified margin, to make sure that relocations that originally are in451// range, but only barely, also get thunks - in case other added thunks makes452// the target go out of range.453//454// After adding thunks, we verify that all relocations are in range (with455// no extra margin requirements). If this failed, we restart (throwing away456// the previously created thunks) and retry with a wider margin.457bool Writer::createThunks(OutputSection *os, int margin) {458bool addressesChanged = false;459DenseMap<uint64_t, Defined *> lastThunks;460DenseMap<std::pair<ObjFile *, Defined *>, uint32_t> thunkSymtabIndices;461size_t thunksSize = 0;462// Recheck Chunks.size() each iteration, since we can insert more463// elements into it.464for (size_t i = 0; i != os->chunks.size(); ++i) {465SectionChunk *sc = dyn_cast_or_null<SectionChunk>(os->chunks[i]);466if (!sc)467continue;468size_t thunkInsertionSpot = i + 1;469470// Try to get a good enough estimate of where new thunks will be placed.471// Offset this by the size of the new thunks added so far, to make the472// estimate slightly better.473size_t thunkInsertionRVA = sc->getRVA() + sc->getSize() + thunksSize;474ObjFile *file = sc->file;475std::vector<std::pair<uint32_t, uint32_t>> relocReplacements;476ArrayRef<coff_relocation> originalRelocs =477file->getCOFFObj()->getRelocations(sc->header);478for (size_t j = 0, e = originalRelocs.size(); j < e; ++j) {479const coff_relocation &rel = originalRelocs[j];480Symbol *relocTarget = file->getSymbol(rel.SymbolTableIndex);481482// The estimate of the source address P should be pretty accurate,483// but we don't know whether the target Symbol address should be484// offset by thunksSize or not (or by some of thunksSize but not all of485// it), giving us some uncertainty once we have added one thunk.486uint64_t p = sc->getRVA() + rel.VirtualAddress + thunksSize;487488Defined *sym = dyn_cast_or_null<Defined>(relocTarget);489if (!sym)490continue;491492uint64_t s = sym->getRVA();493494if (isInRange(rel.Type, s, p, margin))495continue;496497// If the target isn't in range, hook it up to an existing or new thunk.498auto [thunk, wasNew] = getThunk(lastThunks, sym, p, rel.Type, margin);499if (wasNew) {500Chunk *thunkChunk = thunk->getChunk();501thunkChunk->setRVA(502thunkInsertionRVA); // Estimate of where it will be located.503os->chunks.insert(os->chunks.begin() + thunkInsertionSpot, thunkChunk);504thunkInsertionSpot++;505thunksSize += thunkChunk->getSize();506thunkInsertionRVA += thunkChunk->getSize();507addressesChanged = true;508}509510// To redirect the relocation, add a symbol to the parent object file's511// symbol table, and replace the relocation symbol table index with the512// new index.513auto insertion = thunkSymtabIndices.insert({{file, thunk}, ~0U});514uint32_t &thunkSymbolIndex = insertion.first->second;515if (insertion.second)516thunkSymbolIndex = file->addRangeThunkSymbol(thunk);517relocReplacements.emplace_back(j, thunkSymbolIndex);518}519520// Get a writable copy of this section's relocations so they can be521// modified. If the relocations point into the object file, allocate new522// memory. Otherwise, this must be previously allocated memory that can be523// modified in place.524ArrayRef<coff_relocation> curRelocs = sc->getRelocs();525MutableArrayRef<coff_relocation> newRelocs;526if (originalRelocs.data() == curRelocs.data()) {527newRelocs = MutableArrayRef(528bAlloc().Allocate<coff_relocation>(originalRelocs.size()),529originalRelocs.size());530} else {531newRelocs = MutableArrayRef(532const_cast<coff_relocation *>(curRelocs.data()), curRelocs.size());533}534535// Copy each relocation, but replace the symbol table indices which need536// thunks.537auto nextReplacement = relocReplacements.begin();538auto endReplacement = relocReplacements.end();539for (size_t i = 0, e = originalRelocs.size(); i != e; ++i) {540newRelocs[i] = originalRelocs[i];541if (nextReplacement != endReplacement && nextReplacement->first == i) {542newRelocs[i].SymbolTableIndex = nextReplacement->second;543++nextReplacement;544}545}546547sc->setRelocs(newRelocs);548}549return addressesChanged;550}551552// Create a code map for CHPE metadata.553void Writer::createECCodeMap() {554if (!isArm64EC(ctx.config.machine))555return;556557// Clear the map in case we were're recomputing the map after adding558// a range extension thunk.559codeMap.clear();560561std::optional<chpe_range_type> lastType;562Chunk *first, *last;563564auto closeRange = [&]() {565if (lastType) {566codeMap.push_back({first, last, *lastType});567lastType.reset();568}569};570571for (OutputSection *sec : ctx.outputSections) {572for (Chunk *c : sec->chunks) {573// Skip empty section chunks. MS link.exe does not seem to do that and574// generates empty code ranges in some cases.575if (isa<SectionChunk>(c) && !c->getSize())576continue;577578std::optional<chpe_range_type> chunkType = c->getArm64ECRangeType();579if (chunkType != lastType) {580closeRange();581first = c;582lastType = chunkType;583}584last = c;585}586}587588closeRange();589590Symbol *tableCountSym = ctx.symtab.findUnderscore("__hybrid_code_map_count");591cast<DefinedAbsolute>(tableCountSym)->setVA(codeMap.size());592}593594// Verify that all relocations are in range, with no extra margin requirements.595bool Writer::verifyRanges(const std::vector<Chunk *> chunks) {596for (Chunk *c : chunks) {597SectionChunk *sc = dyn_cast_or_null<SectionChunk>(c);598if (!sc)599continue;600601ArrayRef<coff_relocation> relocs = sc->getRelocs();602for (const coff_relocation &rel : relocs) {603Symbol *relocTarget = sc->file->getSymbol(rel.SymbolTableIndex);604605Defined *sym = dyn_cast_or_null<Defined>(relocTarget);606if (!sym)607continue;608609uint64_t p = sc->getRVA() + rel.VirtualAddress;610uint64_t s = sym->getRVA();611612if (!isInRange(rel.Type, s, p, 0))613return false;614}615}616return true;617}618619// Assign addresses and add thunks if necessary.620void Writer::finalizeAddresses() {621assignAddresses();622if (ctx.config.machine != ARMNT && ctx.config.machine != ARM64)623return;624625size_t origNumChunks = 0;626for (OutputSection *sec : ctx.outputSections) {627sec->origChunks = sec->chunks;628origNumChunks += sec->chunks.size();629}630631int pass = 0;632int margin = 1024 * 100;633while (true) {634llvm::TimeTraceScope timeScope2("Add thunks pass");635636// First check whether we need thunks at all, or if the previous pass of637// adding them turned out ok.638bool rangesOk = true;639size_t numChunks = 0;640{641llvm::TimeTraceScope timeScope3("Verify ranges");642for (OutputSection *sec : ctx.outputSections) {643if (!verifyRanges(sec->chunks)) {644rangesOk = false;645break;646}647numChunks += sec->chunks.size();648}649}650if (rangesOk) {651if (pass > 0)652log("Added " + Twine(numChunks - origNumChunks) + " thunks with " +653"margin " + Twine(margin) + " in " + Twine(pass) + " passes");654return;655}656657if (pass >= 10)658fatal("adding thunks hasn't converged after " + Twine(pass) + " passes");659660if (pass > 0) {661// If the previous pass didn't work out, reset everything back to the662// original conditions before retrying with a wider margin. This should663// ideally never happen under real circumstances.664for (OutputSection *sec : ctx.outputSections)665sec->chunks = sec->origChunks;666margin *= 2;667}668669// Try adding thunks everywhere where it is needed, with a margin670// to avoid things going out of range due to the added thunks.671bool addressesChanged = false;672{673llvm::TimeTraceScope timeScope3("Create thunks");674for (OutputSection *sec : ctx.outputSections)675addressesChanged |= createThunks(sec, margin);676}677// If the verification above thought we needed thunks, we should have678// added some.679assert(addressesChanged);680(void)addressesChanged;681682// Recalculate the layout for the whole image (and verify the ranges at683// the start of the next round).684assignAddresses();685686pass++;687}688}689690void Writer::writePEChecksum() {691if (!ctx.config.writeCheckSum) {692return;693}694695llvm::TimeTraceScope timeScope("PE checksum");696697// https://docs.microsoft.com/en-us/windows/win32/debug/pe-format#checksum698uint32_t *buf = (uint32_t *)buffer->getBufferStart();699uint32_t size = (uint32_t)(buffer->getBufferSize());700701coff_file_header *coffHeader =702(coff_file_header *)((uint8_t *)buf + dosStubSize + sizeof(PEMagic));703pe32_header *peHeader =704(pe32_header *)((uint8_t *)coffHeader + sizeof(coff_file_header));705706uint64_t sum = 0;707uint32_t count = size;708ulittle16_t *addr = (ulittle16_t *)buf;709710// The PE checksum algorithm, implemented as suggested in RFC1071711while (count > 1) {712sum += *addr++;713count -= 2;714}715716// Add left-over byte, if any717if (count > 0)718sum += *(unsigned char *)addr;719720// Fold 32-bit sum to 16 bits721while (sum >> 16) {722sum = (sum & 0xffff) + (sum >> 16);723}724725sum += size;726peHeader->CheckSum = sum;727}728729// The main function of the writer.730void Writer::run() {731{732llvm::TimeTraceScope timeScope("Write PE");733ScopedTimer t1(ctx.codeLayoutTimer);734735createImportTables();736createSections();737appendImportThunks();738// Import thunks must be added before the Control Flow Guard tables are739// added.740createMiscChunks();741createExportTable();742mergeSections();743sortECChunks();744removeUnusedSections();745finalizeAddresses();746removeEmptySections();747assignOutputSectionIndices();748setSectionPermissions();749setECSymbols();750createSymbolAndStringTable();751752if (fileSize > UINT32_MAX)753fatal("image size (" + Twine(fileSize) + ") " +754"exceeds maximum allowable size (" + Twine(UINT32_MAX) + ")");755756openFile(ctx.config.outputFile);757if (ctx.config.is64()) {758writeHeader<pe32plus_header>();759} else {760writeHeader<pe32_header>();761}762writeSections();763prepareLoadConfig();764sortExceptionTables();765766// Fix up the alignment in the TLS Directory's characteristic field,767// if a specific alignment value is needed768if (tlsAlignment)769fixTlsAlignment();770}771772if (!ctx.config.pdbPath.empty() && ctx.config.debug) {773assert(buildId);774createPDB(ctx, sectionTable, buildId->buildId);775}776writeBuildId();777778writeLLDMapFile(ctx);779writeMapFile(ctx);780781writePEChecksum();782783if (errorCount())784return;785786llvm::TimeTraceScope timeScope("Commit PE to disk");787ScopedTimer t2(ctx.outputCommitTimer);788if (auto e = buffer->commit())789fatal("failed to write output '" + buffer->getPath() +790"': " + toString(std::move(e)));791}792793static StringRef getOutputSectionName(StringRef name) {794StringRef s = name.split('$').first;795796// Treat a later period as a separator for MinGW, for sections like797// ".ctors.01234".798return s.substr(0, s.find('.', 1));799}800801// For /order.802void Writer::sortBySectionOrder(std::vector<Chunk *> &chunks) {803auto getPriority = [&ctx = ctx](const Chunk *c) {804if (auto *sec = dyn_cast<SectionChunk>(c))805if (sec->sym)806return ctx.config.order.lookup(sec->sym->getName());807return 0;808};809810llvm::stable_sort(chunks, [=](const Chunk *a, const Chunk *b) {811return getPriority(a) < getPriority(b);812});813}814815// Change the characteristics of existing PartialSections that belong to the816// section Name to Chars.817void Writer::fixPartialSectionChars(StringRef name, uint32_t chars) {818for (auto it : partialSections) {819PartialSection *pSec = it.second;820StringRef curName = pSec->name;821if (!curName.consume_front(name) ||822(!curName.empty() && !curName.starts_with("$")))823continue;824if (pSec->characteristics == chars)825continue;826PartialSection *destSec = createPartialSection(pSec->name, chars);827destSec->chunks.insert(destSec->chunks.end(), pSec->chunks.begin(),828pSec->chunks.end());829pSec->chunks.clear();830}831}832833// Sort concrete section chunks from GNU import libraries.834//835// GNU binutils doesn't use short import files, but instead produces import836// libraries that consist of object files, with section chunks for the .idata$*837// sections. These are linked just as regular static libraries. Each import838// library consists of one header object, one object file for every imported839// symbol, and one trailer object. In order for the .idata tables/lists to840// be formed correctly, the section chunks within each .idata$* section need841// to be grouped by library, and sorted alphabetically within each library842// (which makes sure the header comes first and the trailer last).843bool Writer::fixGnuImportChunks() {844uint32_t rdata = IMAGE_SCN_CNT_INITIALIZED_DATA | IMAGE_SCN_MEM_READ;845846// Make sure all .idata$* section chunks are mapped as RDATA in order to847// be sorted into the same sections as our own synthesized .idata chunks.848fixPartialSectionChars(".idata", rdata);849850bool hasIdata = false;851// Sort all .idata$* chunks, grouping chunks from the same library,852// with alphabetical ordering of the object files within a library.853for (auto it : partialSections) {854PartialSection *pSec = it.second;855if (!pSec->name.starts_with(".idata"))856continue;857858if (!pSec->chunks.empty())859hasIdata = true;860llvm::stable_sort(pSec->chunks, [&](Chunk *s, Chunk *t) {861SectionChunk *sc1 = dyn_cast_or_null<SectionChunk>(s);862SectionChunk *sc2 = dyn_cast_or_null<SectionChunk>(t);863if (!sc1 || !sc2) {864// if SC1, order them ascending. If SC2 or both null,865// S is not less than T.866return sc1 != nullptr;867}868// Make a string with "libraryname/objectfile" for sorting, achieving869// both grouping by library and sorting of objects within a library,870// at once.871std::string key1 =872(sc1->file->parentName + "/" + sc1->file->getName()).str();873std::string key2 =874(sc2->file->parentName + "/" + sc2->file->getName()).str();875return key1 < key2;876});877}878return hasIdata;879}880881// Add generated idata chunks, for imported symbols and DLLs, and a882// terminator in .idata$2.883void Writer::addSyntheticIdata() {884uint32_t rdata = IMAGE_SCN_CNT_INITIALIZED_DATA | IMAGE_SCN_MEM_READ;885idata.create(ctx);886887// Add the .idata content in the right section groups, to allow888// chunks from other linked in object files to be grouped together.889// See Microsoft PE/COFF spec 5.4 for details.890auto add = [&](StringRef n, std::vector<Chunk *> &v) {891PartialSection *pSec = createPartialSection(n, rdata);892pSec->chunks.insert(pSec->chunks.end(), v.begin(), v.end());893};894895// The loader assumes a specific order of data.896// Add each type in the correct order.897add(".idata$2", idata.dirs);898add(".idata$4", idata.lookups);899add(".idata$5", idata.addresses);900if (!idata.hints.empty())901add(".idata$6", idata.hints);902add(".idata$7", idata.dllNames);903}904905// Locate the first Chunk and size of the import directory list and the906// IAT.907void Writer::locateImportTables() {908uint32_t rdata = IMAGE_SCN_CNT_INITIALIZED_DATA | IMAGE_SCN_MEM_READ;909910if (PartialSection *importDirs = findPartialSection(".idata$2", rdata)) {911if (!importDirs->chunks.empty())912importTableStart = importDirs->chunks.front();913for (Chunk *c : importDirs->chunks)914importTableSize += c->getSize();915}916917if (PartialSection *importAddresses = findPartialSection(".idata$5", rdata)) {918if (!importAddresses->chunks.empty())919iatStart = importAddresses->chunks.front();920for (Chunk *c : importAddresses->chunks)921iatSize += c->getSize();922}923}924925// Return whether a SectionChunk's suffix (the dollar and any trailing926// suffix) should be removed and sorted into the main suffixless927// PartialSection.928static bool shouldStripSectionSuffix(SectionChunk *sc, StringRef name,929bool isMinGW) {930// On MinGW, comdat groups are formed by putting the comdat group name931// after the '$' in the section name. For .eh_frame$<symbol>, that must932// still be sorted before the .eh_frame trailer from crtend.o, thus just933// strip the section name trailer. For other sections, such as934// .tls$$<symbol> (where non-comdat .tls symbols are otherwise stored in935// ".tls$"), they must be strictly sorted after .tls. And for the936// hypothetical case of comdat .CRT$XCU, we definitely need to keep the937// suffix for sorting. Thus, to play it safe, only strip the suffix for938// the standard sections.939if (!isMinGW)940return false;941if (!sc || !sc->isCOMDAT())942return false;943return name.starts_with(".text$") || name.starts_with(".data$") ||944name.starts_with(".rdata$") || name.starts_with(".pdata$") ||945name.starts_with(".xdata$") || name.starts_with(".eh_frame$");946}947948void Writer::sortSections() {949if (!ctx.config.callGraphProfile.empty()) {950DenseMap<const SectionChunk *, int> order =951computeCallGraphProfileOrder(ctx);952for (auto it : order) {953if (DefinedRegular *sym = it.first->sym)954ctx.config.order[sym->getName()] = it.second;955}956}957if (!ctx.config.order.empty())958for (auto it : partialSections)959sortBySectionOrder(it.second->chunks);960}961962// Create output section objects and add them to OutputSections.963void Writer::createSections() {964llvm::TimeTraceScope timeScope("Output sections");965// First, create the builtin sections.966const uint32_t data = IMAGE_SCN_CNT_INITIALIZED_DATA;967const uint32_t bss = IMAGE_SCN_CNT_UNINITIALIZED_DATA;968const uint32_t code = IMAGE_SCN_CNT_CODE;969const uint32_t discardable = IMAGE_SCN_MEM_DISCARDABLE;970const uint32_t r = IMAGE_SCN_MEM_READ;971const uint32_t w = IMAGE_SCN_MEM_WRITE;972const uint32_t x = IMAGE_SCN_MEM_EXECUTE;973974SmallDenseMap<std::pair<StringRef, uint32_t>, OutputSection *> sections;975auto createSection = [&](StringRef name, uint32_t outChars) {976OutputSection *&sec = sections[{name, outChars}];977if (!sec) {978sec = make<OutputSection>(name, outChars);979ctx.outputSections.push_back(sec);980}981return sec;982};983984// Try to match the section order used by link.exe.985textSec = createSection(".text", code | r | x);986createSection(".bss", bss | r | w);987rdataSec = createSection(".rdata", data | r);988buildidSec = createSection(".buildid", data | r);989dataSec = createSection(".data", data | r | w);990pdataSec = createSection(".pdata", data | r);991idataSec = createSection(".idata", data | r);992edataSec = createSection(".edata", data | r);993didatSec = createSection(".didat", data | r);994rsrcSec = createSection(".rsrc", data | r);995relocSec = createSection(".reloc", data | discardable | r);996ctorsSec = createSection(".ctors", data | r | w);997dtorsSec = createSection(".dtors", data | r | w);998999// Then bin chunks by name and output characteristics.1000for (Chunk *c : ctx.symtab.getChunks()) {1001auto *sc = dyn_cast<SectionChunk>(c);1002if (sc && !sc->live) {1003if (ctx.config.verbose)1004sc->printDiscardedMessage();1005continue;1006}1007StringRef name = c->getSectionName();1008if (shouldStripSectionSuffix(sc, name, ctx.config.mingw))1009name = name.split('$').first;10101011if (name.starts_with(".tls"))1012tlsAlignment = std::max(tlsAlignment, c->getAlignment());10131014PartialSection *pSec = createPartialSection(name,1015c->getOutputCharacteristics());1016pSec->chunks.push_back(c);1017}10181019fixPartialSectionChars(".rsrc", data | r);1020fixPartialSectionChars(".edata", data | r);1021// Even in non MinGW cases, we might need to link against GNU import1022// libraries.1023bool hasIdata = fixGnuImportChunks();1024if (!idata.empty())1025hasIdata = true;10261027if (hasIdata)1028addSyntheticIdata();10291030sortSections();10311032if (hasIdata)1033locateImportTables();10341035// Then create an OutputSection for each section.1036// '$' and all following characters in input section names are1037// discarded when determining output section. So, .text$foo1038// contributes to .text, for example. See PE/COFF spec 3.2.1039for (auto it : partialSections) {1040PartialSection *pSec = it.second;1041StringRef name = getOutputSectionName(pSec->name);1042uint32_t outChars = pSec->characteristics;10431044if (name == ".CRT") {1045// In link.exe, there is a special case for the I386 target where .CRT1046// sections are treated as if they have output characteristics DATA | R if1047// their characteristics are DATA | R | W. This implements the same1048// special case for all architectures.1049outChars = data | r;10501051log("Processing section " + pSec->name + " -> " + name);10521053sortCRTSectionChunks(pSec->chunks);1054}10551056OutputSection *sec = createSection(name, outChars);1057for (Chunk *c : pSec->chunks)1058sec->addChunk(c);10591060sec->addContributingPartialSection(pSec);1061}10621063// Finally, move some output sections to the end.1064auto sectionOrder = [&](const OutputSection *s) {1065// Move DISCARDABLE (or non-memory-mapped) sections to the end of file1066// because the loader cannot handle holes. Stripping can remove other1067// discardable ones than .reloc, which is first of them (created early).1068if (s->header.Characteristics & IMAGE_SCN_MEM_DISCARDABLE) {1069// Move discardable sections named .debug_ to the end, after other1070// discardable sections. Stripping only removes the sections named1071// .debug_* - thus try to avoid leaving holes after stripping.1072if (s->name.starts_with(".debug_"))1073return 3;1074return 2;1075}1076// .rsrc should come at the end of the non-discardable sections because its1077// size may change by the Win32 UpdateResources() function, causing1078// subsequent sections to move (see https://crbug.com/827082).1079if (s == rsrcSec)1080return 1;1081return 0;1082};1083llvm::stable_sort(ctx.outputSections,1084[&](const OutputSection *s, const OutputSection *t) {1085return sectionOrder(s) < sectionOrder(t);1086});1087}10881089void Writer::createMiscChunks() {1090llvm::TimeTraceScope timeScope("Misc chunks");1091Configuration *config = &ctx.config;10921093for (MergeChunk *p : ctx.mergeChunkInstances) {1094if (p) {1095p->finalizeContents();1096rdataSec->addChunk(p);1097}1098}10991100// Create thunks for locally-dllimported symbols.1101if (!ctx.symtab.localImportChunks.empty()) {1102for (Chunk *c : ctx.symtab.localImportChunks)1103rdataSec->addChunk(c);1104}11051106// Create Debug Information Chunks1107debugInfoSec = config->mingw ? buildidSec : rdataSec;1108if (config->buildIDHash != BuildIDHash::None || config->debug ||1109config->repro || config->cetCompat) {1110debugDirectory =1111make<DebugDirectoryChunk>(ctx, debugRecords, config->repro);1112debugDirectory->setAlignment(4);1113debugInfoSec->addChunk(debugDirectory);1114}11151116if (config->debug || config->buildIDHash != BuildIDHash::None) {1117// Make a CVDebugRecordChunk even when /DEBUG:CV is not specified. We1118// output a PDB no matter what, and this chunk provides the only means of1119// allowing a debugger to match a PDB and an executable. So we need it even1120// if we're ultimately not going to write CodeView data to the PDB.1121buildId = make<CVDebugRecordChunk>(ctx);1122debugRecords.emplace_back(COFF::IMAGE_DEBUG_TYPE_CODEVIEW, buildId);1123if (Symbol *buildidSym = ctx.symtab.findUnderscore("__buildid"))1124replaceSymbol<DefinedSynthetic>(buildidSym, buildidSym->getName(),1125buildId, 4);1126}11271128if (config->cetCompat) {1129debugRecords.emplace_back(COFF::IMAGE_DEBUG_TYPE_EX_DLLCHARACTERISTICS,1130make<ExtendedDllCharacteristicsChunk>(1131IMAGE_DLL_CHARACTERISTICS_EX_CET_COMPAT));1132}11331134// Align and add each chunk referenced by the debug data directory.1135for (std::pair<COFF::DebugType, Chunk *> r : debugRecords) {1136r.second->setAlignment(4);1137debugInfoSec->addChunk(r.second);1138}11391140// Create SEH table. x86-only.1141if (config->safeSEH)1142createSEHTable();11431144// Create /guard:cf tables if requested.1145if (config->guardCF != GuardCFLevel::Off)1146createGuardCFTables();11471148if (isArm64EC(config->machine))1149createECChunks();11501151if (config->autoImport)1152createRuntimePseudoRelocs();11531154if (config->mingw)1155insertCtorDtorSymbols();1156}11571158// Create .idata section for the DLL-imported symbol table.1159// The format of this section is inherently Windows-specific.1160// IdataContents class abstracted away the details for us,1161// so we just let it create chunks and add them to the section.1162void Writer::createImportTables() {1163llvm::TimeTraceScope timeScope("Import tables");1164// Initialize DLLOrder so that import entries are ordered in1165// the same order as in the command line. (That affects DLL1166// initialization order, and this ordering is MSVC-compatible.)1167for (ImportFile *file : ctx.importFileInstances) {1168if (!file->live)1169continue;11701171std::string dll = StringRef(file->dllName).lower();1172if (ctx.config.dllOrder.count(dll) == 0)1173ctx.config.dllOrder[dll] = ctx.config.dllOrder.size();11741175if (file->impSym && !isa<DefinedImportData>(file->impSym))1176fatal(toString(ctx, *file->impSym) + " was replaced");1177DefinedImportData *impSym = cast_or_null<DefinedImportData>(file->impSym);1178if (ctx.config.delayLoads.count(StringRef(file->dllName).lower())) {1179if (!file->thunkSym)1180fatal("cannot delay-load " + toString(file) +1181" due to import of data: " + toString(ctx, *impSym));1182delayIdata.add(impSym);1183} else {1184idata.add(impSym);1185}1186}1187}11881189void Writer::appendImportThunks() {1190if (ctx.importFileInstances.empty())1191return;11921193llvm::TimeTraceScope timeScope("Import thunks");1194for (ImportFile *file : ctx.importFileInstances) {1195if (!file->live)1196continue;11971198if (!file->thunkSym)1199continue;12001201if (!isa<DefinedImportThunk>(file->thunkSym))1202fatal(toString(ctx, *file->thunkSym) + " was replaced");1203DefinedImportThunk *thunk = cast<DefinedImportThunk>(file->thunkSym);1204if (file->thunkLive)1205textSec->addChunk(thunk->getChunk());1206}12071208if (!delayIdata.empty()) {1209Defined *helper = cast<Defined>(ctx.config.delayLoadHelper);1210delayIdata.create(helper);1211for (Chunk *c : delayIdata.getChunks())1212didatSec->addChunk(c);1213for (Chunk *c : delayIdata.getDataChunks())1214dataSec->addChunk(c);1215for (Chunk *c : delayIdata.getCodeChunks())1216textSec->addChunk(c);1217for (Chunk *c : delayIdata.getCodePData())1218pdataSec->addChunk(c);1219for (Chunk *c : delayIdata.getCodeUnwindInfo())1220rdataSec->addChunk(c);1221}1222}12231224void Writer::createExportTable() {1225llvm::TimeTraceScope timeScope("Export table");1226if (!edataSec->chunks.empty()) {1227// Allow using a custom built export table from input object files, instead1228// of having the linker synthesize the tables.1229if (ctx.config.hadExplicitExports)1230warn("literal .edata sections override exports");1231} else if (!ctx.config.exports.empty()) {1232for (Chunk *c : edata.chunks)1233edataSec->addChunk(c);1234}1235if (!edataSec->chunks.empty()) {1236edataStart = edataSec->chunks.front();1237edataEnd = edataSec->chunks.back();1238}1239// Warn on exported deleting destructor.1240for (auto e : ctx.config.exports)1241if (e.sym && e.sym->getName().starts_with("??_G"))1242warn("export of deleting dtor: " + toString(ctx, *e.sym));1243}12441245void Writer::removeUnusedSections() {1246llvm::TimeTraceScope timeScope("Remove unused sections");1247// Remove sections that we can be sure won't get content, to avoid1248// allocating space for their section headers.1249auto isUnused = [this](OutputSection *s) {1250if (s == relocSec)1251return false; // This section is populated later.1252// MergeChunks have zero size at this point, as their size is finalized1253// later. Only remove sections that have no Chunks at all.1254return s->chunks.empty();1255};1256llvm::erase_if(ctx.outputSections, isUnused);1257}12581259// The Windows loader doesn't seem to like empty sections,1260// so we remove them if any.1261void Writer::removeEmptySections() {1262llvm::TimeTraceScope timeScope("Remove empty sections");1263auto isEmpty = [](OutputSection *s) { return s->getVirtualSize() == 0; };1264llvm::erase_if(ctx.outputSections, isEmpty);1265}12661267void Writer::assignOutputSectionIndices() {1268llvm::TimeTraceScope timeScope("Output sections indices");1269// Assign final output section indices, and assign each chunk to its output1270// section.1271uint32_t idx = 1;1272for (OutputSection *os : ctx.outputSections) {1273os->sectionIndex = idx;1274for (Chunk *c : os->chunks)1275c->setOutputSectionIdx(idx);1276++idx;1277}12781279// Merge chunks are containers of chunks, so assign those an output section1280// too.1281for (MergeChunk *mc : ctx.mergeChunkInstances)1282if (mc)1283for (SectionChunk *sc : mc->sections)1284if (sc && sc->live)1285sc->setOutputSectionIdx(mc->getOutputSectionIdx());1286}12871288size_t Writer::addEntryToStringTable(StringRef str) {1289assert(str.size() > COFF::NameSize);1290size_t offsetOfEntry = strtab.size() + 4; // +4 for the size field1291strtab.insert(strtab.end(), str.begin(), str.end());1292strtab.push_back('\0');1293return offsetOfEntry;1294}12951296std::optional<coff_symbol16> Writer::createSymbol(Defined *def) {1297coff_symbol16 sym;1298switch (def->kind()) {1299case Symbol::DefinedAbsoluteKind: {1300auto *da = dyn_cast<DefinedAbsolute>(def);1301// Note: COFF symbol can only store 32-bit values, so 64-bit absolute1302// values will be truncated.1303sym.Value = da->getVA();1304sym.SectionNumber = IMAGE_SYM_ABSOLUTE;1305break;1306}1307default: {1308// Don't write symbols that won't be written to the output to the symbol1309// table.1310// We also try to write DefinedSynthetic as a normal symbol. Some of these1311// symbols do point to an actual chunk, like __safe_se_handler_table. Others1312// like __ImageBase are outside of sections and thus cannot be represented.1313Chunk *c = def->getChunk();1314if (!c)1315return std::nullopt;1316OutputSection *os = ctx.getOutputSection(c);1317if (!os)1318return std::nullopt;13191320sym.Value = def->getRVA() - os->getRVA();1321sym.SectionNumber = os->sectionIndex;1322break;1323}1324}13251326// Symbols that are runtime pseudo relocations don't point to the actual1327// symbol data itself (as they are imported), but points to the IAT entry1328// instead. Avoid emitting them to the symbol table, as they can confuse1329// debuggers.1330if (def->isRuntimePseudoReloc)1331return std::nullopt;13321333StringRef name = def->getName();1334if (name.size() > COFF::NameSize) {1335sym.Name.Offset.Zeroes = 0;1336sym.Name.Offset.Offset = addEntryToStringTable(name);1337} else {1338memset(sym.Name.ShortName, 0, COFF::NameSize);1339memcpy(sym.Name.ShortName, name.data(), name.size());1340}13411342if (auto *d = dyn_cast<DefinedCOFF>(def)) {1343COFFSymbolRef ref = d->getCOFFSymbol();1344sym.Type = ref.getType();1345sym.StorageClass = ref.getStorageClass();1346} else if (def->kind() == Symbol::DefinedImportThunkKind) {1347sym.Type = (IMAGE_SYM_DTYPE_FUNCTION << SCT_COMPLEX_TYPE_SHIFT) |1348IMAGE_SYM_TYPE_NULL;1349sym.StorageClass = IMAGE_SYM_CLASS_EXTERNAL;1350} else {1351sym.Type = IMAGE_SYM_TYPE_NULL;1352sym.StorageClass = IMAGE_SYM_CLASS_EXTERNAL;1353}1354sym.NumberOfAuxSymbols = 0;1355return sym;1356}13571358void Writer::createSymbolAndStringTable() {1359llvm::TimeTraceScope timeScope("Symbol and string table");1360// PE/COFF images are limited to 8 byte section names. Longer names can be1361// supported by writing a non-standard string table, but this string table is1362// not mapped at runtime and the long names will therefore be inaccessible.1363// link.exe always truncates section names to 8 bytes, whereas binutils always1364// preserves long section names via the string table. LLD adopts a hybrid1365// solution where discardable sections have long names preserved and1366// non-discardable sections have their names truncated, to ensure that any1367// section which is mapped at runtime also has its name mapped at runtime.1368for (OutputSection *sec : ctx.outputSections) {1369if (sec->name.size() <= COFF::NameSize)1370continue;1371if ((sec->header.Characteristics & IMAGE_SCN_MEM_DISCARDABLE) == 0)1372continue;1373if (ctx.config.warnLongSectionNames) {1374warn("section name " + sec->name +1375" is longer than 8 characters and will use a non-standard string "1376"table");1377}1378sec->setStringTableOff(addEntryToStringTable(sec->name));1379}13801381if (ctx.config.writeSymtab) {1382for (ObjFile *file : ctx.objFileInstances) {1383for (Symbol *b : file->getSymbols()) {1384auto *d = dyn_cast_or_null<Defined>(b);1385if (!d || d->writtenToSymtab)1386continue;1387d->writtenToSymtab = true;1388if (auto *dc = dyn_cast_or_null<DefinedCOFF>(d)) {1389COFFSymbolRef symRef = dc->getCOFFSymbol();1390if (symRef.isSectionDefinition() ||1391symRef.getStorageClass() == COFF::IMAGE_SYM_CLASS_LABEL)1392continue;1393}13941395if (std::optional<coff_symbol16> sym = createSymbol(d))1396outputSymtab.push_back(*sym);13971398if (auto *dthunk = dyn_cast<DefinedImportThunk>(d)) {1399if (!dthunk->wrappedSym->writtenToSymtab) {1400dthunk->wrappedSym->writtenToSymtab = true;1401if (std::optional<coff_symbol16> sym =1402createSymbol(dthunk->wrappedSym))1403outputSymtab.push_back(*sym);1404}1405}1406}1407}1408}14091410if (outputSymtab.empty() && strtab.empty())1411return;14121413// We position the symbol table to be adjacent to the end of the last section.1414uint64_t fileOff = fileSize;1415pointerToSymbolTable = fileOff;1416fileOff += outputSymtab.size() * sizeof(coff_symbol16);1417fileOff += 4 + strtab.size();1418fileSize = alignTo(fileOff, ctx.config.fileAlign);1419}14201421void Writer::mergeSections() {1422llvm::TimeTraceScope timeScope("Merge sections");1423if (!pdataSec->chunks.empty()) {1424if (isArm64EC(ctx.config.machine)) {1425// On ARM64EC .pdata may contain both ARM64 and X64 data. Split them by1426// sorting and store their regions separately.1427llvm::stable_sort(pdataSec->chunks, [=](const Chunk *a, const Chunk *b) {1428return (a->getMachine() == AMD64) < (b->getMachine() == AMD64);1429});14301431for (auto chunk : pdataSec->chunks) {1432if (chunk->getMachine() == AMD64) {1433hybridPdata.first = chunk;1434hybridPdata.last = pdataSec->chunks.back();1435break;1436}14371438if (!pdata.first)1439pdata.first = chunk;1440pdata.last = chunk;1441}1442} else {1443pdata.first = pdataSec->chunks.front();1444pdata.last = pdataSec->chunks.back();1445}1446}14471448for (auto &p : ctx.config.merge) {1449StringRef toName = p.second;1450if (p.first == toName)1451continue;1452StringSet<> names;1453while (true) {1454if (!names.insert(toName).second)1455fatal("/merge: cycle found for section '" + p.first + "'");1456auto i = ctx.config.merge.find(toName);1457if (i == ctx.config.merge.end())1458break;1459toName = i->second;1460}1461OutputSection *from = findSection(p.first);1462OutputSection *to = findSection(toName);1463if (!from)1464continue;1465if (!to) {1466from->name = toName;1467continue;1468}1469to->merge(from);1470}1471}14721473// EC targets may have chunks of various architectures mixed together at this1474// point. Group code chunks of the same architecture together by sorting chunks1475// by their EC range type.1476void Writer::sortECChunks() {1477if (!isArm64EC(ctx.config.machine))1478return;14791480for (OutputSection *sec : ctx.outputSections) {1481if (sec->isCodeSection())1482llvm::stable_sort(sec->chunks, [=](const Chunk *a, const Chunk *b) {1483std::optional<chpe_range_type> aType = a->getArm64ECRangeType(),1484bType = b->getArm64ECRangeType();1485return bType && (!aType || *aType < *bType);1486});1487}1488}14891490// Visits all sections to assign incremental, non-overlapping RVAs and1491// file offsets.1492void Writer::assignAddresses() {1493llvm::TimeTraceScope timeScope("Assign addresses");1494Configuration *config = &ctx.config;14951496// We need to create EC code map so that ECCodeMapChunk knows its size.1497// We do it here to make sure that we account for range extension chunks.1498createECCodeMap();14991500sizeOfHeaders = dosStubSize + sizeof(PEMagic) + sizeof(coff_file_header) +1501sizeof(data_directory) * numberOfDataDirectory +1502sizeof(coff_section) * ctx.outputSections.size();1503sizeOfHeaders +=1504config->is64() ? sizeof(pe32plus_header) : sizeof(pe32_header);1505sizeOfHeaders = alignTo(sizeOfHeaders, config->fileAlign);1506fileSize = sizeOfHeaders;15071508// The first page is kept unmapped.1509uint64_t rva = alignTo(sizeOfHeaders, config->align);15101511for (OutputSection *sec : ctx.outputSections) {1512llvm::TimeTraceScope timeScope("Section: ", sec->name);1513if (sec == relocSec)1514addBaserels();1515uint64_t rawSize = 0, virtualSize = 0;1516sec->header.VirtualAddress = rva;15171518// If /FUNCTIONPADMIN is used, functions are padded in order to create a1519// hotpatchable image.1520uint32_t padding = sec->isCodeSection() ? config->functionPadMin : 0;1521std::optional<chpe_range_type> prevECRange;15221523for (Chunk *c : sec->chunks) {1524// Alignment EC code range baudaries.1525if (isArm64EC(ctx.config.machine) && sec->isCodeSection()) {1526std::optional<chpe_range_type> rangeType = c->getArm64ECRangeType();1527if (rangeType != prevECRange) {1528virtualSize = alignTo(virtualSize, 4096);1529prevECRange = rangeType;1530}1531}1532if (padding && c->isHotPatchable())1533virtualSize += padding;1534// If chunk has EC entry thunk, reserve a space for an offset to the1535// thunk.1536if (c->getEntryThunk())1537virtualSize += sizeof(uint32_t);1538virtualSize = alignTo(virtualSize, c->getAlignment());1539c->setRVA(rva + virtualSize);1540virtualSize += c->getSize();1541if (c->hasData)1542rawSize = alignTo(virtualSize, config->fileAlign);1543}1544if (virtualSize > UINT32_MAX)1545error("section larger than 4 GiB: " + sec->name);1546sec->header.VirtualSize = virtualSize;1547sec->header.SizeOfRawData = rawSize;1548if (rawSize != 0)1549sec->header.PointerToRawData = fileSize;1550rva += alignTo(virtualSize, config->align);1551fileSize += alignTo(rawSize, config->fileAlign);1552}1553sizeOfImage = alignTo(rva, config->align);15541555// Assign addresses to sections in MergeChunks.1556for (MergeChunk *mc : ctx.mergeChunkInstances)1557if (mc)1558mc->assignSubsectionRVAs();1559}15601561template <typename PEHeaderTy> void Writer::writeHeader() {1562// Write DOS header. For backwards compatibility, the first part of a PE/COFF1563// executable consists of an MS-DOS MZ executable. If the executable is run1564// under DOS, that program gets run (usually to just print an error message).1565// When run under Windows, the loader looks at AddressOfNewExeHeader and uses1566// the PE header instead.1567Configuration *config = &ctx.config;1568uint8_t *buf = buffer->getBufferStart();1569auto *dos = reinterpret_cast<dos_header *>(buf);1570buf += sizeof(dos_header);1571dos->Magic[0] = 'M';1572dos->Magic[1] = 'Z';1573dos->UsedBytesInTheLastPage = dosStubSize % 512;1574dos->FileSizeInPages = divideCeil(dosStubSize, 512);1575dos->HeaderSizeInParagraphs = sizeof(dos_header) / 16;15761577dos->AddressOfRelocationTable = sizeof(dos_header);1578dos->AddressOfNewExeHeader = dosStubSize;15791580// Write DOS program.1581memcpy(buf, dosProgram, sizeof(dosProgram));1582buf += sizeof(dosProgram);15831584// Write PE magic1585memcpy(buf, PEMagic, sizeof(PEMagic));1586buf += sizeof(PEMagic);15871588// Write COFF header1589auto *coff = reinterpret_cast<coff_file_header *>(buf);1590buf += sizeof(*coff);1591switch (config->machine) {1592case ARM64EC:1593coff->Machine = AMD64;1594break;1595case ARM64X:1596coff->Machine = ARM64;1597break;1598default:1599coff->Machine = config->machine;1600}1601coff->NumberOfSections = ctx.outputSections.size();1602coff->Characteristics = IMAGE_FILE_EXECUTABLE_IMAGE;1603if (config->largeAddressAware)1604coff->Characteristics |= IMAGE_FILE_LARGE_ADDRESS_AWARE;1605if (!config->is64())1606coff->Characteristics |= IMAGE_FILE_32BIT_MACHINE;1607if (config->dll)1608coff->Characteristics |= IMAGE_FILE_DLL;1609if (config->driverUponly)1610coff->Characteristics |= IMAGE_FILE_UP_SYSTEM_ONLY;1611if (!config->relocatable)1612coff->Characteristics |= IMAGE_FILE_RELOCS_STRIPPED;1613if (config->swaprunCD)1614coff->Characteristics |= IMAGE_FILE_REMOVABLE_RUN_FROM_SWAP;1615if (config->swaprunNet)1616coff->Characteristics |= IMAGE_FILE_NET_RUN_FROM_SWAP;1617coff->SizeOfOptionalHeader =1618sizeof(PEHeaderTy) + sizeof(data_directory) * numberOfDataDirectory;16191620// Write PE header1621auto *pe = reinterpret_cast<PEHeaderTy *>(buf);1622buf += sizeof(*pe);1623pe->Magic = config->is64() ? PE32Header::PE32_PLUS : PE32Header::PE32;16241625// If {Major,Minor}LinkerVersion is left at 0.0, then for some1626// reason signing the resulting PE file with Authenticode produces a1627// signature that fails to validate on Windows 7 (but is OK on 10).1628// Set it to 14.0, which is what VS2015 outputs, and which avoids1629// that problem.1630pe->MajorLinkerVersion = 14;1631pe->MinorLinkerVersion = 0;16321633pe->ImageBase = config->imageBase;1634pe->SectionAlignment = config->align;1635pe->FileAlignment = config->fileAlign;1636pe->MajorImageVersion = config->majorImageVersion;1637pe->MinorImageVersion = config->minorImageVersion;1638pe->MajorOperatingSystemVersion = config->majorOSVersion;1639pe->MinorOperatingSystemVersion = config->minorOSVersion;1640pe->MajorSubsystemVersion = config->majorSubsystemVersion;1641pe->MinorSubsystemVersion = config->minorSubsystemVersion;1642pe->Subsystem = config->subsystem;1643pe->SizeOfImage = sizeOfImage;1644pe->SizeOfHeaders = sizeOfHeaders;1645if (!config->noEntry) {1646Defined *entry = cast<Defined>(config->entry);1647pe->AddressOfEntryPoint = entry->getRVA();1648// Pointer to thumb code must have the LSB set, so adjust it.1649if (config->machine == ARMNT)1650pe->AddressOfEntryPoint |= 1;1651}1652pe->SizeOfStackReserve = config->stackReserve;1653pe->SizeOfStackCommit = config->stackCommit;1654pe->SizeOfHeapReserve = config->heapReserve;1655pe->SizeOfHeapCommit = config->heapCommit;1656if (config->appContainer)1657pe->DLLCharacteristics |= IMAGE_DLL_CHARACTERISTICS_APPCONTAINER;1658if (config->driverWdm)1659pe->DLLCharacteristics |= IMAGE_DLL_CHARACTERISTICS_WDM_DRIVER;1660if (config->dynamicBase)1661pe->DLLCharacteristics |= IMAGE_DLL_CHARACTERISTICS_DYNAMIC_BASE;1662if (config->highEntropyVA)1663pe->DLLCharacteristics |= IMAGE_DLL_CHARACTERISTICS_HIGH_ENTROPY_VA;1664if (!config->allowBind)1665pe->DLLCharacteristics |= IMAGE_DLL_CHARACTERISTICS_NO_BIND;1666if (config->nxCompat)1667pe->DLLCharacteristics |= IMAGE_DLL_CHARACTERISTICS_NX_COMPAT;1668if (!config->allowIsolation)1669pe->DLLCharacteristics |= IMAGE_DLL_CHARACTERISTICS_NO_ISOLATION;1670if (config->guardCF != GuardCFLevel::Off)1671pe->DLLCharacteristics |= IMAGE_DLL_CHARACTERISTICS_GUARD_CF;1672if (config->integrityCheck)1673pe->DLLCharacteristics |= IMAGE_DLL_CHARACTERISTICS_FORCE_INTEGRITY;1674if (setNoSEHCharacteristic || config->noSEH)1675pe->DLLCharacteristics |= IMAGE_DLL_CHARACTERISTICS_NO_SEH;1676if (config->terminalServerAware)1677pe->DLLCharacteristics |= IMAGE_DLL_CHARACTERISTICS_TERMINAL_SERVER_AWARE;1678pe->NumberOfRvaAndSize = numberOfDataDirectory;1679if (textSec->getVirtualSize()) {1680pe->BaseOfCode = textSec->getRVA();1681pe->SizeOfCode = textSec->getRawSize();1682}1683pe->SizeOfInitializedData = getSizeOfInitializedData();16841685// Write data directory1686auto *dir = reinterpret_cast<data_directory *>(buf);1687buf += sizeof(*dir) * numberOfDataDirectory;1688if (edataStart) {1689dir[EXPORT_TABLE].RelativeVirtualAddress = edataStart->getRVA();1690dir[EXPORT_TABLE].Size =1691edataEnd->getRVA() + edataEnd->getSize() - edataStart->getRVA();1692}1693if (importTableStart) {1694dir[IMPORT_TABLE].RelativeVirtualAddress = importTableStart->getRVA();1695dir[IMPORT_TABLE].Size = importTableSize;1696}1697if (iatStart) {1698dir[IAT].RelativeVirtualAddress = iatStart->getRVA();1699dir[IAT].Size = iatSize;1700}1701if (rsrcSec->getVirtualSize()) {1702dir[RESOURCE_TABLE].RelativeVirtualAddress = rsrcSec->getRVA();1703dir[RESOURCE_TABLE].Size = rsrcSec->getVirtualSize();1704}1705// ARM64EC (but not ARM64X) contains x86_64 exception table in data directory.1706ChunkRange &exceptionTable =1707ctx.config.machine == ARM64EC ? hybridPdata : pdata;1708if (exceptionTable.first) {1709dir[EXCEPTION_TABLE].RelativeVirtualAddress =1710exceptionTable.first->getRVA();1711dir[EXCEPTION_TABLE].Size = exceptionTable.last->getRVA() +1712exceptionTable.last->getSize() -1713exceptionTable.first->getRVA();1714}1715if (relocSec->getVirtualSize()) {1716dir[BASE_RELOCATION_TABLE].RelativeVirtualAddress = relocSec->getRVA();1717dir[BASE_RELOCATION_TABLE].Size = relocSec->getVirtualSize();1718}1719if (Symbol *sym = ctx.symtab.findUnderscore("_tls_used")) {1720if (Defined *b = dyn_cast<Defined>(sym)) {1721dir[TLS_TABLE].RelativeVirtualAddress = b->getRVA();1722dir[TLS_TABLE].Size = config->is64()1723? sizeof(object::coff_tls_directory64)1724: sizeof(object::coff_tls_directory32);1725}1726}1727if (debugDirectory) {1728dir[DEBUG_DIRECTORY].RelativeVirtualAddress = debugDirectory->getRVA();1729dir[DEBUG_DIRECTORY].Size = debugDirectory->getSize();1730}1731if (Symbol *sym = ctx.symtab.findUnderscore("_load_config_used")) {1732if (auto *b = dyn_cast<DefinedRegular>(sym)) {1733SectionChunk *sc = b->getChunk();1734assert(b->getRVA() >= sc->getRVA());1735uint64_t offsetInChunk = b->getRVA() - sc->getRVA();1736if (!sc->hasData || offsetInChunk + 4 > sc->getSize())1737fatal("_load_config_used is malformed");17381739ArrayRef<uint8_t> secContents = sc->getContents();1740uint32_t loadConfigSize =1741*reinterpret_cast<const ulittle32_t *>(&secContents[offsetInChunk]);1742if (offsetInChunk + loadConfigSize > sc->getSize())1743fatal("_load_config_used is too large");1744dir[LOAD_CONFIG_TABLE].RelativeVirtualAddress = b->getRVA();1745dir[LOAD_CONFIG_TABLE].Size = loadConfigSize;1746}1747}1748if (!delayIdata.empty()) {1749dir[DELAY_IMPORT_DESCRIPTOR].RelativeVirtualAddress =1750delayIdata.getDirRVA();1751dir[DELAY_IMPORT_DESCRIPTOR].Size = delayIdata.getDirSize();1752}17531754// Write section table1755for (OutputSection *sec : ctx.outputSections) {1756sec->writeHeaderTo(buf, config->debug);1757buf += sizeof(coff_section);1758}1759sectionTable = ArrayRef<uint8_t>(1760buf - ctx.outputSections.size() * sizeof(coff_section), buf);17611762if (outputSymtab.empty() && strtab.empty())1763return;17641765coff->PointerToSymbolTable = pointerToSymbolTable;1766uint32_t numberOfSymbols = outputSymtab.size();1767coff->NumberOfSymbols = numberOfSymbols;1768auto *symbolTable = reinterpret_cast<coff_symbol16 *>(1769buffer->getBufferStart() + coff->PointerToSymbolTable);1770for (size_t i = 0; i != numberOfSymbols; ++i)1771symbolTable[i] = outputSymtab[i];1772// Create the string table, it follows immediately after the symbol table.1773// The first 4 bytes is length including itself.1774buf = reinterpret_cast<uint8_t *>(&symbolTable[numberOfSymbols]);1775write32le(buf, strtab.size() + 4);1776if (!strtab.empty())1777memcpy(buf + 4, strtab.data(), strtab.size());1778}17791780void Writer::openFile(StringRef path) {1781buffer = CHECK(1782FileOutputBuffer::create(path, fileSize, FileOutputBuffer::F_executable),1783"failed to open " + path);1784}17851786void Writer::createSEHTable() {1787SymbolRVASet handlers;1788for (ObjFile *file : ctx.objFileInstances) {1789if (!file->hasSafeSEH())1790error("/safeseh: " + file->getName() + " is not compatible with SEH");1791markSymbolsForRVATable(file, file->getSXDataChunks(), handlers);1792}17931794// Set the "no SEH" characteristic if there really were no handlers, or if1795// there is no load config object to point to the table of handlers.1796setNoSEHCharacteristic =1797handlers.empty() || !ctx.symtab.findUnderscore("_load_config_used");17981799maybeAddRVATable(std::move(handlers), "__safe_se_handler_table",1800"__safe_se_handler_count");1801}18021803// Add a symbol to an RVA set. Two symbols may have the same RVA, but an RVA set1804// cannot contain duplicates. Therefore, the set is uniqued by Chunk and the1805// symbol's offset into that Chunk.1806static void addSymbolToRVASet(SymbolRVASet &rvaSet, Defined *s) {1807Chunk *c = s->getChunk();1808if (!c)1809return;1810if (auto *sc = dyn_cast<SectionChunk>(c))1811c = sc->repl; // Look through ICF replacement.1812uint32_t off = s->getRVA() - (c ? c->getRVA() : 0);1813rvaSet.insert({c, off});1814}18151816// Given a symbol, add it to the GFIDs table if it is a live, defined, function1817// symbol in an executable section.1818static void maybeAddAddressTakenFunction(SymbolRVASet &addressTakenSyms,1819Symbol *s) {1820if (!s)1821return;18221823switch (s->kind()) {1824case Symbol::DefinedLocalImportKind:1825case Symbol::DefinedImportDataKind:1826// Defines an __imp_ pointer, so it is data, so it is ignored.1827break;1828case Symbol::DefinedCommonKind:1829// Common is always data, so it is ignored.1830break;1831case Symbol::DefinedAbsoluteKind:1832case Symbol::DefinedSyntheticKind:1833// Absolute is never code, synthetic generally isn't and usually isn't1834// determinable.1835break;1836case Symbol::LazyArchiveKind:1837case Symbol::LazyObjectKind:1838case Symbol::LazyDLLSymbolKind:1839case Symbol::UndefinedKind:1840// Undefined symbols resolve to zero, so they don't have an RVA. Lazy1841// symbols shouldn't have relocations.1842break;18431844case Symbol::DefinedImportThunkKind:1845// Thunks are always code, include them.1846addSymbolToRVASet(addressTakenSyms, cast<Defined>(s));1847break;18481849case Symbol::DefinedRegularKind: {1850// This is a regular, defined, symbol from a COFF file. Mark the symbol as1851// address taken if the symbol type is function and it's in an executable1852// section.1853auto *d = cast<DefinedRegular>(s);1854if (d->getCOFFSymbol().getComplexType() == COFF::IMAGE_SYM_DTYPE_FUNCTION) {1855SectionChunk *sc = dyn_cast<SectionChunk>(d->getChunk());1856if (sc && sc->live &&1857sc->getOutputCharacteristics() & IMAGE_SCN_MEM_EXECUTE)1858addSymbolToRVASet(addressTakenSyms, d);1859}1860break;1861}1862}1863}18641865// Visit all relocations from all section contributions of this object file and1866// mark the relocation target as address-taken.1867void Writer::markSymbolsWithRelocations(ObjFile *file,1868SymbolRVASet &usedSymbols) {1869for (Chunk *c : file->getChunks()) {1870// We only care about live section chunks. Common chunks and other chunks1871// don't generally contain relocations.1872SectionChunk *sc = dyn_cast<SectionChunk>(c);1873if (!sc || !sc->live)1874continue;18751876for (const coff_relocation &reloc : sc->getRelocs()) {1877if (ctx.config.machine == I386 &&1878reloc.Type == COFF::IMAGE_REL_I386_REL32)1879// Ignore relative relocations on x86. On x86_64 they can't be ignored1880// since they're also used to compute absolute addresses.1881continue;18821883Symbol *ref = sc->file->getSymbol(reloc.SymbolTableIndex);1884maybeAddAddressTakenFunction(usedSymbols, ref);1885}1886}1887}18881889// Create the guard function id table. This is a table of RVAs of all1890// address-taken functions. It is sorted and uniqued, just like the safe SEH1891// table.1892void Writer::createGuardCFTables() {1893Configuration *config = &ctx.config;18941895SymbolRVASet addressTakenSyms;1896SymbolRVASet giatsRVASet;1897std::vector<Symbol *> giatsSymbols;1898SymbolRVASet longJmpTargets;1899SymbolRVASet ehContTargets;1900for (ObjFile *file : ctx.objFileInstances) {1901// If the object was compiled with /guard:cf, the address taken symbols1902// are in .gfids$y sections, and the longjmp targets are in .gljmp$y1903// sections. If the object was not compiled with /guard:cf, we assume there1904// were no setjmp targets, and that all code symbols with relocations are1905// possibly address-taken.1906if (file->hasGuardCF()) {1907markSymbolsForRVATable(file, file->getGuardFidChunks(), addressTakenSyms);1908markSymbolsForRVATable(file, file->getGuardIATChunks(), giatsRVASet);1909getSymbolsFromSections(file, file->getGuardIATChunks(), giatsSymbols);1910markSymbolsForRVATable(file, file->getGuardLJmpChunks(), longJmpTargets);1911} else {1912markSymbolsWithRelocations(file, addressTakenSyms);1913}1914// If the object was compiled with /guard:ehcont, the ehcont targets are in1915// .gehcont$y sections.1916if (file->hasGuardEHCont())1917markSymbolsForRVATable(file, file->getGuardEHContChunks(), ehContTargets);1918}19191920// Mark the image entry as address-taken.1921if (config->entry)1922maybeAddAddressTakenFunction(addressTakenSyms, config->entry);19231924// Mark exported symbols in executable sections as address-taken.1925for (Export &e : config->exports)1926maybeAddAddressTakenFunction(addressTakenSyms, e.sym);19271928// For each entry in the .giats table, check if it has a corresponding load1929// thunk (e.g. because the DLL that defines it will be delay-loaded) and, if1930// so, add the load thunk to the address taken (.gfids) table.1931for (Symbol *s : giatsSymbols) {1932if (auto *di = dyn_cast<DefinedImportData>(s)) {1933if (di->loadThunkSym)1934addSymbolToRVASet(addressTakenSyms, di->loadThunkSym);1935}1936}19371938// Ensure sections referenced in the gfid table are 16-byte aligned.1939for (const ChunkAndOffset &c : addressTakenSyms)1940if (c.inputChunk->getAlignment() < 16)1941c.inputChunk->setAlignment(16);19421943maybeAddRVATable(std::move(addressTakenSyms), "__guard_fids_table",1944"__guard_fids_count");19451946// Add the Guard Address Taken IAT Entry Table (.giats).1947maybeAddRVATable(std::move(giatsRVASet), "__guard_iat_table",1948"__guard_iat_count");19491950// Add the longjmp target table unless the user told us not to.1951if (config->guardCF & GuardCFLevel::LongJmp)1952maybeAddRVATable(std::move(longJmpTargets), "__guard_longjmp_table",1953"__guard_longjmp_count");19541955// Add the ehcont target table unless the user told us not to.1956if (config->guardCF & GuardCFLevel::EHCont)1957maybeAddRVATable(std::move(ehContTargets), "__guard_eh_cont_table",1958"__guard_eh_cont_count");19591960// Set __guard_flags, which will be used in the load config to indicate that1961// /guard:cf was enabled.1962uint32_t guardFlags = uint32_t(GuardFlags::CF_INSTRUMENTED) |1963uint32_t(GuardFlags::CF_FUNCTION_TABLE_PRESENT);1964if (config->guardCF & GuardCFLevel::LongJmp)1965guardFlags |= uint32_t(GuardFlags::CF_LONGJUMP_TABLE_PRESENT);1966if (config->guardCF & GuardCFLevel::EHCont)1967guardFlags |= uint32_t(GuardFlags::EH_CONTINUATION_TABLE_PRESENT);1968Symbol *flagSym = ctx.symtab.findUnderscore("__guard_flags");1969cast<DefinedAbsolute>(flagSym)->setVA(guardFlags);1970}19711972// Take a list of input sections containing symbol table indices and add those1973// symbols to a vector. The challenge is that symbol RVAs are not known and1974// depend on the table size, so we can't directly build a set of integers.1975void Writer::getSymbolsFromSections(ObjFile *file,1976ArrayRef<SectionChunk *> symIdxChunks,1977std::vector<Symbol *> &symbols) {1978for (SectionChunk *c : symIdxChunks) {1979// Skip sections discarded by linker GC. This comes up when a .gfids section1980// is associated with something like a vtable and the vtable is discarded.1981// In this case, the associated gfids section is discarded, and we don't1982// mark the virtual member functions as address-taken by the vtable.1983if (!c->live)1984continue;19851986// Validate that the contents look like symbol table indices.1987ArrayRef<uint8_t> data = c->getContents();1988if (data.size() % 4 != 0) {1989warn("ignoring " + c->getSectionName() +1990" symbol table index section in object " + toString(file));1991continue;1992}19931994// Read each symbol table index and check if that symbol was included in the1995// final link. If so, add it to the vector of symbols.1996ArrayRef<ulittle32_t> symIndices(1997reinterpret_cast<const ulittle32_t *>(data.data()), data.size() / 4);1998ArrayRef<Symbol *> objSymbols = file->getSymbols();1999for (uint32_t symIndex : symIndices) {2000if (symIndex >= objSymbols.size()) {2001warn("ignoring invalid symbol table index in section " +2002c->getSectionName() + " in object " + toString(file));2003continue;2004}2005if (Symbol *s = objSymbols[symIndex]) {2006if (s->isLive())2007symbols.push_back(cast<Symbol>(s));2008}2009}2010}2011}20122013// Take a list of input sections containing symbol table indices and add those2014// symbols to an RVA table.2015void Writer::markSymbolsForRVATable(ObjFile *file,2016ArrayRef<SectionChunk *> symIdxChunks,2017SymbolRVASet &tableSymbols) {2018std::vector<Symbol *> syms;2019getSymbolsFromSections(file, symIdxChunks, syms);20202021for (Symbol *s : syms)2022addSymbolToRVASet(tableSymbols, cast<Defined>(s));2023}20242025// Replace the absolute table symbol with a synthetic symbol pointing to2026// tableChunk so that we can emit base relocations for it and resolve section2027// relative relocations.2028void Writer::maybeAddRVATable(SymbolRVASet tableSymbols, StringRef tableSym,2029StringRef countSym, bool hasFlag) {2030if (tableSymbols.empty())2031return;20322033NonSectionChunk *tableChunk;2034if (hasFlag)2035tableChunk = make<RVAFlagTableChunk>(std::move(tableSymbols));2036else2037tableChunk = make<RVATableChunk>(std::move(tableSymbols));2038rdataSec->addChunk(tableChunk);20392040Symbol *t = ctx.symtab.findUnderscore(tableSym);2041Symbol *c = ctx.symtab.findUnderscore(countSym);2042replaceSymbol<DefinedSynthetic>(t, t->getName(), tableChunk);2043cast<DefinedAbsolute>(c)->setVA(tableChunk->getSize() / (hasFlag ? 5 : 4));2044}20452046// Create CHPE metadata chunks.2047void Writer::createECChunks() {2048auto codeMapChunk = make<ECCodeMapChunk>(codeMap);2049rdataSec->addChunk(codeMapChunk);2050Symbol *codeMapSym = ctx.symtab.findUnderscore("__hybrid_code_map");2051replaceSymbol<DefinedSynthetic>(codeMapSym, codeMapSym->getName(),2052codeMapChunk);2053}20542055// MinGW specific. Gather all relocations that are imported from a DLL even2056// though the code didn't expect it to, produce the table that the runtime2057// uses for fixing them up, and provide the synthetic symbols that the2058// runtime uses for finding the table.2059void Writer::createRuntimePseudoRelocs() {2060std::vector<RuntimePseudoReloc> rels;20612062for (Chunk *c : ctx.symtab.getChunks()) {2063auto *sc = dyn_cast<SectionChunk>(c);2064if (!sc || !sc->live)2065continue;2066// Don't create pseudo relocations for sections that won't be2067// mapped at runtime.2068if (sc->header->Characteristics & IMAGE_SCN_MEM_DISCARDABLE)2069continue;2070sc->getRuntimePseudoRelocs(rels);2071}20722073if (!ctx.config.pseudoRelocs) {2074// Not writing any pseudo relocs; if some were needed, error out and2075// indicate what required them.2076for (const RuntimePseudoReloc &rpr : rels)2077error("automatic dllimport of " + rpr.sym->getName() + " in " +2078toString(rpr.target->file) + " requires pseudo relocations");2079return;2080}20812082if (!rels.empty()) {2083log("Writing " + Twine(rels.size()) + " runtime pseudo relocations");2084const char *symbolName = "_pei386_runtime_relocator";2085Symbol *relocator = ctx.symtab.findUnderscore(symbolName);2086if (!relocator)2087error("output image has runtime pseudo relocations, but the function " +2088Twine(symbolName) +2089" is missing; it is needed for fixing the relocations at runtime");2090}20912092PseudoRelocTableChunk *table = make<PseudoRelocTableChunk>(rels);2093rdataSec->addChunk(table);2094EmptyChunk *endOfList = make<EmptyChunk>();2095rdataSec->addChunk(endOfList);20962097Symbol *headSym = ctx.symtab.findUnderscore("__RUNTIME_PSEUDO_RELOC_LIST__");2098Symbol *endSym =2099ctx.symtab.findUnderscore("__RUNTIME_PSEUDO_RELOC_LIST_END__");2100replaceSymbol<DefinedSynthetic>(headSym, headSym->getName(), table);2101replaceSymbol<DefinedSynthetic>(endSym, endSym->getName(), endOfList);2102}21032104// MinGW specific.2105// The MinGW .ctors and .dtors lists have sentinels at each end;2106// a (uintptr_t)-1 at the start and a (uintptr_t)0 at the end.2107// There's a symbol pointing to the start sentinel pointer, __CTOR_LIST__2108// and __DTOR_LIST__ respectively.2109void Writer::insertCtorDtorSymbols() {2110AbsolutePointerChunk *ctorListHead = make<AbsolutePointerChunk>(ctx, -1);2111AbsolutePointerChunk *ctorListEnd = make<AbsolutePointerChunk>(ctx, 0);2112AbsolutePointerChunk *dtorListHead = make<AbsolutePointerChunk>(ctx, -1);2113AbsolutePointerChunk *dtorListEnd = make<AbsolutePointerChunk>(ctx, 0);2114ctorsSec->insertChunkAtStart(ctorListHead);2115ctorsSec->addChunk(ctorListEnd);2116dtorsSec->insertChunkAtStart(dtorListHead);2117dtorsSec->addChunk(dtorListEnd);21182119Symbol *ctorListSym = ctx.symtab.findUnderscore("__CTOR_LIST__");2120Symbol *dtorListSym = ctx.symtab.findUnderscore("__DTOR_LIST__");2121replaceSymbol<DefinedSynthetic>(ctorListSym, ctorListSym->getName(),2122ctorListHead);2123replaceSymbol<DefinedSynthetic>(dtorListSym, dtorListSym->getName(),2124dtorListHead);2125}21262127// Handles /section options to allow users to overwrite2128// section attributes.2129void Writer::setSectionPermissions() {2130llvm::TimeTraceScope timeScope("Sections permissions");2131for (auto &p : ctx.config.section) {2132StringRef name = p.first;2133uint32_t perm = p.second;2134for (OutputSection *sec : ctx.outputSections)2135if (sec->name == name)2136sec->setPermissions(perm);2137}2138}21392140// Set symbols used by ARM64EC metadata.2141void Writer::setECSymbols() {2142if (!isArm64EC(ctx.config.machine))2143return;21442145Symbol *rfeTableSym = ctx.symtab.findUnderscore("__arm64x_extra_rfe_table");2146replaceSymbol<DefinedSynthetic>(rfeTableSym, "__arm64x_extra_rfe_table",2147pdata.first);21482149if (pdata.first) {2150Symbol *rfeSizeSym =2151ctx.symtab.findUnderscore("__arm64x_extra_rfe_table_size");2152cast<DefinedAbsolute>(rfeSizeSym)2153->setVA(pdata.last->getRVA() + pdata.last->getSize() -2154pdata.first->getRVA());2155}2156}21572158// Write section contents to a mmap'ed file.2159void Writer::writeSections() {2160llvm::TimeTraceScope timeScope("Write sections");2161uint8_t *buf = buffer->getBufferStart();2162for (OutputSection *sec : ctx.outputSections) {2163uint8_t *secBuf = buf + sec->getFileOff();2164// Fill gaps between functions in .text with INT3 instructions2165// instead of leaving as NUL bytes (which can be interpreted as2166// ADD instructions). Only fill the gaps between chunks. Most2167// chunks overwrite it anyway, but uninitialized data chunks2168// merged into a code section don't.2169if ((sec->header.Characteristics & IMAGE_SCN_CNT_CODE) &&2170(ctx.config.machine == AMD64 || ctx.config.machine == I386)) {2171uint32_t prevEnd = 0;2172for (Chunk *c : sec->chunks) {2173uint32_t off = c->getRVA() - sec->getRVA();2174memset(secBuf + prevEnd, 0xCC, off - prevEnd);2175prevEnd = off + c->getSize();2176}2177memset(secBuf + prevEnd, 0xCC, sec->getRawSize() - prevEnd);2178}21792180parallelForEach(sec->chunks, [&](Chunk *c) {2181c->writeTo(secBuf + c->getRVA() - sec->getRVA());2182});2183}2184}21852186void Writer::writeBuildId() {2187llvm::TimeTraceScope timeScope("Write build ID");21882189// There are two important parts to the build ID.2190// 1) If building with debug info, the COFF debug directory contains a2191// timestamp as well as a Guid and Age of the PDB.2192// 2) In all cases, the PE COFF file header also contains a timestamp.2193// For reproducibility, instead of a timestamp we want to use a hash of the2194// PE contents.2195Configuration *config = &ctx.config;2196bool generateSyntheticBuildId = config->buildIDHash == BuildIDHash::Binary;2197if (generateSyntheticBuildId) {2198assert(buildId && "BuildId is not set!");2199// BuildId->BuildId was filled in when the PDB was written.2200}22012202// At this point the only fields in the COFF file which remain unset are the2203// "timestamp" in the COFF file header, and the ones in the coff debug2204// directory. Now we can hash the file and write that hash to the various2205// timestamp fields in the file.2206StringRef outputFileData(2207reinterpret_cast<const char *>(buffer->getBufferStart()),2208buffer->getBufferSize());22092210uint32_t timestamp = config->timestamp;2211uint64_t hash = 0;22122213if (config->repro || generateSyntheticBuildId)2214hash = xxh3_64bits(outputFileData);22152216if (config->repro)2217timestamp = static_cast<uint32_t>(hash);22182219if (generateSyntheticBuildId) {2220buildId->buildId->PDB70.CVSignature = OMF::Signature::PDB70;2221buildId->buildId->PDB70.Age = 1;2222memcpy(buildId->buildId->PDB70.Signature, &hash, 8);2223// xxhash only gives us 8 bytes, so put some fixed data in the other half.2224memcpy(&buildId->buildId->PDB70.Signature[8], "LLD PDB.", 8);2225}22262227if (debugDirectory)2228debugDirectory->setTimeDateStamp(timestamp);22292230uint8_t *buf = buffer->getBufferStart();2231buf += dosStubSize + sizeof(PEMagic);2232object::coff_file_header *coffHeader =2233reinterpret_cast<coff_file_header *>(buf);2234coffHeader->TimeDateStamp = timestamp;2235}22362237// Sort .pdata section contents according to PE/COFF spec 5.5.2238template <typename T>2239void Writer::sortExceptionTable(ChunkRange &exceptionTable) {2240if (!exceptionTable.first)2241return;22422243// We assume .pdata contains function table entries only.2244auto bufAddr = [&](Chunk *c) {2245OutputSection *os = ctx.getOutputSection(c);2246return buffer->getBufferStart() + os->getFileOff() + c->getRVA() -2247os->getRVA();2248};2249uint8_t *begin = bufAddr(exceptionTable.first);2250uint8_t *end = bufAddr(exceptionTable.last) + exceptionTable.last->getSize();2251if ((end - begin) % sizeof(T) != 0) {2252fatal("unexpected .pdata size: " + Twine(end - begin) +2253" is not a multiple of " + Twine(sizeof(T)));2254}22552256parallelSort(MutableArrayRef<T>(reinterpret_cast<T *>(begin),2257reinterpret_cast<T *>(end)),2258[](const T &a, const T &b) { return a.begin < b.begin; });2259}22602261// Sort .pdata section contents according to PE/COFF spec 5.5.2262void Writer::sortExceptionTables() {2263llvm::TimeTraceScope timeScope("Sort exception table");22642265struct EntryX64 {2266ulittle32_t begin, end, unwind;2267};2268struct EntryArm {2269ulittle32_t begin, unwind;2270};22712272switch (ctx.config.machine) {2273case AMD64:2274sortExceptionTable<EntryX64>(pdata);2275break;2276case ARM64EC:2277case ARM64X:2278sortExceptionTable<EntryX64>(hybridPdata);2279[[fallthrough]];2280case ARMNT:2281case ARM64:2282sortExceptionTable<EntryArm>(pdata);2283break;2284default:2285if (pdata.first)2286lld::errs() << "warning: don't know how to handle .pdata.\n";2287break;2288}2289}22902291// The CRT section contains, among other things, the array of function2292// pointers that initialize every global variable that is not trivially2293// constructed. The CRT calls them one after the other prior to invoking2294// main().2295//2296// As per C++ spec, 3.6.2/2.3,2297// "Variables with ordered initialization defined within a single2298// translation unit shall be initialized in the order of their definitions2299// in the translation unit"2300//2301// It is therefore critical to sort the chunks containing the function2302// pointers in the order that they are listed in the object file (top to2303// bottom), otherwise global objects might not be initialized in the2304// correct order.2305void Writer::sortCRTSectionChunks(std::vector<Chunk *> &chunks) {2306auto sectionChunkOrder = [](const Chunk *a, const Chunk *b) {2307auto sa = dyn_cast<SectionChunk>(a);2308auto sb = dyn_cast<SectionChunk>(b);2309assert(sa && sb && "Non-section chunks in CRT section!");23102311StringRef sAObj = sa->file->mb.getBufferIdentifier();2312StringRef sBObj = sb->file->mb.getBufferIdentifier();23132314return sAObj == sBObj && sa->getSectionNumber() < sb->getSectionNumber();2315};2316llvm::stable_sort(chunks, sectionChunkOrder);23172318if (ctx.config.verbose) {2319for (auto &c : chunks) {2320auto sc = dyn_cast<SectionChunk>(c);2321log(" " + sc->file->mb.getBufferIdentifier().str() +2322", SectionID: " + Twine(sc->getSectionNumber()));2323}2324}2325}23262327OutputSection *Writer::findSection(StringRef name) {2328for (OutputSection *sec : ctx.outputSections)2329if (sec->name == name)2330return sec;2331return nullptr;2332}23332334uint32_t Writer::getSizeOfInitializedData() {2335uint32_t res = 0;2336for (OutputSection *s : ctx.outputSections)2337if (s->header.Characteristics & IMAGE_SCN_CNT_INITIALIZED_DATA)2338res += s->getRawSize();2339return res;2340}23412342// Add base relocations to .reloc section.2343void Writer::addBaserels() {2344if (!ctx.config.relocatable)2345return;2346relocSec->chunks.clear();2347std::vector<Baserel> v;2348for (OutputSection *sec : ctx.outputSections) {2349if (sec->header.Characteristics & IMAGE_SCN_MEM_DISCARDABLE)2350continue;2351llvm::TimeTraceScope timeScope("Base relocations: ", sec->name);2352// Collect all locations for base relocations.2353for (Chunk *c : sec->chunks)2354c->getBaserels(&v);2355// Add the addresses to .reloc section.2356if (!v.empty())2357addBaserelBlocks(v);2358v.clear();2359}2360}23612362// Add addresses to .reloc section. Note that addresses are grouped by page.2363void Writer::addBaserelBlocks(std::vector<Baserel> &v) {2364const uint32_t mask = ~uint32_t(pageSize - 1);2365uint32_t page = v[0].rva & mask;2366size_t i = 0, j = 1;2367for (size_t e = v.size(); j < e; ++j) {2368uint32_t p = v[j].rva & mask;2369if (p == page)2370continue;2371relocSec->addChunk(make<BaserelChunk>(page, &v[i], &v[0] + j));2372i = j;2373page = p;2374}2375if (i == j)2376return;2377relocSec->addChunk(make<BaserelChunk>(page, &v[i], &v[0] + j));2378}23792380PartialSection *Writer::createPartialSection(StringRef name,2381uint32_t outChars) {2382PartialSection *&pSec = partialSections[{name, outChars}];2383if (pSec)2384return pSec;2385pSec = make<PartialSection>(name, outChars);2386return pSec;2387}23882389PartialSection *Writer::findPartialSection(StringRef name, uint32_t outChars) {2390auto it = partialSections.find({name, outChars});2391if (it != partialSections.end())2392return it->second;2393return nullptr;2394}23952396void Writer::fixTlsAlignment() {2397Defined *tlsSym =2398dyn_cast_or_null<Defined>(ctx.symtab.findUnderscore("_tls_used"));2399if (!tlsSym)2400return;24012402OutputSection *sec = ctx.getOutputSection(tlsSym->getChunk());2403assert(sec && tlsSym->getRVA() >= sec->getRVA() &&2404"no output section for _tls_used");24052406uint8_t *secBuf = buffer->getBufferStart() + sec->getFileOff();2407uint64_t tlsOffset = tlsSym->getRVA() - sec->getRVA();2408uint64_t directorySize = ctx.config.is64()2409? sizeof(object::coff_tls_directory64)2410: sizeof(object::coff_tls_directory32);24112412if (tlsOffset + directorySize > sec->getRawSize())2413fatal("_tls_used sym is malformed");24142415if (ctx.config.is64()) {2416object::coff_tls_directory64 *tlsDir =2417reinterpret_cast<object::coff_tls_directory64 *>(&secBuf[tlsOffset]);2418tlsDir->setAlignment(tlsAlignment);2419} else {2420object::coff_tls_directory32 *tlsDir =2421reinterpret_cast<object::coff_tls_directory32 *>(&secBuf[tlsOffset]);2422tlsDir->setAlignment(tlsAlignment);2423}2424}24252426void Writer::prepareLoadConfig() {2427Symbol *sym = ctx.symtab.findUnderscore("_load_config_used");2428auto *b = cast_if_present<DefinedRegular>(sym);2429if (!b) {2430if (ctx.config.guardCF != GuardCFLevel::Off)2431warn("Control Flow Guard is enabled but '_load_config_used' is missing");2432return;2433}24342435OutputSection *sec = ctx.getOutputSection(b->getChunk());2436uint8_t *buf = buffer->getBufferStart();2437uint8_t *secBuf = buf + sec->getFileOff();2438uint8_t *symBuf = secBuf + (b->getRVA() - sec->getRVA());2439uint32_t expectedAlign = ctx.config.is64() ? 8 : 4;2440if (b->getChunk()->getAlignment() < expectedAlign)2441warn("'_load_config_used' is misaligned (expected alignment to be " +2442Twine(expectedAlign) + " bytes, got " +2443Twine(b->getChunk()->getAlignment()) + " instead)");2444else if (!isAligned(Align(expectedAlign), b->getRVA()))2445warn("'_load_config_used' is misaligned (RVA is 0x" +2446Twine::utohexstr(b->getRVA()) + " not aligned to " +2447Twine(expectedAlign) + " bytes)");24482449if (ctx.config.is64())2450prepareLoadConfig(reinterpret_cast<coff_load_configuration64 *>(symBuf));2451else2452prepareLoadConfig(reinterpret_cast<coff_load_configuration32 *>(symBuf));2453}24542455template <typename T> void Writer::prepareLoadConfig(T *loadConfig) {2456if (ctx.config.dependentLoadFlags)2457loadConfig->DependentLoadFlags = ctx.config.dependentLoadFlags;24582459checkLoadConfigGuardData(loadConfig);2460}24612462template <typename T>2463void Writer::checkLoadConfigGuardData(const T *loadConfig) {2464size_t loadConfigSize = loadConfig->Size;24652466#define RETURN_IF_NOT_CONTAINS(field) \2467if (loadConfigSize < offsetof(T, field) + sizeof(T::field)) { \2468warn("'_load_config_used' structure too small to include " #field); \2469return; \2470}24712472#define IF_CONTAINS(field) \2473if (loadConfigSize >= offsetof(T, field) + sizeof(T::field))24742475#define CHECK_VA(field, sym) \2476if (auto *s = dyn_cast<DefinedSynthetic>(ctx.symtab.findUnderscore(sym))) \2477if (loadConfig->field != ctx.config.imageBase + s->getRVA()) \2478warn(#field " not set correctly in '_load_config_used'");24792480#define CHECK_ABSOLUTE(field, sym) \2481if (auto *s = dyn_cast<DefinedAbsolute>(ctx.symtab.findUnderscore(sym))) \2482if (loadConfig->field != s->getVA()) \2483warn(#field " not set correctly in '_load_config_used'");24842485if (ctx.config.guardCF == GuardCFLevel::Off)2486return;2487RETURN_IF_NOT_CONTAINS(GuardFlags)2488CHECK_VA(GuardCFFunctionTable, "__guard_fids_table")2489CHECK_ABSOLUTE(GuardCFFunctionCount, "__guard_fids_count")2490CHECK_ABSOLUTE(GuardFlags, "__guard_flags")2491IF_CONTAINS(GuardAddressTakenIatEntryCount) {2492CHECK_VA(GuardAddressTakenIatEntryTable, "__guard_iat_table")2493CHECK_ABSOLUTE(GuardAddressTakenIatEntryCount, "__guard_iat_count")2494}24952496if (!(ctx.config.guardCF & GuardCFLevel::LongJmp))2497return;2498RETURN_IF_NOT_CONTAINS(GuardLongJumpTargetCount)2499CHECK_VA(GuardLongJumpTargetTable, "__guard_longjmp_table")2500CHECK_ABSOLUTE(GuardLongJumpTargetCount, "__guard_longjmp_count")25012502if (!(ctx.config.guardCF & GuardCFLevel::EHCont))2503return;2504RETURN_IF_NOT_CONTAINS(GuardEHContinuationCount)2505CHECK_VA(GuardEHContinuationTable, "__guard_eh_cont_table")2506CHECK_ABSOLUTE(GuardEHContinuationCount, "__guard_eh_cont_count")25072508#undef RETURN_IF_NOT_CONTAINS2509#undef IF_CONTAINS2510#undef CHECK_VA2511#undef CHECK_ABSOLUTE2512}251325142515