brintos

brintos / llvm-project-archived public Read only

0
0
Text · 112.8 KiB · 3ac2668 Raw
3107 lines · cpp
1//===- Writer.cpp ---------------------------------------------------------===//2//3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.4// See https://llvm.org/LICENSE.txt for license information.5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception6//7//===----------------------------------------------------------------------===//8 9#include "Writer.h"10#include "COFFLinkerContext.h"11#include "CallGraphSort.h"12#include "Config.h"13#include "DLL.h"14#include "InputFiles.h"15#include "LLDMapFile.h"16#include "MapFile.h"17#include "PDB.h"18#include "SymbolTable.h"19#include "Symbols.h"20#include "lld/Common/ErrorHandler.h"21#include "lld/Common/Memory.h"22#include "lld/Common/Timer.h"23#include "llvm/ADT/DenseMap.h"24#include "llvm/ADT/STLExtras.h"25#include "llvm/ADT/StringSet.h"26#include "llvm/BinaryFormat/COFF.h"27#include "llvm/MC/StringTableBuilder.h"28#include "llvm/Support/Endian.h"29#include "llvm/Support/FileOutputBuffer.h"30#include "llvm/Support/FormatAdapters.h"31#include "llvm/Support/FormatVariadic.h"32#include "llvm/Support/Parallel.h"33#include "llvm/Support/RandomNumberGenerator.h"34#include "llvm/Support/TimeProfiler.h"35#include "llvm/Support/xxhash.h"36#include <algorithm>37#include <cstdio>38#include <map>39#include <memory>40#include <utility>41 42using namespace llvm;43using namespace llvm::COFF;44using namespace llvm::object;45using namespace llvm::support;46using namespace llvm::support::endian;47using namespace lld;48using namespace lld::coff;49 50/* To re-generate DOSProgram:51$ cat > /tmp/DOSProgram.asm52org 053        ; Copy cs to ds.54        push cs55        pop ds56        ; Point ds:dx at the $-terminated string.57        mov dx, str58        ; Int 21/AH=09h: Write string to standard output.59        mov ah, 0x960        int 0x2161        ; Int 21/AH=4Ch: Exit with return code (in AL).62        mov ax, 0x4C0163        int 0x2164str:65        db 'This program cannot be run in DOS mode.$'66align 8, db 067$ nasm -fbin /tmp/DOSProgram.asm -o /tmp/DOSProgram.bin68$ xxd -i /tmp/DOSProgram.bin69*/70static unsigned char dosProgram[] = {71  0x0e, 0x1f, 0xba, 0x0e, 0x00, 0xb4, 0x09, 0xcd, 0x21, 0xb8, 0x01, 0x4c,72  0xcd, 0x21, 0x54, 0x68, 0x69, 0x73, 0x20, 0x70, 0x72, 0x6f, 0x67, 0x72,73  0x61, 0x6d, 0x20, 0x63, 0x61, 0x6e, 0x6e, 0x6f, 0x74, 0x20, 0x62, 0x65,74  0x20, 0x72, 0x75, 0x6e, 0x20, 0x69, 0x6e, 0x20, 0x44, 0x4f, 0x53, 0x20,75  0x6d, 0x6f, 0x64, 0x65, 0x2e, 0x24, 0x00, 0x0076};77static_assert(sizeof(dosProgram) % 8 == 0,78              "DOSProgram size must be multiple of 8");79static_assert((sizeof(dos_header) + sizeof(dosProgram)) % 8 == 0,80              "DOSStub size must be multiple of 8");81 82static const int numberOfDataDirectory = 16;83 84namespace {85 86class DebugDirectoryChunk : public NonSectionChunk {87public:88  DebugDirectoryChunk(const COFFLinkerContext &c,89                      const std::vector<std::pair<COFF::DebugType, Chunk *>> &r,90                      bool writeRepro)91      : records(r), writeRepro(writeRepro), ctx(c) {}92 93  size_t getSize() const override {94    return (records.size() + int(writeRepro)) * sizeof(debug_directory);95  }96 97  void writeTo(uint8_t *b) const override {98    auto *d = reinterpret_cast<debug_directory *>(b);99 100    for (const std::pair<COFF::DebugType, Chunk *>& record : records) {101      Chunk *c = record.second;102      const OutputSection *os = ctx.getOutputSection(c);103      uint64_t offs = os->getFileOff() + (c->getRVA() - os->getRVA());104      fillEntry(d, record.first, c->getSize(), c->getRVA(), offs);105      ++d;106    }107 108    if (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.114      fillEntry(d, COFF::IMAGE_DEBUG_TYPE_REPRO, 0, 0, 0);115    }116  }117 118  void setTimeDateStamp(uint32_t timeDateStamp) {119    for (support::ulittle32_t *tds : timeDateStamps)120      *tds = timeDateStamp;121  }122 123private:124  void fillEntry(debug_directory *d, COFF::DebugType debugType, size_t size,125                 uint64_t rva, uint64_t offs) const {126    d->Characteristics = 0;127    d->TimeDateStamp = 0;128    d->MajorVersion = 0;129    d->MinorVersion = 0;130    d->Type = debugType;131    d->SizeOfData = size;132    d->AddressOfRawData = rva;133    d->PointerToRawData = offs;134 135    timeDateStamps.push_back(&d->TimeDateStamp);136  }137 138  mutable std::vector<support::ulittle32_t *> timeDateStamps;139  const std::vector<std::pair<COFF::DebugType, Chunk *>> &records;140  bool writeRepro;141  const COFFLinkerContext &ctx;142};143 144class CVDebugRecordChunk : public NonSectionChunk {145public:146  CVDebugRecordChunk(const COFFLinkerContext &c) : ctx(c) {}147 148  size_t getSize() const override {149    return sizeof(codeview::DebugInfo) + ctx.config.pdbAltPath.size() + 1;150  }151 152  void writeTo(uint8_t *b) const override {153    // Save off the DebugInfo entry to backfill the file signature (build id)154    // in Writer::writeBuildId155    buildId = reinterpret_cast<codeview::DebugInfo *>(b);156 157    // variable sized field (PDB Path)158    char *p = reinterpret_cast<char *>(b + sizeof(*buildId));159    if (!ctx.config.pdbAltPath.empty())160      memcpy(p, ctx.config.pdbAltPath.data(), ctx.config.pdbAltPath.size());161    p[ctx.config.pdbAltPath.size()] = '\0';162  }163 164  mutable codeview::DebugInfo *buildId = nullptr;165 166private:167  const COFFLinkerContext &ctx;168};169 170class ExtendedDllCharacteristicsChunk : public NonSectionChunk {171public:172  ExtendedDllCharacteristicsChunk(uint32_t c) : characteristics(c) {}173 174  size_t getSize() const override { return 4; }175 176  void writeTo(uint8_t *buf) const override { write32le(buf, characteristics); }177 178  uint32_t characteristics = 0;179};180 181// 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:186  StringRef name;187  unsigned characteristics;188 189  bool operator<(const PartialSectionKey &other) const {190    int c = name.compare(other.name);191    if (c > 0)192      return false;193    if (c == 0)194      return characteristics < other.characteristics;195    return true;196  }197};198 199struct ChunkRange {200  Chunk *first = nullptr, *last;201};202 203// The writer writes a SymbolTable result to a file.204class Writer {205public:206  Writer(COFFLinkerContext &c)207      : buffer(c.e.outputBuffer), strtab(StringTableBuilder::WinCOFF),208        delayIdata(c), ctx(c) {}209  void run();210 211private:212  void calculateStubDependentSizes();213  void createSections();214  void createMiscChunks();215  void createImportTables();216  void appendImportThunks();217  void locateImportTables();218  void createExportTable();219  void mergeSection(const std::map<StringRef, StringRef>::value_type &p);220  void mergeSections();221  void sortECChunks();222  void appendECImportTables();223  void removeUnusedSections();224  void layoutSections();225  void assignAddresses();226  bool isInRange(uint16_t relType, uint64_t s, uint64_t p, int margin,227                 MachineTypes machine);228  std::pair<Defined *, bool> getThunk(DenseMap<uint64_t, Defined *> &lastThunks,229                                      Defined *target, uint64_t p,230                                      uint16_t type, int margin,231                                      MachineTypes machine);232  bool createThunks(OutputSection *os, int margin);233  bool verifyRanges(const std::vector<Chunk *> chunks);234  void createECCodeMap();235  void finalizeAddresses();236  void removeEmptySections();237  void assignOutputSectionIndices();238  void createSymbolAndStringTable();239  void openFile(StringRef outputPath);240  template <typename PEHeaderTy> void writeHeader();241  void createSEHTable();242  void createRuntimePseudoRelocs();243  void createECChunks();244  void insertCtorDtorSymbols();245  void insertBssDataStartEndSymbols();246  void markSymbolsWithRelocations(ObjFile *file, SymbolRVASet &usedSymbols);247  void createGuardCFTables();248  void markSymbolsForRVATable(ObjFile *file,249                              ArrayRef<SectionChunk *> symIdxChunks,250                              SymbolRVASet &tableSymbols);251  void getSymbolsFromSections(ObjFile *file,252                              ArrayRef<SectionChunk *> symIdxChunks,253                              std::vector<Symbol *> &symbols);254  void maybeAddRVATable(SymbolRVASet tableSymbols, StringRef tableSym,255                        StringRef countSym, bool hasFlag=false);256  void setSectionPermissions();257  void setECSymbols();258  void writeSections();259  void writeBuildId();260  void writePEChecksum();261  void sortSections();262  template <typename T> void sortExceptionTable(ChunkRange &exceptionTable);263  void sortExceptionTables();264  void sortCRTSectionChunks(std::vector<Chunk *> &chunks);265  void addSyntheticIdata();266  void sortBySectionOrder(std::vector<Chunk *> &chunks);267  void fixPartialSectionChars(StringRef name, uint32_t chars);268  bool fixGnuImportChunks();269  void fixTlsAlignment();270  PartialSection *createPartialSection(StringRef name, uint32_t outChars);271  PartialSection *findPartialSection(StringRef name, uint32_t outChars);272 273  std::optional<coff_symbol16> createSymbol(Defined *d);274  size_t addEntryToStringTable(StringRef str);275 276  OutputSection *findSection(StringRef name);277  void addBaserels();278  void addBaserelBlocks(std::vector<Baserel> &v);279  void createDynamicRelocs();280 281  uint32_t getSizeOfInitializedData();282 283  void prepareLoadConfig();284  template <typename T>285  void prepareLoadConfig(SymbolTable &symtab, T *loadConfig);286 287  void printSummary();288 289  std::unique_ptr<FileOutputBuffer> &buffer;290  std::map<PartialSectionKey, PartialSection *> partialSections;291  StringTableBuilder strtab;292  std::vector<llvm::object::coff_symbol16> outputSymtab;293  std::vector<ECCodeMapEntry> codeMap;294  IdataContents idata;295  Chunk *importTableStart = nullptr;296  uint64_t importTableSize = 0;297  Chunk *iatStart = nullptr;298  uint64_t iatSize = 0;299  DelayLoadContents delayIdata;300  bool setNoSEHCharacteristic = false;301  uint32_t tlsAlignment = 0;302 303  DebugDirectoryChunk *debugDirectory = nullptr;304  std::vector<std::pair<COFF::DebugType, Chunk *>> debugRecords;305  CVDebugRecordChunk *buildId = nullptr;306  ArrayRef<uint8_t> sectionTable;307 308  // List of Arm64EC export thunks.309  std::vector<std::pair<Chunk *, Defined *>> exportThunks;310 311  uint64_t fileSize;312  uint32_t pointerToSymbolTable = 0;313  uint64_t sizeOfImage;314  uint64_t sizeOfHeaders;315 316  uint32_t dosStubSize;317  uint32_t coffHeaderOffset;318  uint32_t peHeaderOffset;319  uint32_t dataDirOffset64;320 321  OutputSection *textSec;322  OutputSection *wowthkSec;323  OutputSection *hexpthkSec;324  OutputSection *bssSec;325  OutputSection *rdataSec;326  OutputSection *buildidSec;327  OutputSection *cvinfoSec;328  OutputSection *dataSec;329  OutputSection *pdataSec;330  OutputSection *idataSec;331  OutputSection *edataSec;332  OutputSection *didatSec;333  OutputSection *a64xrmSec;334  OutputSection *rsrcSec;335  OutputSection *relocSec;336  OutputSection *ctorsSec;337  OutputSection *dtorsSec;338  // Either .rdata section or .buildid section.339  OutputSection *debugInfoSec;340 341  // The range of .pdata sections in the output file.342  //343  // We need to keep track of the location of .pdata in whichever section it344  // gets merged into so that we can sort its contents and emit a correct data345  // directory entry for the exception table. This is also the case for some346  // other sections (such as .edata) but because the contents of those sections347  // are entirely linker-generated we can keep track of their locations using348  // the chunks that the linker creates. All .pdata chunks come from input349  // files, so we need to keep track of them separately.350  ChunkRange pdata;351 352  // x86_64 .pdata sections on ARM64EC/ARM64X targets.353  ChunkRange hybridPdata;354 355  // CHPE metadata symbol on ARM64C target.356  DefinedRegular *chpeSym = nullptr;357 358  COFFLinkerContext &ctx;359};360} // anonymous namespace361 362void lld::coff::writeResult(COFFLinkerContext &ctx) {363  llvm::TimeTraceScope timeScope("Write output(s)");364  Writer(ctx).run();365}366 367void OutputSection::addChunk(Chunk *c) {368  chunks.push_back(c);369}370 371void OutputSection::insertChunkAtStart(Chunk *c) {372  chunks.insert(chunks.begin(), c);373}374 375void OutputSection::setPermissions(uint32_t c) {376  header.Characteristics &= ~permMask;377  header.Characteristics |= c;378}379 380void OutputSection::merge(OutputSection *other) {381  chunks.insert(chunks.end(), other->chunks.begin(), other->chunks.end());382  other->chunks.clear();383  contribSections.insert(contribSections.end(), other->contribSections.begin(),384                         other->contribSections.end());385  other->contribSections.clear();386 387  // MS link.exe compatibility: when merging a code section into a data section,388  // mark the target section as a code section.389  if (other->header.Characteristics & IMAGE_SCN_CNT_CODE) {390    header.Characteristics |= IMAGE_SCN_CNT_CODE;391    header.Characteristics &=392        ~(IMAGE_SCN_CNT_INITIALIZED_DATA | IMAGE_SCN_CNT_UNINITIALIZED_DATA);393  }394}395 396// Write the section header to a given buffer.397void OutputSection::writeHeaderTo(uint8_t *buf, bool isDebug) {398  auto *hdr = reinterpret_cast<coff_section *>(buf);399  *hdr = header;400  if (stringTableOff) {401    // If name is too long, write offset into the string table as a name.402    encodeSectionName(hdr->Name, stringTableOff);403  } else {404    assert(!isDebug || name.size() <= COFF::NameSize ||405           (hdr->Characteristics & IMAGE_SCN_MEM_DISCARDABLE) == 0);406    strncpy(hdr->Name, name.data(),407            std::min(name.size(), (size_t)COFF::NameSize));408  }409}410 411void OutputSection::addContributingPartialSection(PartialSection *sec) {412  contribSections.push_back(sec);413}414 415void OutputSection::splitECChunks() {416  llvm::stable_sort(chunks, [=](const Chunk *a, const Chunk *b) {417    return (a->getMachine() != ARM64) < (b->getMachine() != ARM64);418  });419}420 421// Check whether the target address S is in range from a relocation422// of type relType at address P.423bool Writer::isInRange(uint16_t relType, uint64_t s, uint64_t p, int margin,424                       MachineTypes machine) {425  if (machine == ARMNT) {426    int64_t diff = AbsoluteDifference(s, p + 4) + margin;427    switch (relType) {428    case IMAGE_REL_ARM_BRANCH20T:429      return isInt<21>(diff);430    case IMAGE_REL_ARM_BRANCH24T:431    case IMAGE_REL_ARM_BLX23T:432      return isInt<25>(diff);433    default:434      return true;435    }436  } else if (isAnyArm64(machine)) {437    int64_t diff = AbsoluteDifference(s, p) + margin;438    switch (relType) {439    case IMAGE_REL_ARM64_BRANCH26:440      return isInt<28>(diff);441    case IMAGE_REL_ARM64_BRANCH19:442      return isInt<21>(diff);443    case IMAGE_REL_ARM64_BRANCH14:444      return isInt<16>(diff);445    default:446      return true;447    }448  } else {449    return true;450  }451}452 453// Return the last thunk for the given target if it is in range,454// or create a new one.455std::pair<Defined *, bool>456Writer::getThunk(DenseMap<uint64_t, Defined *> &lastThunks, Defined *target,457                 uint64_t p, uint16_t type, int margin, MachineTypes machine) {458  Defined *&lastThunk = lastThunks[target->getRVA()];459  if (lastThunk && isInRange(type, lastThunk->getRVA(), p, margin, machine))460    return {lastThunk, false};461  Chunk *c;462  switch (getMachineArchType(machine)) {463  case Triple::thumb:464    c = make<RangeExtensionThunkARM>(ctx, target);465    break;466  case Triple::aarch64:467    c = make<RangeExtensionThunkARM64>(machine, target);468    break;469  default:470    llvm_unreachable("Unexpected architecture");471  }472  Defined *d = make<DefinedSynthetic>("range_extension_thunk", c);473  lastThunk = d;474  return {d, true};475}476 477// This checks all relocations, and for any relocation which isn't in range478// it adds a thunk after the section chunk that contains the relocation.479// If the latest thunk for the specific target is in range, that is used480// instead of creating a new thunk. All range checks are done with the481// specified margin, to make sure that relocations that originally are in482// range, but only barely, also get thunks - in case other added thunks makes483// the target go out of range.484//485// After adding thunks, we verify that all relocations are in range (with486// no extra margin requirements). If this failed, we restart (throwing away487// the previously created thunks) and retry with a wider margin.488bool Writer::createThunks(OutputSection *os, int margin) {489  bool addressesChanged = false;490  DenseMap<uint64_t, Defined *> lastThunks;491  DenseMap<std::pair<ObjFile *, Defined *>, uint32_t> thunkSymtabIndices;492  size_t thunksSize = 0;493  // Recheck Chunks.size() each iteration, since we can insert more494  // elements into it.495  for (size_t i = 0; i != os->chunks.size(); ++i) {496    SectionChunk *sc = dyn_cast<SectionChunk>(os->chunks[i]);497    if (!sc) {498      auto chunk = cast<NonSectionChunk>(os->chunks[i]);499      if (uint32_t size = chunk->extendRanges()) {500        thunksSize += size;501        addressesChanged = true;502      }503      continue;504    }505    MachineTypes machine = sc->getMachine();506    size_t thunkInsertionSpot = i + 1;507 508    // Try to get a good enough estimate of where new thunks will be placed.509    // Offset this by the size of the new thunks added so far, to make the510    // estimate slightly better.511    size_t thunkInsertionRVA = sc->getRVA() + sc->getSize() + thunksSize;512    ObjFile *file = sc->file;513    std::vector<std::pair<uint32_t, uint32_t>> relocReplacements;514    ArrayRef<coff_relocation> originalRelocs =515        file->getCOFFObj()->getRelocations(sc->header);516    for (size_t j = 0, e = originalRelocs.size(); j < e; ++j) {517      const coff_relocation &rel = originalRelocs[j];518      Symbol *relocTarget = file->getSymbol(rel.SymbolTableIndex);519 520      // The estimate of the source address P should be pretty accurate,521      // but we don't know whether the target Symbol address should be522      // offset by thunksSize or not (or by some of thunksSize but not all of523      // it), giving us some uncertainty once we have added one thunk.524      uint64_t p = sc->getRVA() + rel.VirtualAddress + thunksSize;525 526      Defined *sym = dyn_cast_or_null<Defined>(relocTarget);527      if (!sym)528        continue;529 530      uint64_t s = sym->getRVA();531 532      if (isInRange(rel.Type, s, p, margin, machine))533        continue;534 535      // If the target isn't in range, hook it up to an existing or new thunk.536      auto [thunk, wasNew] =537          getThunk(lastThunks, sym, p, rel.Type, margin, machine);538      if (wasNew) {539        Chunk *thunkChunk = thunk->getChunk();540        thunkChunk->setRVA(541            thunkInsertionRVA); // Estimate of where it will be located.542        os->chunks.insert(os->chunks.begin() + thunkInsertionSpot, thunkChunk);543        thunkInsertionSpot++;544        thunksSize += thunkChunk->getSize();545        thunkInsertionRVA += thunkChunk->getSize();546        addressesChanged = true;547      }548 549      // To redirect the relocation, add a symbol to the parent object file's550      // symbol table, and replace the relocation symbol table index with the551      // new index.552      auto insertion = thunkSymtabIndices.insert({{file, thunk}, ~0U});553      uint32_t &thunkSymbolIndex = insertion.first->second;554      if (insertion.second)555        thunkSymbolIndex = file->addRangeThunkSymbol(thunk);556      relocReplacements.emplace_back(j, thunkSymbolIndex);557    }558 559    // Get a writable copy of this section's relocations so they can be560    // modified. If the relocations point into the object file, allocate new561    // memory. Otherwise, this must be previously allocated memory that can be562    // modified in place.563    ArrayRef<coff_relocation> curRelocs = sc->getRelocs();564    MutableArrayRef<coff_relocation> newRelocs;565    if (originalRelocs.data() == curRelocs.data()) {566      newRelocs = MutableArrayRef(567          bAlloc().Allocate<coff_relocation>(originalRelocs.size()),568          originalRelocs.size());569    } else {570      newRelocs = MutableArrayRef(571          const_cast<coff_relocation *>(curRelocs.data()), curRelocs.size());572    }573 574    // Copy each relocation, but replace the symbol table indices which need575    // thunks.576    auto nextReplacement = relocReplacements.begin();577    auto endReplacement = relocReplacements.end();578    for (size_t i = 0, e = originalRelocs.size(); i != e; ++i) {579      newRelocs[i] = originalRelocs[i];580      if (nextReplacement != endReplacement && nextReplacement->first == i) {581        newRelocs[i].SymbolTableIndex = nextReplacement->second;582        ++nextReplacement;583      }584    }585 586    sc->setRelocs(newRelocs);587  }588  return addressesChanged;589}590 591// Create a code map for CHPE metadata.592void Writer::createECCodeMap() {593  if (!ctx.symtab.isEC())594    return;595 596  // Clear the map in case we were're recomputing the map after adding597  // a range extension thunk.598  codeMap.clear();599 600  std::optional<chpe_range_type> lastType;601  Chunk *first, *last;602 603  auto closeRange = [&]() {604    if (lastType) {605      codeMap.push_back({first, last, *lastType});606      lastType.reset();607    }608  };609 610  for (OutputSection *sec : ctx.outputSections) {611    for (Chunk *c : sec->chunks) {612      // Skip empty section chunks. MS link.exe does not seem to do that and613      // generates empty code ranges in some cases.614      if (isa<SectionChunk>(c) && !c->getSize())615        continue;616 617      std::optional<chpe_range_type> chunkType = c->getArm64ECRangeType();618      if (chunkType != lastType) {619        closeRange();620        first = c;621        lastType = chunkType;622      }623      last = c;624    }625  }626 627  closeRange();628 629  Symbol *tableCountSym = ctx.symtab.findUnderscore("__hybrid_code_map_count");630  cast<DefinedAbsolute>(tableCountSym)->setVA(codeMap.size());631}632 633// Verify that all relocations are in range, with no extra margin requirements.634bool Writer::verifyRanges(const std::vector<Chunk *> chunks) {635  for (Chunk *c : chunks) {636    SectionChunk *sc = dyn_cast<SectionChunk>(c);637    if (!sc) {638      if (!cast<NonSectionChunk>(c)->verifyRanges())639        return false;640      continue;641    }642    MachineTypes machine = sc->getMachine();643 644    ArrayRef<coff_relocation> relocs = sc->getRelocs();645    for (const coff_relocation &rel : relocs) {646      Symbol *relocTarget = sc->file->getSymbol(rel.SymbolTableIndex);647 648      Defined *sym = dyn_cast_or_null<Defined>(relocTarget);649      if (!sym)650        continue;651 652      uint64_t p = sc->getRVA() + rel.VirtualAddress;653      uint64_t s = sym->getRVA();654 655      if (!isInRange(rel.Type, s, p, 0, machine))656        return false;657    }658  }659  return true;660}661 662// Assign addresses and add thunks if necessary.663void Writer::finalizeAddresses() {664  assignAddresses();665  if (ctx.config.machine != ARMNT && !isAnyArm64(ctx.config.machine))666    return;667 668  size_t origNumChunks = 0;669  for (OutputSection *sec : ctx.outputSections) {670    sec->origChunks = sec->chunks;671    origNumChunks += sec->chunks.size();672  }673 674  int pass = 0;675  int margin = 1024 * 100;676  while (true) {677    llvm::TimeTraceScope timeScope2("Add thunks pass");678 679    // First check whether we need thunks at all, or if the previous pass of680    // adding them turned out ok.681    bool rangesOk = true;682    size_t numChunks = 0;683    {684      llvm::TimeTraceScope timeScope3("Verify ranges");685      for (OutputSection *sec : ctx.outputSections) {686        if (!verifyRanges(sec->chunks)) {687          rangesOk = false;688          break;689        }690        numChunks += sec->chunks.size();691      }692    }693    if (rangesOk) {694      if (pass > 0)695        Log(ctx) << "Added " << (numChunks - origNumChunks) << " thunks with "696                 << "margin " << margin << " in " << pass << " passes";697      return;698    }699 700    if (pass >= 10)701      Fatal(ctx) << "adding thunks hasn't converged after " << pass702                 << " passes";703 704    if (pass > 0) {705      // If the previous pass didn't work out, reset everything back to the706      // original conditions before retrying with a wider margin. This should707      // ideally never happen under real circumstances.708      for (OutputSection *sec : ctx.outputSections)709        sec->chunks = sec->origChunks;710      margin *= 2;711    }712 713    // Try adding thunks everywhere where it is needed, with a margin714    // to avoid things going out of range due to the added thunks.715    bool addressesChanged = false;716    {717      llvm::TimeTraceScope timeScope3("Create thunks");718      for (OutputSection *sec : ctx.outputSections)719        addressesChanged |= createThunks(sec, margin);720    }721    // If the verification above thought we needed thunks, we should have722    // added some.723    assert(addressesChanged);724    (void)addressesChanged;725 726    // Recalculate the layout for the whole image (and verify the ranges at727    // the start of the next round).728    assignAddresses();729 730    pass++;731  }732}733 734void Writer::writePEChecksum() {735  if (!ctx.config.writeCheckSum) {736    return;737  }738 739  llvm::TimeTraceScope timeScope("PE checksum");740 741  // https://docs.microsoft.com/en-us/windows/win32/debug/pe-format#checksum742  uint32_t *buf = (uint32_t *)buffer->getBufferStart();743  uint32_t size = (uint32_t)(buffer->getBufferSize());744 745  pe32_header *peHeader = (pe32_header *)((uint8_t *)buf + coffHeaderOffset +746                                          sizeof(coff_file_header));747 748  uint64_t sum = 0;749  uint32_t count = size;750  ulittle16_t *addr = (ulittle16_t *)buf;751 752  // The PE checksum algorithm, implemented as suggested in RFC1071753  while (count > 1) {754    sum += *addr++;755    count -= 2;756  }757 758  // Add left-over byte, if any759  if (count > 0)760    sum += *(unsigned char *)addr;761 762  // Fold 32-bit sum to 16 bits763  while (sum >> 16) {764    sum = (sum & 0xffff) + (sum >> 16);765  }766 767  sum += size;768  peHeader->CheckSum = sum;769}770 771// The main function of the writer.772void Writer::run() {773  {774    llvm::TimeTraceScope timeScope("Write PE");775    ScopedTimer t1(ctx.codeLayoutTimer);776 777    calculateStubDependentSizes();778    if (ctx.config.machine == ARM64X)779      ctx.dynamicRelocs = make<DynamicRelocsChunk>();780    createImportTables();781    createSections();782    appendImportThunks();783    // Import thunks must be added before the Control Flow Guard tables are784    // added.785    createMiscChunks();786    createExportTable();787    mergeSections();788    sortECChunks();789    appendECImportTables();790    createDynamicRelocs();791    removeUnusedSections();792    layoutSections();793    finalizeAddresses();794    removeEmptySections();795    assignOutputSectionIndices();796    setSectionPermissions();797    setECSymbols();798    createSymbolAndStringTable();799 800    if (fileSize > UINT32_MAX)801      Fatal(ctx) << "image size (" << fileSize << ") "802                 << "exceeds maximum allowable size (" << UINT32_MAX << ")";803 804    openFile(ctx.config.outputFile);805    if (ctx.config.is64()) {806      writeHeader<pe32plus_header>();807    } else {808      writeHeader<pe32_header>();809    }810    writeSections();811    prepareLoadConfig();812    sortExceptionTables();813 814    // Fix up the alignment in the TLS Directory's characteristic field,815    // if a specific alignment value is needed816    if (tlsAlignment)817      fixTlsAlignment();818  }819 820  if (!ctx.config.pdbPath.empty() && ctx.config.debug) {821    assert(buildId);822    createPDB(ctx, sectionTable, buildId->buildId);823  }824  writeBuildId();825 826  writeLLDMapFile(ctx);827  writeMapFile(ctx);828 829  writePEChecksum();830 831  printSummary();832 833  if (errorCount())834    return;835 836  llvm::TimeTraceScope timeScope("Commit PE to disk");837  ScopedTimer t2(ctx.outputCommitTimer);838  if (auto e = buffer->commit())839    Fatal(ctx) << "failed to write output '" << buffer->getPath()840               << "': " << toString(std::move(e));841}842 843static StringRef getOutputSectionName(StringRef name) {844  StringRef s = name.split('$').first;845 846  // Treat a later period as a separator for MinGW, for sections like847  // ".ctors.01234".848  return s.substr(0, s.find('.', 1));849}850 851// For /order.852void Writer::sortBySectionOrder(std::vector<Chunk *> &chunks) {853  auto getPriority = [&ctx = ctx](const Chunk *c) {854    if (auto *sec = dyn_cast<SectionChunk>(c))855      if (sec->sym)856        return ctx.config.order.lookup(sec->sym->getName());857    return 0;858  };859 860  llvm::stable_sort(chunks, [=](const Chunk *a, const Chunk *b) {861    return getPriority(a) < getPriority(b);862  });863}864 865// Change the characteristics of existing PartialSections that belong to the866// section Name to Chars.867void Writer::fixPartialSectionChars(StringRef name, uint32_t chars) {868  for (auto it : partialSections) {869    PartialSection *pSec = it.second;870    StringRef curName = pSec->name;871    if (!curName.consume_front(name) ||872        (!curName.empty() && !curName.starts_with("$")))873      continue;874    if (pSec->characteristics == chars)875      continue;876    PartialSection *destSec = createPartialSection(pSec->name, chars);877    destSec->chunks.insert(destSec->chunks.end(), pSec->chunks.begin(),878                           pSec->chunks.end());879    pSec->chunks.clear();880  }881}882 883// Sort concrete section chunks from GNU import libraries.884//885// GNU binutils doesn't use short import files, but instead produces import886// libraries that consist of object files, with section chunks for the .idata$*887// sections. These are linked just as regular static libraries. Each import888// library consists of one header object, one object file for every imported889// symbol, and one trailer object. In order for the .idata tables/lists to890// be formed correctly, the section chunks within each .idata$* section need891// to be grouped by library, and sorted alphabetically within each library892// (which makes sure the header comes first and the trailer last).893bool Writer::fixGnuImportChunks() {894  uint32_t rdata = IMAGE_SCN_CNT_INITIALIZED_DATA | IMAGE_SCN_MEM_READ;895 896  // Make sure all .idata$* section chunks are mapped as RDATA in order to897  // be sorted into the same sections as our own synthesized .idata chunks.898  fixPartialSectionChars(".idata", rdata);899 900  bool hasIdata = false;901  // Sort all .idata$* chunks, grouping chunks from the same library,902  // with alphabetical ordering of the object files within a library.903  for (auto it : partialSections) {904    PartialSection *pSec = it.second;905    if (!pSec->name.starts_with(".idata"))906      continue;907 908    if (!pSec->chunks.empty())909      hasIdata = true;910    llvm::stable_sort(pSec->chunks, [&](Chunk *s, Chunk *t) {911      SectionChunk *sc1 = dyn_cast<SectionChunk>(s);912      SectionChunk *sc2 = dyn_cast<SectionChunk>(t);913      if (!sc1 || !sc2) {914        // if SC1, order them ascending. If SC2 or both null,915        // S is not less than T.916        return sc1 != nullptr;917      }918      // Make a string with "libraryname/objectfile" for sorting, achieving919      // both grouping by library and sorting of objects within a library,920      // at once.921      std::string key1 =922          (sc1->file->parentName + "/" + sc1->file->getName()).str();923      std::string key2 =924          (sc2->file->parentName + "/" + sc2->file->getName()).str();925      return key1 < key2;926    });927  }928  return hasIdata;929}930 931// Add generated idata chunks, for imported symbols and DLLs, and a932// terminator in .idata$2.933void Writer::addSyntheticIdata() {934  uint32_t rdata = IMAGE_SCN_CNT_INITIALIZED_DATA | IMAGE_SCN_MEM_READ;935  idata.create(ctx);936 937  // Add the .idata content in the right section groups, to allow938  // chunks from other linked in object files to be grouped together.939  // See Microsoft PE/COFF spec 5.4 for details.940  auto add = [&](StringRef n, std::vector<Chunk *> &v) {941    PartialSection *pSec = createPartialSection(n, rdata);942    pSec->chunks.insert(pSec->chunks.end(), v.begin(), v.end());943  };944 945  // The loader assumes a specific order of data.946  // Add each type in the correct order.947  add(".idata$2", idata.dirs);948  add(".idata$4", idata.lookups);949  add(".idata$5", idata.addresses);950  if (!idata.hints.empty())951    add(".idata$6", idata.hints);952  add(".idata$7", idata.dllNames);953  if (!idata.auxIat.empty())954    add(".idata$9", idata.auxIat);955  if (!idata.auxIatCopy.empty())956    add(".idata$a", idata.auxIatCopy);957}958 959void Writer::appendECImportTables() {960  if (!isArm64EC(ctx.config.machine))961    return;962 963  const uint32_t rdata = IMAGE_SCN_CNT_INITIALIZED_DATA | IMAGE_SCN_MEM_READ;964 965  // IAT is always placed at the beginning of .rdata section and its size966  // is aligned to 4KB. Insert it here, after all merges all done.967  if (PartialSection *importAddresses = findPartialSection(".idata$5", rdata)) {968    if (!rdataSec->chunks.empty())969      rdataSec->chunks.front()->setAlignment(970          std::max(0x1000u, rdataSec->chunks.front()->getAlignment()));971    iatSize = alignTo(iatSize, 0x1000);972 973    rdataSec->chunks.insert(rdataSec->chunks.begin(),974                            importAddresses->chunks.begin(),975                            importAddresses->chunks.end());976    rdataSec->contribSections.insert(rdataSec->contribSections.begin(),977                                     importAddresses);978  }979 980  // The auxiliary IAT is always placed at the end of the .rdata section981  // and is aligned to 4KB.982  if (PartialSection *auxIat = findPartialSection(".idata$9", rdata)) {983    auxIat->chunks.front()->setAlignment(0x1000);984    rdataSec->chunks.insert(rdataSec->chunks.end(), auxIat->chunks.begin(),985                            auxIat->chunks.end());986    rdataSec->addContributingPartialSection(auxIat);987  }988 989  if (!delayIdata.getAuxIat().empty()) {990    delayIdata.getAuxIat().front()->setAlignment(0x1000);991    rdataSec->chunks.insert(rdataSec->chunks.end(),992                            delayIdata.getAuxIat().begin(),993                            delayIdata.getAuxIat().end());994  }995}996 997// Locate the first Chunk and size of the import directory list and the998// IAT.999void Writer::locateImportTables() {1000  uint32_t rdata = IMAGE_SCN_CNT_INITIALIZED_DATA | IMAGE_SCN_MEM_READ;1001 1002  if (PartialSection *importDirs = findPartialSection(".idata$2", rdata)) {1003    if (!importDirs->chunks.empty())1004      importTableStart = importDirs->chunks.front();1005    for (Chunk *c : importDirs->chunks)1006      importTableSize += c->getSize();1007  }1008 1009  if (PartialSection *importAddresses = findPartialSection(".idata$5", rdata)) {1010    if (!importAddresses->chunks.empty())1011      iatStart = importAddresses->chunks.front();1012    for (Chunk *c : importAddresses->chunks)1013      iatSize += c->getSize();1014  }1015}1016 1017// Return whether a SectionChunk's suffix (the dollar and any trailing1018// suffix) should be removed and sorted into the main suffixless1019// PartialSection.1020static bool shouldStripSectionSuffix(SectionChunk *sc, StringRef name,1021                                     bool isMinGW) {1022  // On MinGW, comdat groups are formed by putting the comdat group name1023  // after the '$' in the section name. For .eh_frame$<symbol>, that must1024  // still be sorted before the .eh_frame trailer from crtend.o, thus just1025  // strip the section name trailer. For other sections, such as1026  // .tls$$<symbol> (where non-comdat .tls symbols are otherwise stored in1027  // ".tls$"), they must be strictly sorted after .tls. And for the1028  // hypothetical case of comdat .CRT$XCU, we definitely need to keep the1029  // suffix for sorting. Thus, to play it safe, only strip the suffix for1030  // the standard sections.1031  if (!isMinGW)1032    return false;1033  if (!sc || !sc->isCOMDAT())1034    return false;1035  return name.starts_with(".text$") || name.starts_with(".data$") ||1036         name.starts_with(".rdata$") || name.starts_with(".pdata$") ||1037         name.starts_with(".xdata$") || name.starts_with(".eh_frame$");1038}1039 1040void Writer::sortSections() {1041  if (!ctx.config.callGraphProfile.empty()) {1042    DenseMap<const SectionChunk *, int> order =1043        computeCallGraphProfileOrder(ctx);1044    for (auto it : order) {1045      if (DefinedRegular *sym = it.first->sym)1046        ctx.config.order[sym->getName()] = it.second;1047    }1048  }1049  if (!ctx.config.order.empty())1050    for (auto it : partialSections)1051      sortBySectionOrder(it.second->chunks);1052}1053 1054void Writer::calculateStubDependentSizes() {1055  if (ctx.config.dosStub)1056    dosStubSize = alignTo(ctx.config.dosStub->getBufferSize(), 8);1057  else1058    dosStubSize = sizeof(dos_header) + sizeof(dosProgram);1059 1060  coffHeaderOffset = dosStubSize + sizeof(PEMagic);1061  peHeaderOffset = coffHeaderOffset + sizeof(coff_file_header);1062  dataDirOffset64 = peHeaderOffset + sizeof(pe32plus_header);1063}1064 1065// Create output section objects and add them to OutputSections.1066void Writer::createSections() {1067  llvm::TimeTraceScope timeScope("Output sections");1068  // First, create the builtin sections.1069  const uint32_t data = IMAGE_SCN_CNT_INITIALIZED_DATA;1070  const uint32_t bss = IMAGE_SCN_CNT_UNINITIALIZED_DATA;1071  const uint32_t code = IMAGE_SCN_CNT_CODE;1072  const uint32_t discardable = IMAGE_SCN_MEM_DISCARDABLE;1073  const uint32_t r = IMAGE_SCN_MEM_READ;1074  const uint32_t w = IMAGE_SCN_MEM_WRITE;1075  const uint32_t x = IMAGE_SCN_MEM_EXECUTE;1076 1077  SmallDenseMap<std::pair<StringRef, uint32_t>, OutputSection *> sections;1078  auto createSection = [&](StringRef name, uint32_t outChars) {1079    OutputSection *&sec = sections[{name, outChars}];1080    if (!sec) {1081      sec = make<OutputSection>(name, outChars);1082      ctx.outputSections.push_back(sec);1083    }1084    return sec;1085  };1086 1087  // Try to match the section order used by link.exe.1088  textSec = createSection(".text", code | r | x);1089  if (isArm64EC(ctx.config.machine)) {1090    wowthkSec = createSection(".wowthk", code | r | x);1091    hexpthkSec = createSection(".hexpthk", code | r | x);1092  }1093  bssSec = createSection(".bss", bss | r | w);1094  rdataSec = createSection(".rdata", data | r);1095  buildidSec = createSection(".buildid", data | r);1096  cvinfoSec = createSection(".cvinfo", data | r);1097  dataSec = createSection(".data", data | r | w);1098  pdataSec = createSection(".pdata", data | r);1099  idataSec = createSection(".idata", data | r);1100  edataSec = createSection(".edata", data | r);1101  didatSec = createSection(".didat", data | r);1102  if (isArm64EC(ctx.config.machine))1103    a64xrmSec = createSection(".a64xrm", data | r);1104  rsrcSec = createSection(".rsrc", data | r);1105  relocSec = createSection(".reloc", data | discardable | r);1106  ctorsSec = createSection(".ctors", data | r | w);1107  dtorsSec = createSection(".dtors", data | r | w);1108 1109  // Then bin chunks by name and output characteristics.1110  for (Chunk *c : ctx.driver.getChunks()) {1111    auto *sc = dyn_cast<SectionChunk>(c);1112    if (sc && !sc->live) {1113      if (ctx.config.verbose)1114        sc->printDiscardedMessage();1115      continue;1116    }1117    if (auto *cc = dyn_cast<CommonChunk>(c)) {1118      if (!cc->live)1119        continue;1120    }1121    StringRef name = c->getSectionName();1122    if (shouldStripSectionSuffix(sc, name, ctx.config.mingw))1123      name = name.split('$').first;1124 1125    if (name.starts_with(".tls"))1126      tlsAlignment = std::max(tlsAlignment, c->getAlignment());1127 1128    PartialSection *pSec = createPartialSection(name,1129                                                c->getOutputCharacteristics());1130    pSec->chunks.push_back(c);1131  }1132 1133  fixPartialSectionChars(".rsrc", data | r);1134  fixPartialSectionChars(".edata", data | r);1135  // Even in non MinGW cases, we might need to link against GNU import1136  // libraries.1137  bool hasIdata = fixGnuImportChunks();1138  if (!idata.empty())1139    hasIdata = true;1140 1141  if (hasIdata)1142    addSyntheticIdata();1143 1144  sortSections();1145 1146  if (hasIdata)1147    locateImportTables();1148 1149  for (auto thunk : ctx.symtab.sameAddressThunks)1150    wowthkSec->addChunk(thunk);1151 1152  // Then create an OutputSection for each section.1153  // '$' and all following characters in input section names are1154  // discarded when determining output section. So, .text$foo1155  // contributes to .text, for example. See PE/COFF spec 3.2.1156  for (auto it : partialSections) {1157    PartialSection *pSec = it.second;1158    StringRef name = getOutputSectionName(pSec->name);1159    uint32_t outChars = pSec->characteristics;1160 1161    if (name == ".CRT") {1162      // In link.exe, there is a special case for the I386 target where .CRT1163      // sections are treated as if they have output characteristics DATA | R if1164      // their characteristics are DATA | R | W. This implements the same1165      // special case for all architectures.1166      outChars = data | r;1167 1168      Log(ctx) << "Processing section " << pSec->name << " -> " << name;1169 1170      sortCRTSectionChunks(pSec->chunks);1171    }1172 1173    // ARM64EC has specific placement and alignment requirements for the IAT.1174    // Delay adding its chunks until appendECImportTables.1175    if (isArm64EC(ctx.config.machine) &&1176        (pSec->name == ".idata$5" || pSec->name == ".idata$9"))1177      continue;1178 1179    OutputSection *sec = createSection(name, outChars);1180    for (Chunk *c : pSec->chunks)1181      sec->addChunk(c);1182 1183    sec->addContributingPartialSection(pSec);1184  }1185 1186  if (ctx.hybridSymtab) {1187    if (OutputSection *sec = findSection(".CRT"))1188      sec->splitECChunks();1189  }1190 1191  // Finally, move some output sections to the end.1192  auto sectionOrder = [&](const OutputSection *s) {1193    // Move DISCARDABLE (or non-memory-mapped) sections to the end of file1194    // because the loader cannot handle holes. Stripping can remove other1195    // discardable ones than .reloc, which is first of them (created early).1196    if (s->header.Characteristics & IMAGE_SCN_MEM_DISCARDABLE) {1197      // Move discardable sections named .debug_ to the end, after other1198      // discardable sections. Stripping only removes the sections named1199      // .debug_* - thus try to avoid leaving holes after stripping.1200      if (s->name.starts_with(".debug_"))1201        return 3;1202      return 2;1203    }1204    // .rsrc should come at the end of the non-discardable sections because its1205    // size may change by the Win32 UpdateResources() function, causing1206    // subsequent sections to move (see https://crbug.com/827082).1207    if (s == rsrcSec)1208      return 1;1209    return 0;1210  };1211  llvm::stable_sort(ctx.outputSections,1212                    [&](const OutputSection *s, const OutputSection *t) {1213                      return sectionOrder(s) < sectionOrder(t);1214                    });1215}1216 1217void Writer::createMiscChunks() {1218  llvm::TimeTraceScope timeScope("Misc chunks");1219  Configuration *config = &ctx.config;1220 1221  for (MergeChunk *p : ctx.mergeChunkInstances) {1222    if (p) {1223      p->finalizeContents();1224      rdataSec->addChunk(p);1225    }1226  }1227 1228  // Create thunks for locally-dllimported symbols.1229  ctx.forEachSymtab([&](SymbolTable &symtab) {1230    if (!symtab.localImportChunks.empty()) {1231      for (Chunk *c : symtab.localImportChunks)1232        rdataSec->addChunk(c);1233    }1234  });1235 1236  // Create Debug Information Chunks1237  if (config->mingw) {1238    debugInfoSec = buildidSec;1239  } else if (!config->mergeDebugDirectory) {1240    debugInfoSec = cvinfoSec;1241  } else {1242    debugInfoSec = rdataSec;1243  }1244  if (config->buildIDHash != BuildIDHash::None || config->debug ||1245      config->repro || config->cetCompat || config->cetCompatStrict ||1246      config->cetCompatIpValidationRelaxed ||1247      config->cetCompatDynamicApisInProcOnly || config->hotpatchCompat) {1248    debugDirectory =1249        make<DebugDirectoryChunk>(ctx, debugRecords, config->repro);1250    debugDirectory->setAlignment(4);1251    debugInfoSec->addChunk(debugDirectory);1252  }1253 1254  if (config->debug || config->buildIDHash != BuildIDHash::None) {1255    // Make a CVDebugRecordChunk even when /DEBUG:CV is not specified.  We1256    // output a PDB no matter what, and this chunk provides the only means of1257    // allowing a debugger to match a PDB and an executable.  So we need it even1258    // if we're ultimately not going to write CodeView data to the PDB.1259    buildId = make<CVDebugRecordChunk>(ctx);1260    debugRecords.emplace_back(COFF::IMAGE_DEBUG_TYPE_CODEVIEW, buildId);1261    ctx.forEachSymtab([&](SymbolTable &symtab) {1262      if (Symbol *buildidSym = symtab.findUnderscore("__buildid"))1263        replaceSymbol<DefinedSynthetic>(buildidSym, buildidSym->getName(),1264                                        buildId, 4);1265    });1266  }1267 1268  uint16_t ex_characteristics_flags = 0;1269  if (config->cetCompat)1270    ex_characteristics_flags |= IMAGE_DLL_CHARACTERISTICS_EX_CET_COMPAT;1271  if (config->cetCompatStrict)1272    ex_characteristics_flags |=1273        IMAGE_DLL_CHARACTERISTICS_EX_CET_COMPAT_STRICT_MODE;1274  if (config->cetCompatIpValidationRelaxed)1275    ex_characteristics_flags |=1276        IMAGE_DLL_CHARACTERISTICS_EX_CET_SET_CONTEXT_IP_VALIDATION_RELAXED_MODE;1277  if (config->cetCompatDynamicApisInProcOnly)1278    ex_characteristics_flags |=1279        IMAGE_DLL_CHARACTERISTICS_EX_CET_DYNAMIC_APIS_ALLOW_IN_PROC_ONLY;1280  if (config->hotpatchCompat)1281    ex_characteristics_flags |=1282        IMAGE_DLL_CHARACTERISTICS_EX_HOTPATCH_COMPATIBLE;1283 1284  if (ex_characteristics_flags) {1285    debugRecords.emplace_back(1286        COFF::IMAGE_DEBUG_TYPE_EX_DLLCHARACTERISTICS,1287        make<ExtendedDllCharacteristicsChunk>(ex_characteristics_flags));1288  }1289 1290  // Align and add each chunk referenced by the debug data directory.1291  for (std::pair<COFF::DebugType, Chunk *> r : debugRecords) {1292    r.second->setAlignment(4);1293    debugInfoSec->addChunk(r.second);1294  }1295 1296  // Create SEH table. x86-only.1297  if (config->safeSEH)1298    createSEHTable();1299 1300  // Create /guard:cf tables if requested.1301  createGuardCFTables();1302 1303  createECChunks();1304 1305  if (config->autoImport)1306    createRuntimePseudoRelocs();1307 1308  if (config->mingw) {1309    insertCtorDtorSymbols();1310    insertBssDataStartEndSymbols();1311  }1312}1313 1314// Create .idata section for the DLL-imported symbol table.1315// The format of this section is inherently Windows-specific.1316// IdataContents class abstracted away the details for us,1317// so we just let it create chunks and add them to the section.1318void Writer::createImportTables() {1319  llvm::TimeTraceScope timeScope("Import tables");1320  // Initialize DLLOrder so that import entries are ordered in1321  // the same order as in the command line. (That affects DLL1322  // initialization order, and this ordering is MSVC-compatible.)1323  for (ImportFile *file : ctx.importFileInstances) {1324    if (!file->live)1325      continue;1326 1327    std::string dll = StringRef(file->dllName).lower();1328    ctx.config.dllOrder.try_emplace(dll, ctx.config.dllOrder.size());1329 1330    if (file->impSym && !isa<DefinedImportData>(file->impSym))1331      Fatal(ctx) << file->symtab.printSymbol(file->impSym) << " was replaced";1332    DefinedImportData *impSym = cast_or_null<DefinedImportData>(file->impSym);1333    if (ctx.config.delayLoads.count(StringRef(file->dllName).lower())) {1334      if (!file->thunkSym)1335        Fatal(ctx) << "cannot delay-load " << toString(file)1336                   << " due to import of data: "1337                   << file->symtab.printSymbol(impSym);1338      delayIdata.add(impSym);1339    } else {1340      idata.add(impSym);1341    }1342  }1343}1344 1345void Writer::appendImportThunks() {1346  if (ctx.importFileInstances.empty())1347    return;1348 1349  llvm::TimeTraceScope timeScope("Import thunks");1350  for (ImportFile *file : ctx.importFileInstances) {1351    if (!file->live)1352      continue;1353 1354    if (file->thunkSym) {1355      if (!isa<DefinedImportThunk>(file->thunkSym))1356        Fatal(ctx) << file->symtab.printSymbol(file->thunkSym)1357                   << " was replaced";1358      auto *chunk = cast<DefinedImportThunk>(file->thunkSym)->getChunk();1359      if (chunk->live)1360        textSec->addChunk(chunk);1361    }1362 1363    if (file->auxThunkSym) {1364      if (!isa<DefinedImportThunk>(file->auxThunkSym))1365        Fatal(ctx) << file->symtab.printSymbol(file->auxThunkSym)1366                   << " was replaced";1367      auto *chunk = cast<DefinedImportThunk>(file->auxThunkSym)->getChunk();1368      if (chunk->live)1369        textSec->addChunk(chunk);1370    }1371 1372    if (file->impchkThunk)1373      textSec->addChunk(file->impchkThunk);1374  }1375 1376  if (!delayIdata.empty()) {1377    delayIdata.create();1378    for (Chunk *c : delayIdata.getChunks())1379      didatSec->addChunk(c);1380    for (Chunk *c : delayIdata.getDataChunks())1381      dataSec->addChunk(c);1382    for (Chunk *c : delayIdata.getCodeChunks())1383      textSec->addChunk(c);1384    for (Chunk *c : delayIdata.getCodePData())1385      pdataSec->addChunk(c);1386    for (Chunk *c : delayIdata.getAuxIatCopy())1387      rdataSec->addChunk(c);1388    for (Chunk *c : delayIdata.getCodeUnwindInfo())1389      rdataSec->addChunk(c);1390  }1391}1392 1393void Writer::createExportTable() {1394  llvm::TimeTraceScope timeScope("Export table");1395  if (!edataSec->chunks.empty()) {1396    // Allow using a custom built export table from input object files, instead1397    // of having the linker synthesize the tables.1398    if (!ctx.hybridSymtab) {1399      ctx.symtab.edataStart = edataSec->chunks.front();1400      ctx.symtab.edataEnd = edataSec->chunks.back();1401    } else {1402      // On hybrid target, split EC and native chunks.1403      llvm::stable_sort(edataSec->chunks, [=](const Chunk *a, const Chunk *b) {1404        return (a->getMachine() != ARM64) < (b->getMachine() != ARM64);1405      });1406 1407      for (auto chunk : edataSec->chunks) {1408        if (chunk->getMachine() != ARM64) {1409          ctx.symtab.edataStart = chunk;1410          ctx.symtab.edataEnd = edataSec->chunks.back();1411          break;1412        }1413 1414        if (!ctx.hybridSymtab->edataStart)1415          ctx.hybridSymtab->edataStart = chunk;1416        ctx.hybridSymtab->edataEnd = chunk;1417      }1418    }1419  }1420  ctx.forEachActiveSymtab([&](SymbolTable &symtab) {1421    if (symtab.edataStart) {1422      if (symtab.hadExplicitExports)1423        Warn(ctx) << "literal .edata sections override exports";1424    } else if (!symtab.exports.empty()) {1425      std::vector<Chunk *> edataChunks;1426      createEdataChunks(symtab, edataChunks);1427      for (Chunk *c : edataChunks)1428        edataSec->addChunk(c);1429      symtab.edataStart = edataChunks.front();1430      symtab.edataEnd = edataChunks.back();1431    }1432 1433    // Warn on exported deleting destructor.1434    for (auto e : symtab.exports)1435      if (e.sym && e.sym->getName().starts_with("??_G"))1436        Warn(ctx) << "export of deleting dtor: " << toString(ctx, *e.sym);1437  });1438}1439 1440void Writer::removeUnusedSections() {1441  llvm::TimeTraceScope timeScope("Remove unused sections");1442  // Remove sections that we can be sure won't get content, to avoid1443  // allocating space for their section headers.1444  auto isUnused = [this](OutputSection *s) {1445    if (s == relocSec)1446      return false; // This section is populated later.1447    // MergeChunks have zero size at this point, as their size is finalized1448    // later. Only remove sections that have no Chunks at all.1449    return s->chunks.empty();1450  };1451  llvm::erase_if(ctx.outputSections, isUnused);1452}1453 1454void Writer::layoutSections() {1455  llvm::TimeTraceScope timeScope("Layout sections");1456  if (ctx.config.sectionOrder.empty())1457    return;1458 1459  llvm::stable_sort(ctx.outputSections,1460                    [this](const OutputSection *a, const OutputSection *b) {1461                      auto itA = ctx.config.sectionOrder.find(a->name.str());1462                      auto itB = ctx.config.sectionOrder.find(b->name.str());1463                      bool aInOrder = itA != ctx.config.sectionOrder.end();1464                      bool bInOrder = itB != ctx.config.sectionOrder.end();1465 1466                      // Put unspecified sections after all specified sections1467                      if (aInOrder && bInOrder) {1468                        return itA->second < itB->second;1469                      } else if (aInOrder && !bInOrder) {1470                        return true; // ordered sections come before unordered1471                      } else {1472                        // (!aInOrder && bInOrder): unordered comes after1473                        // ordered1474                        // (!aInOrder && !bInOrder): both unspecified, preserve1475                        // the original order1476                        return false;1477                      }1478                    });1479}1480 1481// The Windows loader doesn't seem to like empty sections,1482// so we remove them if any.1483void Writer::removeEmptySections() {1484  llvm::TimeTraceScope timeScope("Remove empty sections");1485  auto isEmpty = [](OutputSection *s) { return s->getVirtualSize() == 0; };1486  llvm::erase_if(ctx.outputSections, isEmpty);1487}1488 1489void Writer::assignOutputSectionIndices() {1490  llvm::TimeTraceScope timeScope("Output sections indices");1491  // Assign final output section indices, and assign each chunk to its output1492  // section.1493  uint32_t idx = 1;1494  for (OutputSection *os : ctx.outputSections) {1495    os->sectionIndex = idx;1496    for (Chunk *c : os->chunks)1497      c->setOutputSectionIdx(idx);1498    ++idx;1499  }1500 1501  // Merge chunks are containers of chunks, so assign those an output section1502  // too.1503  for (MergeChunk *mc : ctx.mergeChunkInstances)1504    if (mc)1505      for (SectionChunk *sc : mc->sections)1506        if (sc && sc->live)1507          sc->setOutputSectionIdx(mc->getOutputSectionIdx());1508}1509 1510std::optional<coff_symbol16> Writer::createSymbol(Defined *def) {1511  coff_symbol16 sym;1512  switch (def->kind()) {1513  case Symbol::DefinedAbsoluteKind: {1514    auto *da = dyn_cast<DefinedAbsolute>(def);1515    // Note: COFF symbol can only store 32-bit values, so 64-bit absolute1516    // values will be truncated.1517    sym.Value = da->getVA();1518    sym.SectionNumber = IMAGE_SYM_ABSOLUTE;1519    break;1520  }1521  default: {1522    // Don't write symbols that won't be written to the output to the symbol1523    // table.1524    // We also try to write DefinedSynthetic as a normal symbol. Some of these1525    // symbols do point to an actual chunk, like __safe_se_handler_table. Others1526    // like __ImageBase are outside of sections and thus cannot be represented.1527    Chunk *c = def->getChunk();1528    if (!c)1529      return std::nullopt;1530    OutputSection *os = ctx.getOutputSection(c);1531    if (!os)1532      return std::nullopt;1533 1534    sym.Value = def->getRVA() - os->getRVA();1535    sym.SectionNumber = os->sectionIndex;1536    break;1537  }1538  }1539 1540  // Symbols that are runtime pseudo relocations don't point to the actual1541  // symbol data itself (as they are imported), but points to the IAT entry1542  // instead. Avoid emitting them to the symbol table, as they can confuse1543  // debuggers.1544  if (def->isRuntimePseudoReloc)1545    return std::nullopt;1546 1547  StringRef name = def->getName();1548  if (name.size() > COFF::NameSize) {1549    sym.Name.Offset.Zeroes = 0;1550    sym.Name.Offset.Offset = 0; // Filled in later.1551    strtab.add(name);1552  } else {1553    memset(sym.Name.ShortName, 0, COFF::NameSize);1554    memcpy(sym.Name.ShortName, name.data(), name.size());1555  }1556 1557  if (auto *d = dyn_cast<DefinedCOFF>(def)) {1558    COFFSymbolRef ref = d->getCOFFSymbol();1559    sym.Type = ref.getType();1560    sym.StorageClass = ref.getStorageClass();1561  } else if (def->kind() == Symbol::DefinedImportThunkKind) {1562    sym.Type = (IMAGE_SYM_DTYPE_FUNCTION << SCT_COMPLEX_TYPE_SHIFT) |1563               IMAGE_SYM_TYPE_NULL;1564    sym.StorageClass = IMAGE_SYM_CLASS_EXTERNAL;1565  } else {1566    sym.Type = IMAGE_SYM_TYPE_NULL;1567    sym.StorageClass = IMAGE_SYM_CLASS_EXTERNAL;1568  }1569  sym.NumberOfAuxSymbols = 0;1570  return sym;1571}1572 1573void Writer::createSymbolAndStringTable() {1574  llvm::TimeTraceScope timeScope("Symbol and string table");1575  // PE/COFF images are limited to 8 byte section names. Longer names can be1576  // supported by writing a non-standard string table, but this string table is1577  // not mapped at runtime and the long names will therefore be inaccessible.1578  // link.exe always truncates section names to 8 bytes, whereas binutils always1579  // preserves long section names via the string table. LLD adopts a hybrid1580  // solution where discardable sections have long names preserved and1581  // non-discardable sections have their names truncated, to ensure that any1582  // section which is mapped at runtime also has its name mapped at runtime.1583  SmallVector<OutputSection *> longNameSections;1584  for (OutputSection *sec : ctx.outputSections) {1585    if (sec->name.size() <= COFF::NameSize)1586      continue;1587    if ((sec->header.Characteristics & IMAGE_SCN_MEM_DISCARDABLE) == 0)1588      continue;1589    if (ctx.config.warnLongSectionNames) {1590      Warn(ctx)1591          << "section name " << sec->name1592          << " is longer than 8 characters and will use a non-standard string "1593             "table";1594    }1595    // Put the section name in the begin of strtab so that its offset is less1596    // than Max7DecimalOffset otherwise lldb/gdb will not read it.1597    strtab.add(sec->name, /*Priority=*/UINT8_MAX);1598    longNameSections.push_back(sec);1599  }1600 1601  std::vector<std::pair<size_t, StringRef>> longNameSymbols;1602  if (ctx.config.writeSymtab) {1603    for (ObjFile *file : ctx.objFileInstances) {1604      for (Symbol *b : file->getSymbols()) {1605        auto *d = dyn_cast_or_null<Defined>(b);1606        if (!d || d->writtenToSymtab)1607          continue;1608        d->writtenToSymtab = true;1609        if (auto *dc = dyn_cast_or_null<DefinedCOFF>(d)) {1610          COFFSymbolRef symRef = dc->getCOFFSymbol();1611          if (symRef.isSectionDefinition() ||1612              symRef.getStorageClass() == COFF::IMAGE_SYM_CLASS_LABEL)1613            continue;1614        }1615 1616        if (std::optional<coff_symbol16> sym = createSymbol(d)) {1617          if (d->getName().size() > COFF::NameSize)1618            longNameSymbols.emplace_back(outputSymtab.size(), d->getName());1619          outputSymtab.push_back(*sym);1620        }1621 1622        if (auto *dthunk = dyn_cast<DefinedImportThunk>(d)) {1623          if (!dthunk->wrappedSym->writtenToSymtab) {1624            dthunk->wrappedSym->writtenToSymtab = true;1625            if (std::optional<coff_symbol16> sym =1626                    createSymbol(dthunk->wrappedSym)) {1627              if (dthunk->wrappedSym->getName().size() > COFF::NameSize)1628                longNameSymbols.emplace_back(outputSymtab.size(),1629                                             dthunk->wrappedSym->getName());1630              outputSymtab.push_back(*sym);1631            }1632          }1633        }1634      }1635    }1636  }1637 1638  if (outputSymtab.empty() && strtab.empty())1639    return;1640 1641  strtab.finalize();1642  for (OutputSection *sec : longNameSections)1643    sec->setStringTableOff(strtab.getOffset(sec->name));1644  for (auto P : longNameSymbols) {1645    coff_symbol16 &sym = outputSymtab[P.first];1646    sym.Name.Offset.Offset = strtab.getOffset(P.second);1647  }1648 1649  // We position the symbol table to be adjacent to the end of the last section.1650  uint64_t fileOff = fileSize;1651  pointerToSymbolTable = fileOff;1652  fileOff += outputSymtab.size() * sizeof(coff_symbol16);1653  fileOff += strtab.getSize();1654  fileSize = alignTo(fileOff, ctx.config.fileAlign);1655}1656 1657void Writer::mergeSection(const std::map<StringRef, StringRef>::value_type &p) {1658  StringRef toName = p.second;1659  if (p.first == toName)1660    return;1661  StringSet<> names;1662  while (true) {1663    if (!names.insert(toName).second)1664      Fatal(ctx) << "/merge: cycle found for section '" << p.first << "'";1665    auto i = ctx.config.merge.find(toName);1666    if (i == ctx.config.merge.end())1667      break;1668    toName = i->second;1669  }1670  OutputSection *from = findSection(p.first);1671  OutputSection *to = findSection(toName);1672  if (!from)1673    return;1674  if (!to) {1675    from->name = toName;1676    return;1677  }1678  to->merge(from);1679}1680 1681void Writer::mergeSections() {1682  llvm::TimeTraceScope timeScope("Merge sections");1683  if (!pdataSec->chunks.empty()) {1684    if (isArm64EC(ctx.config.machine)) {1685      // On ARM64EC .pdata may contain both ARM64 and X64 data. Split them by1686      // sorting and store their regions separately.1687      llvm::stable_sort(pdataSec->chunks, [=](const Chunk *a, const Chunk *b) {1688        return (a->getMachine() == AMD64) < (b->getMachine() == AMD64);1689      });1690 1691      for (auto chunk : pdataSec->chunks) {1692        if (chunk->getMachine() == AMD64) {1693          hybridPdata.first = chunk;1694          hybridPdata.last = pdataSec->chunks.back();1695          break;1696        }1697 1698        if (!pdata.first)1699          pdata.first = chunk;1700        pdata.last = chunk;1701      }1702    } else {1703      pdata.first = pdataSec->chunks.front();1704      pdata.last = pdataSec->chunks.back();1705    }1706  }1707 1708  for (auto &p : ctx.config.merge) {1709    if (p.first != ".bss")1710      mergeSection(p);1711  }1712 1713  // Because .bss contains all zeros, it should be merged at the end of1714  // whatever section it is being merged into (usually .data) so that the image1715  // need not actually contain all of the zeros.1716  auto it = ctx.config.merge.find(".bss");1717  if (it != ctx.config.merge.end())1718    mergeSection(*it);1719}1720 1721// EC targets may have chunks of various architectures mixed together at this1722// point. Group code chunks of the same architecture together by sorting chunks1723// by their EC range type.1724void Writer::sortECChunks() {1725  if (!isArm64EC(ctx.config.machine))1726    return;1727 1728  for (OutputSection *sec : ctx.outputSections) {1729    if (sec->isCodeSection())1730      llvm::stable_sort(sec->chunks, [=](const Chunk *a, const Chunk *b) {1731        std::optional<chpe_range_type> aType = a->getArm64ECRangeType(),1732                                       bType = b->getArm64ECRangeType();1733        return bType && (!aType || *aType < *bType);1734      });1735  }1736}1737 1738// Visits all sections to assign incremental, non-overlapping RVAs and1739// file offsets.1740void Writer::assignAddresses() {1741  llvm::TimeTraceScope timeScope("Assign addresses");1742  Configuration *config = &ctx.config;1743 1744  // We need to create EC code map so that ECCodeMapChunk knows its size.1745  // We do it here to make sure that we account for range extension chunks.1746  createECCodeMap();1747 1748  sizeOfHeaders = dosStubSize + sizeof(PEMagic) + sizeof(coff_file_header) +1749                  sizeof(data_directory) * numberOfDataDirectory +1750                  sizeof(coff_section) * ctx.outputSections.size();1751  sizeOfHeaders +=1752      config->is64() ? sizeof(pe32plus_header) : sizeof(pe32_header);1753  sizeOfHeaders = alignTo(sizeOfHeaders, config->fileAlign);1754  fileSize = sizeOfHeaders;1755 1756  // The first page is kept unmapped.1757  uint64_t rva = alignTo(sizeOfHeaders, config->align);1758 1759  for (OutputSection *sec : ctx.outputSections) {1760    llvm::TimeTraceScope timeScope("Section: ", sec->name);1761    if (sec == relocSec) {1762      sec->chunks.clear();1763      addBaserels();1764      if (ctx.dynamicRelocs) {1765        ctx.dynamicRelocs->finalize();1766        relocSec->addChunk(ctx.dynamicRelocs);1767      }1768    }1769    uint64_t rawSize = 0, virtualSize = 0;1770    sec->header.VirtualAddress = rva;1771 1772    // If /FUNCTIONPADMIN is used, functions are padded in order to create a1773    // hotpatchable image.1774    uint32_t padding = sec->isCodeSection() ? config->functionPadMin : 0;1775    std::optional<chpe_range_type> prevECRange;1776 1777    for (Chunk *c : sec->chunks) {1778      // Alignment EC code range baudaries.1779      if (isArm64EC(ctx.config.machine) && sec->isCodeSection()) {1780        std::optional<chpe_range_type> rangeType = c->getArm64ECRangeType();1781        if (rangeType != prevECRange) {1782          virtualSize = alignTo(virtualSize, 4096);1783          prevECRange = rangeType;1784        }1785      }1786      if (padding && c->isHotPatchable())1787        virtualSize += padding;1788      // If chunk has EC entry thunk, reserve a space for an offset to the1789      // thunk.1790      if (c->getEntryThunk())1791        virtualSize += sizeof(uint32_t);1792      virtualSize = alignTo(virtualSize, c->getAlignment());1793      c->setRVA(rva + virtualSize);1794      virtualSize += c->getSize();1795      if (c->hasData)1796        rawSize = alignTo(virtualSize, config->fileAlign);1797    }1798    if (virtualSize > UINT32_MAX)1799      Err(ctx) << "section larger than 4 GiB: " << sec->name;1800    sec->header.VirtualSize = virtualSize;1801    sec->header.SizeOfRawData = rawSize;1802    if (rawSize != 0)1803      sec->header.PointerToRawData = fileSize;1804    rva += alignTo(virtualSize, config->align);1805    fileSize += alignTo(rawSize, config->fileAlign);1806  }1807  sizeOfImage = alignTo(rva, config->align);1808 1809  // Assign addresses to sections in MergeChunks.1810  for (MergeChunk *mc : ctx.mergeChunkInstances)1811    if (mc)1812      mc->assignSubsectionRVAs();1813}1814 1815template <typename PEHeaderTy> void Writer::writeHeader() {1816  // Write DOS header. For backwards compatibility, the first part of a PE/COFF1817  // executable consists of an MS-DOS MZ executable. If the executable is run1818  // under DOS, that program gets run (usually to just print an error message).1819  // When run under Windows, the loader looks at AddressOfNewExeHeader and uses1820  // the PE header instead.1821  Configuration *config = &ctx.config;1822 1823  uint8_t *buf = buffer->getBufferStart();1824  auto *dos = reinterpret_cast<dos_header *>(buf);1825 1826  // Write DOS program.1827  if (config->dosStub) {1828    memcpy(buf, config->dosStub->getBufferStart(),1829           config->dosStub->getBufferSize());1830    // MS link.exe accepts an invalid `e_lfanew` (AddressOfNewExeHeader) and1831    // updates it automatically. Replicate the same behaviour.1832    dos->AddressOfNewExeHeader = alignTo(config->dosStub->getBufferSize(), 8);1833    // Unlike MS link.exe, LLD accepts non-8-byte-aligned stubs.1834    // In that case, we add zero paddings ourselves.1835    buf += alignTo(config->dosStub->getBufferSize(), 8);1836  } else {1837    buf += sizeof(dos_header);1838    dos->Magic[0] = 'M';1839    dos->Magic[1] = 'Z';1840    dos->UsedBytesInTheLastPage = dosStubSize % 512;1841    dos->FileSizeInPages = divideCeil(dosStubSize, 512);1842    dos->HeaderSizeInParagraphs = sizeof(dos_header) / 16;1843 1844    dos->AddressOfRelocationTable = sizeof(dos_header);1845    dos->AddressOfNewExeHeader = dosStubSize;1846 1847    memcpy(buf, dosProgram, sizeof(dosProgram));1848    buf += sizeof(dosProgram);1849  }1850 1851  // Make sure DOS stub is aligned to 8 bytes at this point1852  assert((buf - buffer->getBufferStart()) % 8 == 0);1853 1854  // Write PE magic1855  memcpy(buf, PEMagic, sizeof(PEMagic));1856  buf += sizeof(PEMagic);1857 1858  // Write COFF header1859  assert(coffHeaderOffset == buf - buffer->getBufferStart());1860  auto *coff = reinterpret_cast<coff_file_header *>(buf);1861  buf += sizeof(*coff);1862  SymbolTable &symtab =1863      ctx.config.machine == ARM64X ? *ctx.hybridSymtab : ctx.symtab;1864  coff->Machine = symtab.isEC() ? AMD64 : symtab.machine;1865  coff->NumberOfSections = ctx.outputSections.size();1866  coff->Characteristics = IMAGE_FILE_EXECUTABLE_IMAGE;1867  if (config->largeAddressAware)1868    coff->Characteristics |= IMAGE_FILE_LARGE_ADDRESS_AWARE;1869  if (!config->is64())1870    coff->Characteristics |= IMAGE_FILE_32BIT_MACHINE;1871  if (config->dll)1872    coff->Characteristics |= IMAGE_FILE_DLL;1873  if (config->driverUponly)1874    coff->Characteristics |= IMAGE_FILE_UP_SYSTEM_ONLY;1875  if (!config->relocatable)1876    coff->Characteristics |= IMAGE_FILE_RELOCS_STRIPPED;1877  if (config->swaprunCD)1878    coff->Characteristics |= IMAGE_FILE_REMOVABLE_RUN_FROM_SWAP;1879  if (config->swaprunNet)1880    coff->Characteristics |= IMAGE_FILE_NET_RUN_FROM_SWAP;1881  coff->SizeOfOptionalHeader =1882      sizeof(PEHeaderTy) + sizeof(data_directory) * numberOfDataDirectory;1883 1884  // Write PE header1885  assert(peHeaderOffset == buf - buffer->getBufferStart());1886  auto *pe = reinterpret_cast<PEHeaderTy *>(buf);1887  buf += sizeof(*pe);1888  pe->Magic = config->is64() ? PE32Header::PE32_PLUS : PE32Header::PE32;1889 1890  // If {Major,Minor}LinkerVersion is left at 0.0, then for some1891  // reason signing the resulting PE file with Authenticode produces a1892  // signature that fails to validate on Windows 7 (but is OK on 10).1893  // Set it to 14.0, which is what VS2015 outputs, and which avoids1894  // that problem.1895  pe->MajorLinkerVersion = 14;1896  pe->MinorLinkerVersion = 0;1897 1898  pe->ImageBase = config->imageBase;1899  pe->SectionAlignment = config->align;1900  pe->FileAlignment = config->fileAlign;1901  pe->MajorImageVersion = config->majorImageVersion;1902  pe->MinorImageVersion = config->minorImageVersion;1903  pe->MajorOperatingSystemVersion = config->majorOSVersion;1904  pe->MinorOperatingSystemVersion = config->minorOSVersion;1905  pe->MajorSubsystemVersion = config->majorSubsystemVersion;1906  pe->MinorSubsystemVersion = config->minorSubsystemVersion;1907  pe->Subsystem = config->subsystem;1908  pe->SizeOfImage = sizeOfImage;1909  pe->SizeOfHeaders = sizeOfHeaders;1910  if (!config->noEntry) {1911    Defined *entry = cast<Defined>(symtab.entry);1912    pe->AddressOfEntryPoint = entry->getRVA();1913    // Pointer to thumb code must have the LSB set, so adjust it.1914    if (config->machine == ARMNT)1915      pe->AddressOfEntryPoint |= 1;1916  }1917  pe->SizeOfStackReserve = config->stackReserve;1918  pe->SizeOfStackCommit = config->stackCommit;1919  pe->SizeOfHeapReserve = config->heapReserve;1920  pe->SizeOfHeapCommit = config->heapCommit;1921  if (config->appContainer)1922    pe->DLLCharacteristics |= IMAGE_DLL_CHARACTERISTICS_APPCONTAINER;1923  if (config->driverWdm)1924    pe->DLLCharacteristics |= IMAGE_DLL_CHARACTERISTICS_WDM_DRIVER;1925  if (config->dynamicBase)1926    pe->DLLCharacteristics |= IMAGE_DLL_CHARACTERISTICS_DYNAMIC_BASE;1927  if (config->highEntropyVA)1928    pe->DLLCharacteristics |= IMAGE_DLL_CHARACTERISTICS_HIGH_ENTROPY_VA;1929  if (!config->allowBind)1930    pe->DLLCharacteristics |= IMAGE_DLL_CHARACTERISTICS_NO_BIND;1931  if (config->nxCompat)1932    pe->DLLCharacteristics |= IMAGE_DLL_CHARACTERISTICS_NX_COMPAT;1933  if (!config->allowIsolation)1934    pe->DLLCharacteristics |= IMAGE_DLL_CHARACTERISTICS_NO_ISOLATION;1935  if (config->guardCF != GuardCFLevel::Off)1936    pe->DLLCharacteristics |= IMAGE_DLL_CHARACTERISTICS_GUARD_CF;1937  if (config->integrityCheck)1938    pe->DLLCharacteristics |= IMAGE_DLL_CHARACTERISTICS_FORCE_INTEGRITY;1939  if (setNoSEHCharacteristic || config->noSEH)1940    pe->DLLCharacteristics |= IMAGE_DLL_CHARACTERISTICS_NO_SEH;1941  if (config->terminalServerAware)1942    pe->DLLCharacteristics |= IMAGE_DLL_CHARACTERISTICS_TERMINAL_SERVER_AWARE;1943  pe->NumberOfRvaAndSize = numberOfDataDirectory;1944  if (textSec->getVirtualSize()) {1945    pe->BaseOfCode = textSec->getRVA();1946    pe->SizeOfCode = textSec->getRawSize();1947  }1948  pe->SizeOfInitializedData = getSizeOfInitializedData();1949 1950  // Write data directory1951  assert(!ctx.config.is64() ||1952         dataDirOffset64 == buf - buffer->getBufferStart());1953  auto *dir = reinterpret_cast<data_directory *>(buf);1954  buf += sizeof(*dir) * numberOfDataDirectory;1955  if (symtab.edataStart) {1956    dir[EXPORT_TABLE].RelativeVirtualAddress = symtab.edataStart->getRVA();1957    dir[EXPORT_TABLE].Size = symtab.edataEnd->getRVA() +1958                             symtab.edataEnd->getSize() -1959                             symtab.edataStart->getRVA();1960  }1961  if (importTableStart) {1962    dir[IMPORT_TABLE].RelativeVirtualAddress = importTableStart->getRVA();1963    dir[IMPORT_TABLE].Size = importTableSize;1964  }1965  if (iatStart) {1966    dir[IAT].RelativeVirtualAddress = iatStart->getRVA();1967    dir[IAT].Size = iatSize;1968  }1969  if (rsrcSec->getVirtualSize()) {1970    dir[RESOURCE_TABLE].RelativeVirtualAddress = rsrcSec->getRVA();1971    dir[RESOURCE_TABLE].Size = rsrcSec->getVirtualSize();1972  }1973  // ARM64EC (but not ARM64X) contains x86_64 exception table in data directory.1974  ChunkRange &exceptionTable =1975      ctx.config.machine == ARM64EC ? hybridPdata : pdata;1976  if (exceptionTable.first) {1977    dir[EXCEPTION_TABLE].RelativeVirtualAddress =1978        exceptionTable.first->getRVA();1979    dir[EXCEPTION_TABLE].Size = exceptionTable.last->getRVA() +1980                                exceptionTable.last->getSize() -1981                                exceptionTable.first->getRVA();1982  }1983  size_t relocSize = relocSec->getVirtualSize();1984  if (ctx.dynamicRelocs)1985    relocSize -= ctx.dynamicRelocs->getSize();1986  if (relocSize) {1987    dir[BASE_RELOCATION_TABLE].RelativeVirtualAddress = relocSec->getRVA();1988    dir[BASE_RELOCATION_TABLE].Size = relocSize;1989  }1990  if (Symbol *sym = symtab.findUnderscore("_tls_used")) {1991    if (Defined *b = dyn_cast<Defined>(sym)) {1992      dir[TLS_TABLE].RelativeVirtualAddress = b->getRVA();1993      dir[TLS_TABLE].Size = config->is64()1994                                ? sizeof(object::coff_tls_directory64)1995                                : sizeof(object::coff_tls_directory32);1996    }1997  }1998  if (debugDirectory) {1999    dir[DEBUG_DIRECTORY].RelativeVirtualAddress = debugDirectory->getRVA();2000    dir[DEBUG_DIRECTORY].Size = debugDirectory->getSize();2001  }2002  if (symtab.loadConfigSym) {2003    dir[LOAD_CONFIG_TABLE].RelativeVirtualAddress =2004        symtab.loadConfigSym->getRVA();2005    dir[LOAD_CONFIG_TABLE].Size = symtab.loadConfigSize;2006  }2007  if (!delayIdata.empty()) {2008    dir[DELAY_IMPORT_DESCRIPTOR].RelativeVirtualAddress =2009        delayIdata.getDirRVA();2010    dir[DELAY_IMPORT_DESCRIPTOR].Size = delayIdata.getDirSize();2011  }2012 2013  // Write section table2014  for (OutputSection *sec : ctx.outputSections) {2015    sec->writeHeaderTo(buf, config->debug);2016    buf += sizeof(coff_section);2017  }2018  sectionTable = ArrayRef<uint8_t>(2019      buf - ctx.outputSections.size() * sizeof(coff_section), buf);2020 2021  if (outputSymtab.empty() && strtab.empty())2022    return;2023 2024  coff->PointerToSymbolTable = pointerToSymbolTable;2025  uint32_t numberOfSymbols = outputSymtab.size();2026  coff->NumberOfSymbols = numberOfSymbols;2027  auto *symbolTable = reinterpret_cast<coff_symbol16 *>(2028      buffer->getBufferStart() + coff->PointerToSymbolTable);2029  for (size_t i = 0; i != numberOfSymbols; ++i)2030    symbolTable[i] = outputSymtab[i];2031  // Create the string table, it follows immediately after the symbol table.2032  // The first 4 bytes is length including itself.2033  buf = reinterpret_cast<uint8_t *>(&symbolTable[numberOfSymbols]);2034  strtab.write(buf);2035}2036 2037void Writer::openFile(StringRef path) {2038  buffer = CHECK(2039      FileOutputBuffer::create(path, fileSize, FileOutputBuffer::F_executable),2040      "failed to open " + path);2041}2042 2043void Writer::createSEHTable() {2044  SymbolRVASet handlers;2045  for (ObjFile *file : ctx.objFileInstances) {2046    if (!file->hasSafeSEH())2047      Err(ctx) << "/safeseh: " << file->getName()2048               << " is not compatible with SEH";2049    markSymbolsForRVATable(file, file->getSXDataChunks(), handlers);2050  }2051 2052  // Set the "no SEH" characteristic if there really were no handlers, or if2053  // there is no load config object to point to the table of handlers.2054  setNoSEHCharacteristic =2055      handlers.empty() || !ctx.symtab.findUnderscore("_load_config_used");2056 2057  maybeAddRVATable(std::move(handlers), "__safe_se_handler_table",2058                   "__safe_se_handler_count");2059}2060 2061// Add a symbol to an RVA set. Two symbols may have the same RVA, but an RVA set2062// cannot contain duplicates. Therefore, the set is uniqued by Chunk and the2063// symbol's offset into that Chunk.2064static void addSymbolToRVASet(SymbolRVASet &rvaSet, Defined *s) {2065  Chunk *c = s->getChunk();2066  if (!c)2067    return;2068  if (auto *sc = dyn_cast<SectionChunk>(c))2069    c = sc->repl; // Look through ICF replacement.2070  uint32_t off = s->getRVA() - (c ? c->getRVA() : 0);2071  rvaSet.insert({c, off});2072}2073 2074// Given a symbol, add it to the GFIDs table if it is a live, defined, function2075// symbol in an executable section.2076static void maybeAddAddressTakenFunction(SymbolRVASet &addressTakenSyms,2077                                         Symbol *s) {2078  if (!s)2079    return;2080 2081  switch (s->kind()) {2082  case Symbol::DefinedLocalImportKind:2083  case Symbol::DefinedImportDataKind:2084    // Defines an __imp_ pointer, so it is data, so it is ignored.2085    break;2086  case Symbol::DefinedCommonKind:2087    // Common is always data, so it is ignored.2088    break;2089  case Symbol::DefinedAbsoluteKind:2090    // Absolute is never code, synthetic generally isn't and usually isn't2091    // determinable.2092    break;2093  case Symbol::DefinedSyntheticKind:2094    // For EC export thunks, mark both the thunk itself and its target.2095    if (auto expChunk = dyn_cast_or_null<ECExportThunkChunk>(2096            cast<Defined>(s)->getChunk())) {2097      addSymbolToRVASet(addressTakenSyms, cast<Defined>(s));2098      addSymbolToRVASet(addressTakenSyms, expChunk->target);2099    }2100    break;2101  case Symbol::LazyArchiveKind:2102  case Symbol::LazyObjectKind:2103  case Symbol::LazyDLLSymbolKind:2104  case Symbol::UndefinedKind:2105    // Undefined symbols resolve to zero, so they don't have an RVA. Lazy2106    // symbols shouldn't have relocations.2107    break;2108 2109  case Symbol::DefinedImportThunkKind:2110    // Thunks are always code, include them.2111    addSymbolToRVASet(addressTakenSyms, cast<Defined>(s));2112    break;2113 2114  case Symbol::DefinedRegularKind: {2115    // This is a regular, defined, symbol from a COFF file. Mark the symbol as2116    // address taken if the symbol type is function and it's in an executable2117    // section.2118    auto *d = cast<DefinedRegular>(s);2119    if (d->getCOFFSymbol().getComplexType() == COFF::IMAGE_SYM_DTYPE_FUNCTION) {2120      SectionChunk *sc = dyn_cast<SectionChunk>(d->getChunk());2121      if (sc && sc->live &&2122          sc->getOutputCharacteristics() & IMAGE_SCN_MEM_EXECUTE)2123        addSymbolToRVASet(addressTakenSyms, d);2124    }2125    break;2126  }2127  }2128}2129 2130// Visit all relocations from all section contributions of this object file and2131// mark the relocation target as address-taken.2132void Writer::markSymbolsWithRelocations(ObjFile *file,2133                                        SymbolRVASet &usedSymbols) {2134  for (Chunk *c : file->getChunks()) {2135    // We only care about live section chunks. Common chunks and other chunks2136    // don't generally contain relocations.2137    SectionChunk *sc = dyn_cast<SectionChunk>(c);2138    if (!sc || !sc->live)2139      continue;2140 2141    for (const coff_relocation &reloc : sc->getRelocs()) {2142      if (ctx.config.machine == I386 &&2143          reloc.Type == COFF::IMAGE_REL_I386_REL32)2144        // Ignore relative relocations on x86. On x86_64 they can't be ignored2145        // since they're also used to compute absolute addresses.2146        continue;2147 2148      Symbol *ref = sc->file->getSymbol(reloc.SymbolTableIndex);2149      maybeAddAddressTakenFunction(usedSymbols, ref);2150    }2151  }2152}2153 2154// Create the guard function id table. This is a table of RVAs of all2155// address-taken functions. It is sorted and uniqued, just like the safe SEH2156// table.2157void Writer::createGuardCFTables() {2158  Configuration *config = &ctx.config;2159 2160  if (config->guardCF == GuardCFLevel::Off) {2161    // MSVC marks the entire image as instrumented if any input object was built2162    // with /guard:cf.2163    for (ObjFile *file : ctx.objFileInstances) {2164      if (file->hasGuardCF()) {2165        ctx.forEachSymtab([&](SymbolTable &symtab) {2166          Symbol *flagSym = symtab.findUnderscore("__guard_flags");2167          cast<DefinedAbsolute>(flagSym)->setVA(2168              uint32_t(GuardFlags::CF_INSTRUMENTED));2169        });2170        break;2171      }2172    }2173    return;2174  }2175 2176  SymbolRVASet addressTakenSyms;2177  SymbolRVASet giatsRVASet;2178  std::vector<Symbol *> giatsSymbols;2179  SymbolRVASet longJmpTargets;2180  SymbolRVASet ehContTargets;2181  for (ObjFile *file : ctx.objFileInstances) {2182    // If the object was compiled with /guard:cf, the address taken symbols2183    // are in .gfids$y sections, and the longjmp targets are in .gljmp$y2184    // sections. If the object was not compiled with /guard:cf, we assume there2185    // were no setjmp targets, and that all code symbols with relocations are2186    // possibly address-taken.2187    if (file->hasGuardCF()) {2188      markSymbolsForRVATable(file, file->getGuardFidChunks(), addressTakenSyms);2189      markSymbolsForRVATable(file, file->getGuardIATChunks(), giatsRVASet);2190      getSymbolsFromSections(file, file->getGuardIATChunks(), giatsSymbols);2191      markSymbolsForRVATable(file, file->getGuardLJmpChunks(), longJmpTargets);2192    } else {2193      markSymbolsWithRelocations(file, addressTakenSyms);2194    }2195    // If the object was compiled with /guard:ehcont, the ehcont targets are in2196    // .gehcont$y sections.2197    if (file->hasGuardEHCont())2198      markSymbolsForRVATable(file, file->getGuardEHContChunks(), ehContTargets);2199  }2200 2201  // Mark the image entry as address-taken.2202  ctx.forEachSymtab([&](SymbolTable &symtab) {2203    if (symtab.entry)2204      maybeAddAddressTakenFunction(addressTakenSyms, symtab.entry);2205 2206    // Mark exported symbols in executable sections as address-taken.2207    for (Export &e : symtab.exports)2208      maybeAddAddressTakenFunction(addressTakenSyms, e.sym);2209  });2210 2211  // For each entry in the .giats table, check if it has a corresponding load2212  // thunk (e.g. because the DLL that defines it will be delay-loaded) and, if2213  // so, add the load thunk to the address taken (.gfids) table.2214  for (Symbol *s : giatsSymbols) {2215    if (auto *di = dyn_cast<DefinedImportData>(s)) {2216      if (di->loadThunkSym)2217        addSymbolToRVASet(addressTakenSyms, di->loadThunkSym);2218    }2219  }2220 2221  // Ensure sections referenced in the gfid table are 16-byte aligned.2222  for (const ChunkAndOffset &c : addressTakenSyms)2223    if (c.inputChunk->getAlignment() < 16)2224      c.inputChunk->setAlignment(16);2225 2226  maybeAddRVATable(std::move(addressTakenSyms), "__guard_fids_table",2227                   "__guard_fids_count");2228 2229  // Add the Guard Address Taken IAT Entry Table (.giats).2230  maybeAddRVATable(std::move(giatsRVASet), "__guard_iat_table",2231                   "__guard_iat_count");2232 2233  // Add the longjmp target table unless the user told us not to.2234  if (config->guardCF & GuardCFLevel::LongJmp)2235    maybeAddRVATable(std::move(longJmpTargets), "__guard_longjmp_table",2236                     "__guard_longjmp_count");2237 2238  // Add the ehcont target table unless the user told us not to.2239  if (config->guardCF & GuardCFLevel::EHCont)2240    maybeAddRVATable(std::move(ehContTargets), "__guard_eh_cont_table",2241                     "__guard_eh_cont_count");2242 2243  // Set __guard_flags, which will be used in the load config to indicate that2244  // /guard:cf was enabled.2245  uint32_t guardFlags = uint32_t(GuardFlags::CF_INSTRUMENTED) |2246                        uint32_t(GuardFlags::CF_FUNCTION_TABLE_PRESENT);2247  if (config->guardCF & GuardCFLevel::LongJmp)2248    guardFlags |= uint32_t(GuardFlags::CF_LONGJUMP_TABLE_PRESENT);2249  if (config->guardCF & GuardCFLevel::EHCont)2250    guardFlags |= uint32_t(GuardFlags::EH_CONTINUATION_TABLE_PRESENT);2251  ctx.forEachSymtab([guardFlags](SymbolTable &symtab) {2252    Symbol *flagSym = symtab.findUnderscore("__guard_flags");2253    cast<DefinedAbsolute>(flagSym)->setVA(guardFlags);2254  });2255}2256 2257// Take a list of input sections containing symbol table indices and add those2258// symbols to a vector. The challenge is that symbol RVAs are not known and2259// depend on the table size, so we can't directly build a set of integers.2260void Writer::getSymbolsFromSections(ObjFile *file,2261                                    ArrayRef<SectionChunk *> symIdxChunks,2262                                    std::vector<Symbol *> &symbols) {2263  for (SectionChunk *c : symIdxChunks) {2264    // Skip sections discarded by linker GC. This comes up when a .gfids section2265    // is associated with something like a vtable and the vtable is discarded.2266    // In this case, the associated gfids section is discarded, and we don't2267    // mark the virtual member functions as address-taken by the vtable.2268    if (!c->live)2269      continue;2270 2271    // Validate that the contents look like symbol table indices.2272    ArrayRef<uint8_t> data = c->getContents();2273    if (data.size() % 4 != 0) {2274      Warn(ctx) << "ignoring " << c->getSectionName()2275                << " symbol table index section in object " << file;2276      continue;2277    }2278 2279    // Read each symbol table index and check if that symbol was included in the2280    // final link. If so, add it to the vector of symbols.2281    ArrayRef<ulittle32_t> symIndices(2282        reinterpret_cast<const ulittle32_t *>(data.data()), data.size() / 4);2283    ArrayRef<Symbol *> objSymbols = file->getSymbols();2284    for (uint32_t symIndex : symIndices) {2285      if (symIndex >= objSymbols.size()) {2286        Warn(ctx) << "ignoring invalid symbol table index in section "2287                  << c->getSectionName() << " in object " << file;2288        continue;2289      }2290      if (Symbol *s = objSymbols[symIndex]) {2291        if (s->isLive())2292          symbols.push_back(cast<Symbol>(s));2293      }2294    }2295  }2296}2297 2298// Take a list of input sections containing symbol table indices and add those2299// symbols to an RVA table.2300void Writer::markSymbolsForRVATable(ObjFile *file,2301                                    ArrayRef<SectionChunk *> symIdxChunks,2302                                    SymbolRVASet &tableSymbols) {2303  std::vector<Symbol *> syms;2304  getSymbolsFromSections(file, symIdxChunks, syms);2305 2306  for (Symbol *s : syms)2307    addSymbolToRVASet(tableSymbols, cast<Defined>(s));2308}2309 2310// Replace the absolute table symbol with a synthetic symbol pointing to2311// tableChunk so that we can emit base relocations for it and resolve section2312// relative relocations.2313void Writer::maybeAddRVATable(SymbolRVASet tableSymbols, StringRef tableSym,2314                              StringRef countSym, bool hasFlag) {2315  if (tableSymbols.empty())2316    return;2317 2318  NonSectionChunk *tableChunk;2319  if (hasFlag)2320    tableChunk = make<RVAFlagTableChunk>(std::move(tableSymbols));2321  else2322    tableChunk = make<RVATableChunk>(std::move(tableSymbols));2323  rdataSec->addChunk(tableChunk);2324 2325  ctx.forEachSymtab([&](SymbolTable &symtab) {2326    Symbol *t = symtab.findUnderscore(tableSym);2327    Symbol *c = symtab.findUnderscore(countSym);2328    replaceSymbol<DefinedSynthetic>(t, t->getName(), tableChunk);2329    cast<DefinedAbsolute>(c)->setVA(tableChunk->getSize() / (hasFlag ? 5 : 4));2330  });2331}2332 2333// Create CHPE metadata chunks.2334void Writer::createECChunks() {2335  if (!ctx.symtab.isEC())2336    return;2337 2338  for (Symbol *s : ctx.symtab.expSymbols) {2339    auto sym = dyn_cast<Defined>(s);2340    if (!sym || !sym->getChunk())2341      continue;2342    if (auto thunk = dyn_cast<ECExportThunkChunk>(sym->getChunk())) {2343      hexpthkSec->addChunk(thunk);2344      exportThunks.push_back({thunk, thunk->target});2345    } else if (auto def = dyn_cast<DefinedRegular>(sym)) {2346      // Allow section chunk to be treated as an export thunk if it looks like2347      // one.2348      SectionChunk *chunk = def->getChunk();2349      if (!chunk->live || chunk->getMachine() != AMD64)2350        continue;2351      assert(sym->getName().starts_with("EXP+"));2352      StringRef targetName = sym->getName().substr(strlen("EXP+"));2353      // If EXP+#foo is an export thunk of a hybrid patchable function,2354      // we should use the #foo$hp_target symbol as the redirection target.2355      // First, try to look up the $hp_target symbol. If it can't be found,2356      // assume it's a regular function and look for #foo instead.2357      Symbol *targetSym = ctx.symtab.find((targetName + "$hp_target").str());2358      if (!targetSym)2359        targetSym = ctx.symtab.find(targetName);2360      Defined *t = dyn_cast_or_null<Defined>(targetSym);2361      if (t && isArm64EC(t->getChunk()->getMachine()))2362        exportThunks.push_back({chunk, t});2363    }2364  }2365 2366  auto codeMapChunk = make<ECCodeMapChunk>(codeMap);2367  rdataSec->addChunk(codeMapChunk);2368  Symbol *codeMapSym = ctx.symtab.findUnderscore("__hybrid_code_map");2369  replaceSymbol<DefinedSynthetic>(codeMapSym, codeMapSym->getName(),2370                                  codeMapChunk);2371 2372  CHPECodeRangesChunk *ranges = make<CHPECodeRangesChunk>(exportThunks);2373  rdataSec->addChunk(ranges);2374  Symbol *rangesSym =2375      ctx.symtab.findUnderscore("__x64_code_ranges_to_entry_points");2376  replaceSymbol<DefinedSynthetic>(rangesSym, rangesSym->getName(), ranges);2377 2378  CHPERedirectionChunk *entryPoints = make<CHPERedirectionChunk>(exportThunks);2379  a64xrmSec->addChunk(entryPoints);2380  Symbol *entryPointsSym =2381      ctx.symtab.findUnderscore("__arm64x_redirection_metadata");2382  replaceSymbol<DefinedSynthetic>(entryPointsSym, entryPointsSym->getName(),2383                                  entryPoints);2384 2385  for (auto thunk : ctx.symtab.sameAddressThunks) {2386    // Relocation values are set later in setECSymbols.2387    ctx.dynamicRelocs->add(IMAGE_DVRT_ARM64X_FIXUP_TYPE_VALUE, sizeof(uint32_t),2388                           thunk);2389    ctx.dynamicRelocs->add(IMAGE_DVRT_ARM64X_FIXUP_TYPE_VALUE, sizeof(uint32_t),2390                           Arm64XRelocVal(thunk, sizeof(uint32_t)));2391  }2392}2393 2394// MinGW specific. Gather all relocations that are imported from a DLL even2395// though the code didn't expect it to, produce the table that the runtime2396// uses for fixing them up, and provide the synthetic symbols that the2397// runtime uses for finding the table.2398void Writer::createRuntimePseudoRelocs() {2399  ctx.forEachSymtab([&](SymbolTable &symtab) {2400    std::vector<RuntimePseudoReloc> rels;2401 2402    for (Chunk *c : ctx.driver.getChunks()) {2403      auto *sc = dyn_cast<SectionChunk>(c);2404      if (!sc || !sc->live || &sc->file->symtab != &symtab)2405        continue;2406      // Don't create pseudo relocations for sections that won't be2407      // mapped at runtime.2408      if (sc->header->Characteristics & IMAGE_SCN_MEM_DISCARDABLE)2409        continue;2410      sc->getRuntimePseudoRelocs(rels);2411    }2412 2413    if (!ctx.config.pseudoRelocs) {2414      // Not writing any pseudo relocs; if some were needed, error out and2415      // indicate what required them.2416      for (const RuntimePseudoReloc &rpr : rels)2417        Err(ctx) << "automatic dllimport of " << rpr.sym->getName() << " in "2418                 << toString(rpr.target->file)2419                 << " requires pseudo relocations";2420      return;2421    }2422 2423    if (!rels.empty()) {2424      Log(ctx) << "Writing " << Twine(rels.size())2425               << " runtime pseudo relocations";2426      const char *symbolName = "_pei386_runtime_relocator";2427      Symbol *relocator = symtab.findUnderscore(symbolName);2428      if (!relocator)2429        Err(ctx)2430            << "output image has runtime pseudo relocations, but the function "2431            << symbolName2432            << " is missing; it is needed for fixing the relocations at "2433               "runtime";2434    }2435 2436    PseudoRelocTableChunk *table = make<PseudoRelocTableChunk>(rels);2437    rdataSec->addChunk(table);2438    EmptyChunk *endOfList = make<EmptyChunk>();2439    rdataSec->addChunk(endOfList);2440 2441    Symbol *headSym = symtab.findUnderscore("__RUNTIME_PSEUDO_RELOC_LIST__");2442    Symbol *endSym = symtab.findUnderscore("__RUNTIME_PSEUDO_RELOC_LIST_END__");2443    replaceSymbol<DefinedSynthetic>(headSym, headSym->getName(), table);2444    replaceSymbol<DefinedSynthetic>(endSym, endSym->getName(), endOfList);2445  });2446}2447 2448// MinGW specific.2449// The MinGW .ctors and .dtors lists have sentinels at each end;2450// a (uintptr_t)-1 at the start and a (uintptr_t)0 at the end.2451// There's a symbol pointing to the start sentinel pointer, __CTOR_LIST__2452// and __DTOR_LIST__ respectively.2453void Writer::insertCtorDtorSymbols() {2454  ctx.forEachSymtab([&](SymbolTable &symtab) {2455    AbsolutePointerChunk *ctorListHead = make<AbsolutePointerChunk>(symtab, -1);2456    AbsolutePointerChunk *ctorListEnd = make<AbsolutePointerChunk>(symtab, 0);2457    AbsolutePointerChunk *dtorListHead = make<AbsolutePointerChunk>(symtab, -1);2458    AbsolutePointerChunk *dtorListEnd = make<AbsolutePointerChunk>(symtab, 0);2459    ctorsSec->insertChunkAtStart(ctorListHead);2460    ctorsSec->addChunk(ctorListEnd);2461    dtorsSec->insertChunkAtStart(dtorListHead);2462    dtorsSec->addChunk(dtorListEnd);2463 2464    Symbol *ctorListSym = symtab.findUnderscore("__CTOR_LIST__");2465    Symbol *dtorListSym = symtab.findUnderscore("__DTOR_LIST__");2466    replaceSymbol<DefinedSynthetic>(ctorListSym, ctorListSym->getName(),2467                                    ctorListHead);2468    replaceSymbol<DefinedSynthetic>(dtorListSym, dtorListSym->getName(),2469                                    dtorListHead);2470  });2471 2472  if (ctx.hybridSymtab) {2473    ctorsSec->splitECChunks();2474    dtorsSec->splitECChunks();2475  }2476}2477 2478// MinGW (really, Cygwin) specific.2479// The Cygwin startup code uses __data_start__ __data_end__ __bss_start__2480// and __bss_end__ to know what to copy during fork emulation.2481void Writer::insertBssDataStartEndSymbols() {2482  if (!dataSec->chunks.empty()) {2483    Symbol *dataStartSym = ctx.symtab.find("__data_start__");2484    Symbol *dataEndSym = ctx.symtab.find("__data_end__");2485    Chunk *endChunk = dataSec->chunks.back();2486    replaceSymbol<DefinedSynthetic>(dataStartSym, dataStartSym->getName(),2487                                    dataSec->chunks.front());2488    replaceSymbol<DefinedSynthetic>(dataEndSym, dataEndSym->getName(), endChunk,2489                                    endChunk->getSize());2490  }2491 2492  if (!bssSec->chunks.empty()) {2493    Symbol *bssStartSym = ctx.symtab.find("__bss_start__");2494    Symbol *bssEndSym = ctx.symtab.find("__bss_end__");2495    Chunk *endChunk = bssSec->chunks.back();2496    replaceSymbol<DefinedSynthetic>(bssStartSym, bssStartSym->getName(),2497                                    bssSec->chunks.front());2498    replaceSymbol<DefinedSynthetic>(bssEndSym, bssEndSym->getName(), endChunk,2499                                    endChunk->getSize());2500  }2501}2502 2503// Handles /section options to allow users to overwrite2504// section attributes.2505void Writer::setSectionPermissions() {2506  llvm::TimeTraceScope timeScope("Sections permissions");2507  for (auto &p : ctx.config.section) {2508    StringRef name = p.first;2509    uint32_t perm = p.second;2510    for (OutputSection *sec : ctx.outputSections)2511      if (sec->name == name)2512        sec->setPermissions(perm);2513  }2514}2515 2516// Set symbols used by ARM64EC metadata.2517void Writer::setECSymbols() {2518  if (!ctx.symtab.isEC())2519    return;2520 2521  llvm::stable_sort(exportThunks, [](const std::pair<Chunk *, Defined *> &a,2522                                     const std::pair<Chunk *, Defined *> &b) {2523    return a.first->getRVA() < b.first->getRVA();2524  });2525 2526  ChunkRange &chpePdata = ctx.config.machine == ARM64X ? hybridPdata : pdata;2527  Symbol *rfeTableSym = ctx.symtab.findUnderscore("__arm64x_extra_rfe_table");2528  replaceSymbol<DefinedSynthetic>(rfeTableSym, "__arm64x_extra_rfe_table",2529                                  chpePdata.first);2530 2531  if (chpePdata.first) {2532    Symbol *rfeSizeSym =2533        ctx.symtab.findUnderscore("__arm64x_extra_rfe_table_size");2534    cast<DefinedAbsolute>(rfeSizeSym)2535        ->setVA(chpePdata.last->getRVA() + chpePdata.last->getSize() -2536                chpePdata.first->getRVA());2537  }2538 2539  Symbol *rangesCountSym =2540      ctx.symtab.findUnderscore("__x64_code_ranges_to_entry_points_count");2541  cast<DefinedAbsolute>(rangesCountSym)->setVA(exportThunks.size());2542 2543  Symbol *entryPointCountSym =2544      ctx.symtab.findUnderscore("__arm64x_redirection_metadata_count");2545  cast<DefinedAbsolute>(entryPointCountSym)->setVA(exportThunks.size());2546 2547  Symbol *iatSym = ctx.symtab.findUnderscore("__hybrid_auxiliary_iat");2548  replaceSymbol<DefinedSynthetic>(iatSym, "__hybrid_auxiliary_iat",2549                                  idata.auxIat.empty() ? nullptr2550                                                       : idata.auxIat.front());2551 2552  Symbol *iatCopySym = ctx.symtab.findUnderscore("__hybrid_auxiliary_iat_copy");2553  replaceSymbol<DefinedSynthetic>(2554      iatCopySym, "__hybrid_auxiliary_iat_copy",2555      idata.auxIatCopy.empty() ? nullptr : idata.auxIatCopy.front());2556 2557  Symbol *delayIatSym =2558      ctx.symtab.findUnderscore("__hybrid_auxiliary_delayload_iat");2559  replaceSymbol<DefinedSynthetic>(2560      delayIatSym, "__hybrid_auxiliary_delayload_iat",2561      delayIdata.getAuxIat().empty() ? nullptr2562                                     : delayIdata.getAuxIat().front());2563 2564  Symbol *delayIatCopySym =2565      ctx.symtab.findUnderscore("__hybrid_auxiliary_delayload_iat_copy");2566  replaceSymbol<DefinedSynthetic>(2567      delayIatCopySym, "__hybrid_auxiliary_delayload_iat_copy",2568      delayIdata.getAuxIatCopy().empty() ? nullptr2569                                         : delayIdata.getAuxIatCopy().front());2570 2571  if (ctx.config.machine == ARM64X) {2572    // For the hybrid image, set the alternate entry point to the EC entry2573    // point. In the hybrid view, it is swapped to the native entry point2574    // using ARM64X relocations.2575    if (auto altEntrySym = cast_or_null<Defined>(ctx.symtab.entry)) {2576      // If the entry is an EC export thunk, use its target instead.2577      if (auto thunkChunk =2578              dyn_cast<ECExportThunkChunk>(altEntrySym->getChunk()))2579        altEntrySym = thunkChunk->target;2580      ctx.symtab.findUnderscore("__arm64x_native_entrypoint")2581          ->replaceKeepingName(altEntrySym, sizeof(SymbolUnion));2582    }2583 2584    if (ctx.symtab.edataStart)2585      ctx.dynamicRelocs->set(2586          dataDirOffset64 + EXPORT_TABLE * sizeof(data_directory) +2587              offsetof(data_directory, Size),2588          ctx.symtab.edataEnd->getRVA() - ctx.symtab.edataStart->getRVA() +2589              ctx.symtab.edataEnd->getSize());2590    if (hybridPdata.first)2591      ctx.dynamicRelocs->set(2592          dataDirOffset64 + EXCEPTION_TABLE * sizeof(data_directory) +2593              offsetof(data_directory, Size),2594          hybridPdata.last->getRVA() - hybridPdata.first->getRVA() +2595              hybridPdata.last->getSize());2596    if (chpeSym && pdata.first)2597      ctx.dynamicRelocs->set(2598          chpeSym->getRVA() + offsetof(chpe_metadata, ExtraRFETableSize),2599          pdata.last->getRVA() + pdata.last->getSize() - pdata.first->getRVA());2600  }2601 2602  for (SameAddressThunkARM64EC *thunk : ctx.symtab.sameAddressThunks)2603    thunk->setDynamicRelocs(ctx);2604}2605 2606// Write section contents to a mmap'ed file.2607void Writer::writeSections() {2608  llvm::TimeTraceScope timeScope("Write sections");2609  uint8_t *buf = buffer->getBufferStart();2610  for (OutputSection *sec : ctx.outputSections) {2611    uint8_t *secBuf = buf + sec->getFileOff();2612    // Fill gaps between functions in .text with INT3 instructions2613    // instead of leaving as NUL bytes (which can be interpreted as2614    // ADD instructions). Only fill the gaps between chunks. Most2615    // chunks overwrite it anyway, but uninitialized data chunks2616    // merged into a code section don't.2617    if ((sec->header.Characteristics & IMAGE_SCN_CNT_CODE) &&2618        (ctx.config.machine == AMD64 || ctx.config.machine == I386)) {2619      uint32_t prevEnd = 0;2620      for (Chunk *c : sec->chunks) {2621        uint32_t off = c->getRVA() - sec->getRVA();2622        memset(secBuf + prevEnd, 0xCC, off - prevEnd);2623        prevEnd = off + c->getSize();2624      }2625      memset(secBuf + prevEnd, 0xCC, sec->getRawSize() - prevEnd);2626    }2627 2628    parallelForEach(sec->chunks, [&](Chunk *c) {2629      uint8_t *buf = secBuf + c->getRVA() - sec->getRVA();2630      c->writeTo(buf);2631 2632      // Write the offset to EC entry thunk preceding section contents. The low2633      // bit is always set, so it's effectively an offset from the last byte of2634      // the offset.2635      if (Defined *entryThunk = c->getEntryThunk())2636        write32le(buf - sizeof(uint32_t),2637                  entryThunk->getRVA() - c->getRVA() + 1);2638    });2639  }2640}2641 2642void Writer::writeBuildId() {2643  llvm::TimeTraceScope timeScope("Write build ID");2644 2645  // There are two important parts to the build ID.2646  // 1) If building with debug info, the COFF debug directory contains a2647  //    timestamp as well as a Guid and Age of the PDB.2648  // 2) In all cases, the PE COFF file header also contains a timestamp.2649  // For reproducibility, instead of a timestamp we want to use a hash of the2650  // PE contents.2651  Configuration *config = &ctx.config;2652  bool generateSyntheticBuildId = config->buildIDHash == BuildIDHash::Binary;2653  if (generateSyntheticBuildId) {2654    assert(buildId && "BuildId is not set!");2655    // BuildId->BuildId was filled in when the PDB was written.2656  }2657 2658  // At this point the only fields in the COFF file which remain unset are the2659  // "timestamp" in the COFF file header, and the ones in the coff debug2660  // directory.  Now we can hash the file and write that hash to the various2661  // timestamp fields in the file.2662  StringRef outputFileData(2663      reinterpret_cast<const char *>(buffer->getBufferStart()),2664      buffer->getBufferSize());2665 2666  uint32_t timestamp = config->timestamp;2667  uint64_t hash = 0;2668 2669  if (config->repro || generateSyntheticBuildId)2670    hash = xxh3_64bits(outputFileData);2671 2672  if (config->repro)2673    timestamp = static_cast<uint32_t>(hash);2674 2675  if (generateSyntheticBuildId) {2676    buildId->buildId->PDB70.CVSignature = OMF::Signature::PDB70;2677    buildId->buildId->PDB70.Age = 1;2678    memcpy(buildId->buildId->PDB70.Signature, &hash, 8);2679    // xxhash only gives us 8 bytes, so put some fixed data in the other half.2680    memcpy(&buildId->buildId->PDB70.Signature[8], "LLD PDB.", 8);2681  }2682 2683  if (debugDirectory)2684    debugDirectory->setTimeDateStamp(timestamp);2685 2686  uint8_t *buf = buffer->getBufferStart();2687  buf += dosStubSize + sizeof(PEMagic);2688  object::coff_file_header *coffHeader =2689      reinterpret_cast<coff_file_header *>(buf);2690  coffHeader->TimeDateStamp = timestamp;2691}2692 2693// Sort .pdata section contents according to PE/COFF spec 5.5.2694template <typename T>2695void Writer::sortExceptionTable(ChunkRange &exceptionTable) {2696  if (!exceptionTable.first)2697    return;2698 2699  // We assume .pdata contains function table entries only.2700  auto bufAddr = [&](Chunk *c) {2701    OutputSection *os = ctx.getOutputSection(c);2702    return buffer->getBufferStart() + os->getFileOff() + c->getRVA() -2703           os->getRVA();2704  };2705  uint8_t *begin = bufAddr(exceptionTable.first);2706  uint8_t *end = bufAddr(exceptionTable.last) + exceptionTable.last->getSize();2707  if ((end - begin) % sizeof(T) != 0) {2708    Fatal(ctx) << "unexpected .pdata size: " << (end - begin)2709               << " is not a multiple of " << sizeof(T);2710  }2711 2712  parallelSort(MutableArrayRef<T>(reinterpret_cast<T *>(begin),2713                                  reinterpret_cast<T *>(end)),2714               [](const T &a, const T &b) { return a.begin < b.begin; });2715}2716 2717// Sort .pdata section contents according to PE/COFF spec 5.5.2718void Writer::sortExceptionTables() {2719  llvm::TimeTraceScope timeScope("Sort exception table");2720 2721  struct EntryX64 {2722    ulittle32_t begin, end, unwind;2723  };2724  struct EntryArm {2725    ulittle32_t begin, unwind;2726  };2727 2728  switch (ctx.config.machine) {2729  case AMD64:2730    sortExceptionTable<EntryX64>(pdata);2731    break;2732  case ARM64EC:2733  case ARM64X:2734    sortExceptionTable<EntryX64>(hybridPdata);2735    [[fallthrough]];2736  case ARMNT:2737  case ARM64:2738    sortExceptionTable<EntryArm>(pdata);2739    break;2740  default:2741    if (pdata.first)2742      ctx.e.errs() << "warning: don't know how to handle .pdata\n";2743    break;2744  }2745}2746 2747// The CRT section contains, among other things, the array of function2748// pointers that initialize every global variable that is not trivially2749// constructed. The CRT calls them one after the other prior to invoking2750// main().2751//2752// As per C++ spec, 3.6.2/2.3,2753// "Variables with ordered initialization defined within a single2754// translation unit shall be initialized in the order of their definitions2755// in the translation unit"2756//2757// It is therefore critical to sort the chunks containing the function2758// pointers in the order that they are listed in the object file (top to2759// bottom), otherwise global objects might not be initialized in the2760// correct order.2761void Writer::sortCRTSectionChunks(std::vector<Chunk *> &chunks) {2762  auto sectionChunkOrder = [](const Chunk *a, const Chunk *b) {2763    auto sa = dyn_cast<SectionChunk>(a);2764    auto sb = dyn_cast<SectionChunk>(b);2765    assert(sa && sb && "Non-section chunks in CRT section!");2766 2767    StringRef sAObj = sa->file->mb.getBufferIdentifier();2768    StringRef sBObj = sb->file->mb.getBufferIdentifier();2769 2770    return sAObj == sBObj && sa->getSectionNumber() < sb->getSectionNumber();2771  };2772  llvm::stable_sort(chunks, sectionChunkOrder);2773 2774  if (ctx.config.verbose) {2775    for (auto &c : chunks) {2776      auto sc = dyn_cast<SectionChunk>(c);2777      Log(ctx) << "  " << sc->file->mb.getBufferIdentifier().str()2778               << ", SectionID: " << sc->getSectionNumber();2779    }2780  }2781}2782 2783OutputSection *Writer::findSection(StringRef name) {2784  for (OutputSection *sec : ctx.outputSections)2785    if (sec->name == name)2786      return sec;2787  return nullptr;2788}2789 2790uint32_t Writer::getSizeOfInitializedData() {2791  uint32_t res = 0;2792  for (OutputSection *s : ctx.outputSections)2793    if (s->header.Characteristics & IMAGE_SCN_CNT_INITIALIZED_DATA)2794      res += s->getRawSize();2795  return res;2796}2797 2798// Add base relocations to .reloc section.2799void Writer::addBaserels() {2800  if (!ctx.config.relocatable)2801    return;2802  std::vector<Baserel> v;2803  for (OutputSection *sec : ctx.outputSections) {2804    if (sec->header.Characteristics & IMAGE_SCN_MEM_DISCARDABLE)2805      continue;2806    llvm::TimeTraceScope timeScope("Base relocations: ", sec->name);2807    // Collect all locations for base relocations.2808    for (Chunk *c : sec->chunks)2809      c->getBaserels(&v);2810    // Add the addresses to .reloc section.2811    if (!v.empty())2812      addBaserelBlocks(v);2813    v.clear();2814  }2815}2816 2817// Add addresses to .reloc section. Note that addresses are grouped by page.2818void Writer::addBaserelBlocks(std::vector<Baserel> &v) {2819  const uint32_t mask = ~uint32_t(pageSize - 1);2820  uint32_t page = v[0].rva & mask;2821  size_t i = 0, j = 1;2822  llvm::sort(v,2823             [](const Baserel &x, const Baserel &y) { return x.rva < y.rva; });2824  for (size_t e = v.size(); j < e; ++j) {2825    uint32_t p = v[j].rva & mask;2826    if (p == page)2827      continue;2828    relocSec->addChunk(make<BaserelChunk>(page, &v[i], &v[0] + j));2829    i = j;2830    page = p;2831  }2832  if (i == j)2833    return;2834  relocSec->addChunk(make<BaserelChunk>(page, &v[i], &v[0] + j));2835}2836 2837void Writer::createDynamicRelocs() {2838  if (!ctx.dynamicRelocs)2839    return;2840 2841  // Adjust the Machine field in the COFF header to AMD64.2842  ctx.dynamicRelocs->add(IMAGE_DVRT_ARM64X_FIXUP_TYPE_VALUE, sizeof(uint16_t),2843                         coffHeaderOffset + offsetof(coff_file_header, Machine),2844                         AMD64);2845 2846  if (ctx.symtab.entry != ctx.hybridSymtab->entry ||2847      pdata.first != hybridPdata.first) {2848    chpeSym = cast_or_null<DefinedRegular>(2849        ctx.symtab.findUnderscore("__chpe_metadata"));2850    if (!chpeSym)2851      Warn(ctx) << "'__chpe_metadata' is missing for ARM64X target";2852  }2853 2854  if (ctx.symtab.entry != ctx.hybridSymtab->entry) {2855    ctx.dynamicRelocs->add(IMAGE_DVRT_ARM64X_FIXUP_TYPE_VALUE, sizeof(uint32_t),2856                           peHeaderOffset +2857                               offsetof(pe32plus_header, AddressOfEntryPoint),2858                           cast_or_null<Defined>(ctx.symtab.entry));2859 2860    // Swap the alternate entry point in the CHPE metadata.2861    if (chpeSym)2862      ctx.dynamicRelocs->add(2863          IMAGE_DVRT_ARM64X_FIXUP_TYPE_VALUE, sizeof(uint32_t),2864          Arm64XRelocVal(chpeSym, offsetof(chpe_metadata, AlternateEntryPoint)),2865          cast_or_null<Defined>(ctx.hybridSymtab->entry));2866  }2867 2868  if (ctx.symtab.edataStart != ctx.hybridSymtab->edataStart) {2869    ctx.dynamicRelocs->add(IMAGE_DVRT_ARM64X_FIXUP_TYPE_VALUE, sizeof(uint32_t),2870                           dataDirOffset64 +2871                               EXPORT_TABLE * sizeof(data_directory) +2872                               offsetof(data_directory, RelativeVirtualAddress),2873                           ctx.symtab.edataStart);2874    // The Size value is assigned after addresses are finalized.2875    ctx.dynamicRelocs->add(IMAGE_DVRT_ARM64X_FIXUP_TYPE_VALUE, sizeof(uint32_t),2876                           dataDirOffset64 +2877                               EXPORT_TABLE * sizeof(data_directory) +2878                               offsetof(data_directory, Size));2879  }2880 2881  if (pdata.first != hybridPdata.first) {2882    ctx.dynamicRelocs->add(IMAGE_DVRT_ARM64X_FIXUP_TYPE_VALUE, sizeof(uint32_t),2883                           dataDirOffset64 +2884                               EXCEPTION_TABLE * sizeof(data_directory) +2885                               offsetof(data_directory, RelativeVirtualAddress),2886                           hybridPdata.first);2887    // The Size value is assigned after addresses are finalized.2888    ctx.dynamicRelocs->add(IMAGE_DVRT_ARM64X_FIXUP_TYPE_VALUE, sizeof(uint32_t),2889                           dataDirOffset64 +2890                               EXCEPTION_TABLE * sizeof(data_directory) +2891                               offsetof(data_directory, Size));2892 2893    // Swap ExtraRFETable in the CHPE metadata.2894    if (chpeSym) {2895      ctx.dynamicRelocs->add(2896          IMAGE_DVRT_ARM64X_FIXUP_TYPE_VALUE, sizeof(uint32_t),2897          Arm64XRelocVal(chpeSym, offsetof(chpe_metadata, ExtraRFETable)),2898          pdata.first);2899      // The Size value is assigned after addresses are finalized.2900      ctx.dynamicRelocs->add(2901          IMAGE_DVRT_ARM64X_FIXUP_TYPE_VALUE, sizeof(uint32_t),2902          Arm64XRelocVal(chpeSym, offsetof(chpe_metadata, ExtraRFETableSize)));2903    }2904  }2905 2906  // Set the hybrid load config to the EC load config.2907  ctx.dynamicRelocs->add(IMAGE_DVRT_ARM64X_FIXUP_TYPE_VALUE, sizeof(uint32_t),2908                         dataDirOffset64 +2909                             LOAD_CONFIG_TABLE * sizeof(data_directory) +2910                             offsetof(data_directory, RelativeVirtualAddress),2911                         ctx.symtab.loadConfigSym);2912  ctx.dynamicRelocs->add(IMAGE_DVRT_ARM64X_FIXUP_TYPE_VALUE, sizeof(uint32_t),2913                         dataDirOffset64 +2914                             LOAD_CONFIG_TABLE * sizeof(data_directory) +2915                             offsetof(data_directory, Size),2916                         ctx.symtab.loadConfigSize);2917}2918 2919PartialSection *Writer::createPartialSection(StringRef name,2920                                             uint32_t outChars) {2921  PartialSection *&pSec = partialSections[{name, outChars}];2922  if (pSec)2923    return pSec;2924  pSec = make<PartialSection>(name, outChars);2925  return pSec;2926}2927 2928PartialSection *Writer::findPartialSection(StringRef name, uint32_t outChars) {2929  auto it = partialSections.find({name, outChars});2930  if (it != partialSections.end())2931    return it->second;2932  return nullptr;2933}2934 2935void Writer::fixTlsAlignment() {2936  Defined *tlsSym =2937      dyn_cast_or_null<Defined>(ctx.symtab.findUnderscore("_tls_used"));2938  if (!tlsSym)2939    return;2940 2941  OutputSection *sec = ctx.getOutputSection(tlsSym->getChunk());2942  assert(sec && tlsSym->getRVA() >= sec->getRVA() &&2943         "no output section for _tls_used");2944 2945  uint8_t *secBuf = buffer->getBufferStart() + sec->getFileOff();2946  uint64_t tlsOffset = tlsSym->getRVA() - sec->getRVA();2947  uint64_t directorySize = ctx.config.is64()2948                               ? sizeof(object::coff_tls_directory64)2949                               : sizeof(object::coff_tls_directory32);2950 2951  if (tlsOffset + directorySize > sec->getRawSize())2952    Fatal(ctx) << "_tls_used sym is malformed";2953 2954  if (ctx.config.is64()) {2955    object::coff_tls_directory64 *tlsDir =2956        reinterpret_cast<object::coff_tls_directory64 *>(&secBuf[tlsOffset]);2957    tlsDir->setAlignment(tlsAlignment);2958  } else {2959    object::coff_tls_directory32 *tlsDir =2960        reinterpret_cast<object::coff_tls_directory32 *>(&secBuf[tlsOffset]);2961    tlsDir->setAlignment(tlsAlignment);2962  }2963}2964 2965void Writer::prepareLoadConfig() {2966  ctx.forEachActiveSymtab([&](SymbolTable &symtab) {2967    if (!symtab.loadConfigSym)2968      return;2969 2970    OutputSection *sec = ctx.getOutputSection(symtab.loadConfigSym->getChunk());2971    uint8_t *secBuf = buffer->getBufferStart() + sec->getFileOff();2972    uint8_t *symBuf = secBuf + (symtab.loadConfigSym->getRVA() - sec->getRVA());2973 2974    if (ctx.config.is64())2975      prepareLoadConfig(symtab,2976                        reinterpret_cast<coff_load_configuration64 *>(symBuf));2977    else2978      prepareLoadConfig(symtab,2979                        reinterpret_cast<coff_load_configuration32 *>(symBuf));2980  });2981}2982 2983template <typename T>2984void Writer::prepareLoadConfig(SymbolTable &symtab, T *loadConfig) {2985  size_t loadConfigSize = loadConfig->Size;2986 2987#define RETURN_IF_NOT_CONTAINS(field)                                          \2988  if (loadConfigSize < offsetof(T, field) + sizeof(T::field)) {                \2989    Warn(ctx) << "'_load_config_used' structure too small to include " #field; \2990    return;                                                                    \2991  }2992 2993#define IF_CONTAINS(field)                                                     \2994  if (loadConfigSize >= offsetof(T, field) + sizeof(T::field))2995 2996#define CHECK_VA(field, sym)                                                   \2997  if (auto *s = dyn_cast<DefinedSynthetic>(symtab.findUnderscore(sym)))        \2998    if (loadConfig->field != ctx.config.imageBase + s->getRVA())               \2999      Warn(ctx) << #field " not set correctly in '_load_config_used'";3000 3001#define CHECK_ABSOLUTE(field, sym)                                             \3002  if (auto *s = dyn_cast<DefinedAbsolute>(symtab.findUnderscore(sym)))         \3003    if (loadConfig->field != s->getVA())                                       \3004      Warn(ctx) << #field " not set correctly in '_load_config_used'";3005 3006  if (ctx.config.dependentLoadFlags) {3007    RETURN_IF_NOT_CONTAINS(DependentLoadFlags)3008    loadConfig->DependentLoadFlags = ctx.config.dependentLoadFlags;3009  }3010 3011  if (ctx.dynamicRelocs) {3012    IF_CONTAINS(DynamicValueRelocTableSection) {3013      loadConfig->DynamicValueRelocTableSection = relocSec->sectionIndex;3014      loadConfig->DynamicValueRelocTableOffset =3015          ctx.dynamicRelocs->getRVA() - relocSec->getRVA();3016    }3017    else {3018      Warn(ctx) << "'_load_config_used' structure too small to include dynamic "3019                   "relocations";3020    }3021  }3022 3023  IF_CONTAINS(CHPEMetadataPointer) {3024    // On ARM64X, only the EC version of the load config contains3025    // CHPEMetadataPointer. Copy its value to the native load config.3026    if (ctx.config.machine == ARM64X && !symtab.isEC() &&3027        ctx.symtab.loadConfigSize >=3028            offsetof(T, CHPEMetadataPointer) + sizeof(T::CHPEMetadataPointer)) {3029      OutputSection *sec =3030          ctx.getOutputSection(ctx.symtab.loadConfigSym->getChunk());3031      uint8_t *secBuf = buffer->getBufferStart() + sec->getFileOff();3032      auto hybridLoadConfig =3033          reinterpret_cast<const coff_load_configuration64 *>(3034              secBuf + (ctx.symtab.loadConfigSym->getRVA() - sec->getRVA()));3035      loadConfig->CHPEMetadataPointer = hybridLoadConfig->CHPEMetadataPointer;3036    }3037  }3038 3039  if (ctx.config.guardCF == GuardCFLevel::Off)3040    return;3041  RETURN_IF_NOT_CONTAINS(GuardFlags)3042  CHECK_VA(GuardCFFunctionTable, "__guard_fids_table")3043  CHECK_ABSOLUTE(GuardCFFunctionCount, "__guard_fids_count")3044  CHECK_ABSOLUTE(GuardFlags, "__guard_flags")3045  IF_CONTAINS(GuardAddressTakenIatEntryCount) {3046    CHECK_VA(GuardAddressTakenIatEntryTable, "__guard_iat_table")3047    CHECK_ABSOLUTE(GuardAddressTakenIatEntryCount, "__guard_iat_count")3048  }3049 3050  if (!(ctx.config.guardCF & GuardCFLevel::LongJmp))3051    return;3052  RETURN_IF_NOT_CONTAINS(GuardLongJumpTargetCount)3053  CHECK_VA(GuardLongJumpTargetTable, "__guard_longjmp_table")3054  CHECK_ABSOLUTE(GuardLongJumpTargetCount, "__guard_longjmp_count")3055 3056  if (!(ctx.config.guardCF & GuardCFLevel::EHCont))3057    return;3058  RETURN_IF_NOT_CONTAINS(GuardEHContinuationCount)3059  CHECK_VA(GuardEHContinuationTable, "__guard_eh_cont_table")3060  CHECK_ABSOLUTE(GuardEHContinuationCount, "__guard_eh_cont_count")3061 3062#undef RETURN_IF_NOT_CONTAINS3063#undef IF_CONTAINS3064#undef CHECK_VA3065#undef CHECK_ABSOLUTE3066}3067 3068void Writer::printSummary() {3069  if (!ctx.config.showSummary)3070    return;3071 3072  SmallString<256> buffer;3073  raw_svector_ostream stream(buffer);3074 3075  stream << center_justify("Summary", 80) << '\n'3076         << std::string(80, '-') << '\n';3077 3078  auto print = [&](uint64_t v, StringRef s) {3079    stream << formatv("{0}",3080                      fmt_align(formatv("{0:N}", v), AlignStyle::Right, 20))3081           << " " << s << '\n';3082  };3083 3084  bool hasStats = ctx.pdbStats.has_value();3085 3086  print(ctx.objFileInstances.size(),3087        "Input OBJ files (expanded from all cmd-line inputs)");3088  print(ctx.consumedInputsSize,3089        "Size of all consumed OBJ files (non-lazy), in bytes");3090  print(ctx.typeServerSourceMappings.size(), "PDB type server dependencies");3091  print(ctx.precompSourceMappings.size(), "Precomp OBJ dependencies");3092  print(hasStats ? ctx.pdbStats->nbTypeRecords : 0, "Input debug type records");3093  print(hasStats ? ctx.pdbStats->nbTypeRecordsBytes : 0,3094        "Size of all input debug type records, in bytes");3095  print(hasStats ? ctx.pdbStats->nbTPIrecords : 0, "Merged TPI records");3096  print(hasStats ? ctx.pdbStats->nbIPIrecords : 0, "Merged IPI records");3097  print(hasStats ? ctx.pdbStats->strTabSize : 0, "Output PDB strings");3098  print(hasStats ? ctx.pdbStats->globalSymbols : 0, "Global symbol records");3099  print(hasStats ? ctx.pdbStats->moduleSymbols : 0, "Module symbol records");3100  print(hasStats ? ctx.pdbStats->publicSymbols : 0, "Public symbol records");3101 3102  if (hasStats)3103    stream << ctx.pdbStats->largeInputTypeRecs;3104 3105  Msg(ctx) << buffer;3106}3107