diff options
Diffstat (limited to 'lld/COFF/Writer.cpp')
-rw-r--r-- | lld/COFF/Writer.cpp | 1916 |
1 files changed, 958 insertions, 958 deletions
diff --git a/lld/COFF/Writer.cpp b/lld/COFF/Writer.cpp index 64ed0a15f85..46b1af0934a 100644 --- a/lld/COFF/Writer.cpp +++ b/lld/COFF/Writer.cpp @@ -63,105 +63,105 @@ align 8, db 0 $ nasm -fbin /tmp/DOSProgram.asm -o /tmp/DOSProgram.bin $ xxd -i /tmp/DOSProgram.bin */ -static unsigned char DOSProgram[] = { +static unsigned char dosProgram[] = { 0x0e, 0x1f, 0xba, 0x0e, 0x00, 0xb4, 0x09, 0xcd, 0x21, 0xb8, 0x01, 0x4c, 0xcd, 0x21, 0x54, 0x68, 0x69, 0x73, 0x20, 0x70, 0x72, 0x6f, 0x67, 0x72, 0x61, 0x6d, 0x20, 0x63, 0x61, 0x6e, 0x6e, 0x6f, 0x74, 0x20, 0x62, 0x65, 0x20, 0x72, 0x75, 0x6e, 0x20, 0x69, 0x6e, 0x20, 0x44, 0x4f, 0x53, 0x20, 0x6d, 0x6f, 0x64, 0x65, 0x2e, 0x24, 0x00, 0x00 }; -static_assert(sizeof(DOSProgram) % 8 == 0, +static_assert(sizeof(dosProgram) % 8 == 0, "DOSProgram size must be multiple of 8"); -static const int DOSStubSize = sizeof(dos_header) + sizeof(DOSProgram); -static_assert(DOSStubSize % 8 == 0, "DOSStub size must be multiple of 8"); +static const int dosStubSize = sizeof(dos_header) + sizeof(dosProgram); +static_assert(dosStubSize % 8 == 0, "DOSStub size must be multiple of 8"); -static const int NumberOfDataDirectory = 16; +static const int numberOfDataDirectory = 16; // Global vector of all output sections. After output sections are finalized, // this can be indexed by Chunk::getOutputSection. -static std::vector<OutputSection *> OutputSections; +static std::vector<OutputSection *> outputSections; OutputSection *Chunk::getOutputSection() const { - return OSIdx == 0 ? nullptr : OutputSections[OSIdx - 1]; + return osidx == 0 ? nullptr : outputSections[osidx - 1]; } namespace { class DebugDirectoryChunk : public NonSectionChunk { public: - DebugDirectoryChunk(const std::vector<Chunk *> &R, bool WriteRepro) - : Records(R), WriteRepro(WriteRepro) {} + DebugDirectoryChunk(const std::vector<Chunk *> &r, bool writeRepro) + : records(r), writeRepro(writeRepro) {} size_t getSize() const override { - return (Records.size() + int(WriteRepro)) * sizeof(debug_directory); + return (records.size() + int(writeRepro)) * sizeof(debug_directory); } - void writeTo(uint8_t *B) const override { - auto *D = reinterpret_cast<debug_directory *>(B); + void writeTo(uint8_t *b) const override { + auto *d = reinterpret_cast<debug_directory *>(b); - for (const Chunk *Record : Records) { - OutputSection *OS = Record->getOutputSection(); - uint64_t Offs = OS->getFileOff() + (Record->getRVA() - OS->getRVA()); - fillEntry(D, COFF::IMAGE_DEBUG_TYPE_CODEVIEW, Record->getSize(), - Record->getRVA(), Offs); - ++D; + for (const Chunk *record : records) { + OutputSection *os = record->getOutputSection(); + uint64_t offs = os->getFileOff() + (record->getRVA() - os->getRVA()); + fillEntry(d, COFF::IMAGE_DEBUG_TYPE_CODEVIEW, record->getSize(), + record->getRVA(), offs); + ++d; } - if (WriteRepro) { + if (writeRepro) { // FIXME: The COFF spec allows either a 0-sized entry to just say // "the timestamp field is really a hash", or a 4-byte size field // followed by that many bytes containing a longer hash (with the // lowest 4 bytes usually being the timestamp in little-endian order). // Consider storing the full 8 bytes computed by xxHash64 here. - fillEntry(D, COFF::IMAGE_DEBUG_TYPE_REPRO, 0, 0, 0); + fillEntry(d, COFF::IMAGE_DEBUG_TYPE_REPRO, 0, 0, 0); } } - void setTimeDateStamp(uint32_t TimeDateStamp) { - for (support::ulittle32_t *TDS : TimeDateStamps) - *TDS = TimeDateStamp; + void setTimeDateStamp(uint32_t timeDateStamp) { + for (support::ulittle32_t *tds : timeDateStamps) + *tds = timeDateStamp; } private: - void fillEntry(debug_directory *D, COFF::DebugType DebugType, size_t Size, - uint64_t RVA, uint64_t Offs) const { - D->Characteristics = 0; - D->TimeDateStamp = 0; - D->MajorVersion = 0; - D->MinorVersion = 0; - D->Type = DebugType; - D->SizeOfData = Size; - D->AddressOfRawData = RVA; - D->PointerToRawData = Offs; - - TimeDateStamps.push_back(&D->TimeDateStamp); - } - - mutable std::vector<support::ulittle32_t *> TimeDateStamps; - const std::vector<Chunk *> &Records; - bool WriteRepro; + void fillEntry(debug_directory *d, COFF::DebugType debugType, size_t size, + uint64_t rva, uint64_t offs) const { + d->Characteristics = 0; + d->TimeDateStamp = 0; + d->MajorVersion = 0; + d->MinorVersion = 0; + d->Type = debugType; + d->SizeOfData = size; + d->AddressOfRawData = rva; + d->PointerToRawData = offs; + + timeDateStamps.push_back(&d->TimeDateStamp); + } + + mutable std::vector<support::ulittle32_t *> timeDateStamps; + const std::vector<Chunk *> &records; + bool writeRepro; }; class CVDebugRecordChunk : public NonSectionChunk { public: size_t getSize() const override { - return sizeof(codeview::DebugInfo) + Config->PDBAltPath.size() + 1; + return sizeof(codeview::DebugInfo) + config->pdbAltPath.size() + 1; } - void writeTo(uint8_t *B) const override { + void writeTo(uint8_t *b) const override { // Save off the DebugInfo entry to backfill the file signature (build id) // in Writer::writeBuildId - BuildId = reinterpret_cast<codeview::DebugInfo *>(B); + buildId = reinterpret_cast<codeview::DebugInfo *>(b); // variable sized field (PDB Path) - char *P = reinterpret_cast<char *>(B + sizeof(*BuildId)); - if (!Config->PDBAltPath.empty()) - memcpy(P, Config->PDBAltPath.data(), Config->PDBAltPath.size()); - P[Config->PDBAltPath.size()] = '\0'; + char *p = reinterpret_cast<char *>(b + sizeof(*buildId)); + if (!config->pdbAltPath.empty()) + memcpy(p, config->pdbAltPath.data(), config->pdbAltPath.size()); + p[config->pdbAltPath.size()] = '\0'; } - mutable codeview::DebugInfo *BuildId = nullptr; + mutable codeview::DebugInfo *buildId = nullptr; }; // PartialSection represents a group of chunks that contribute to an @@ -169,15 +169,15 @@ public: // characteristics constitutes the OutputSection. class PartialSectionKey { public: - StringRef Name; - unsigned Characteristics; + StringRef name; + unsigned characteristics; - bool operator<(const PartialSectionKey &Other) const { - int C = Name.compare(Other.Name); - if (C == 1) + bool operator<(const PartialSectionKey &other) const { + int c = name.compare(other.name); + if (c == 1) return false; - if (C == 0) - return Characteristics < Other.Characteristics; + if (c == 0) + return characteristics < other.characteristics; return true; } }; @@ -185,7 +185,7 @@ public: // The writer writes a SymbolTable result to a file. class Writer { public: - Writer() : Buffer(errorHandler().OutputBuffer) {} + Writer() : buffer(errorHandler().outputBuffer) {} void run(); private: @@ -202,72 +202,72 @@ private: void removeEmptySections(); void assignOutputSectionIndices(); void createSymbolAndStringTable(); - void openFile(StringRef OutputPath); + void openFile(StringRef outputPath); template <typename PEHeaderTy> void writeHeader(); void createSEHTable(); void createRuntimePseudoRelocs(); void insertCtorDtorSymbols(); void createGuardCFTables(); - void markSymbolsForRVATable(ObjFile *File, - ArrayRef<SectionChunk *> SymIdxChunks, - SymbolRVASet &TableSymbols); - void maybeAddRVATable(SymbolRVASet TableSymbols, StringRef TableSym, - StringRef CountSym); + void markSymbolsForRVATable(ObjFile *file, + ArrayRef<SectionChunk *> symIdxChunks, + SymbolRVASet &tableSymbols); + void maybeAddRVATable(SymbolRVASet tableSymbols, StringRef tableSym, + StringRef countSym); void setSectionPermissions(); void writeSections(); void writeBuildId(); void sortExceptionTable(); - void sortCRTSectionChunks(std::vector<Chunk *> &Chunks); + void sortCRTSectionChunks(std::vector<Chunk *> &chunks); void addSyntheticIdata(); - void fixPartialSectionChars(StringRef Name, uint32_t Chars); + void fixPartialSectionChars(StringRef name, uint32_t chars); bool fixGnuImportChunks(); - PartialSection *createPartialSection(StringRef Name, uint32_t OutChars); - PartialSection *findPartialSection(StringRef Name, uint32_t OutChars); + PartialSection *createPartialSection(StringRef name, uint32_t outChars); + PartialSection *findPartialSection(StringRef name, uint32_t outChars); - llvm::Optional<coff_symbol16> createSymbol(Defined *D); - size_t addEntryToStringTable(StringRef Str); + llvm::Optional<coff_symbol16> createSymbol(Defined *d); + size_t addEntryToStringTable(StringRef str); - OutputSection *findSection(StringRef Name); + OutputSection *findSection(StringRef name); void addBaserels(); - void addBaserelBlocks(std::vector<Baserel> &V); + void addBaserelBlocks(std::vector<Baserel> &v); uint32_t getSizeOfInitializedData(); - std::unique_ptr<FileOutputBuffer> &Buffer; - std::map<PartialSectionKey, PartialSection *> PartialSections; - std::vector<char> Strtab; - std::vector<llvm::object::coff_symbol16> OutputSymtab; - IdataContents Idata; - Chunk *ImportTableStart = nullptr; - uint64_t ImportTableSize = 0; - Chunk *IATStart = nullptr; - uint64_t IATSize = 0; - DelayLoadContents DelayIdata; - EdataContents Edata; - bool SetNoSEHCharacteristic = false; - - DebugDirectoryChunk *DebugDirectory = nullptr; - std::vector<Chunk *> DebugRecords; - CVDebugRecordChunk *BuildId = nullptr; - ArrayRef<uint8_t> SectionTable; - - uint64_t FileSize; - uint32_t PointerToSymbolTable = 0; - uint64_t SizeOfImage; - uint64_t SizeOfHeaders; - - OutputSection *TextSec; - OutputSection *RdataSec; - OutputSection *BuildidSec; - OutputSection *DataSec; - OutputSection *PdataSec; - OutputSection *IdataSec; - OutputSection *EdataSec; - OutputSection *DidatSec; - OutputSection *RsrcSec; - OutputSection *RelocSec; - OutputSection *CtorsSec; - OutputSection *DtorsSec; + std::unique_ptr<FileOutputBuffer> &buffer; + std::map<PartialSectionKey, PartialSection *> partialSections; + std::vector<char> strtab; + std::vector<llvm::object::coff_symbol16> outputSymtab; + IdataContents idata; + Chunk *importTableStart = nullptr; + uint64_t importTableSize = 0; + Chunk *iatStart = nullptr; + uint64_t iatSize = 0; + DelayLoadContents delayIdata; + EdataContents edata; + bool setNoSEHCharacteristic = false; + + DebugDirectoryChunk *debugDirectory = nullptr; + std::vector<Chunk *> debugRecords; + CVDebugRecordChunk *buildId = nullptr; + ArrayRef<uint8_t> sectionTable; + + uint64_t fileSize; + uint32_t pointerToSymbolTable = 0; + uint64_t sizeOfImage; + uint64_t sizeOfHeaders; + + OutputSection *textSec; + OutputSection *rdataSec; + OutputSection *buildidSec; + OutputSection *dataSec; + OutputSection *pdataSec; + OutputSection *idataSec; + OutputSection *edataSec; + OutputSection *didatSec; + OutputSection *rsrcSec; + OutputSection *relocSec; + OutputSection *ctorsSec; + OutputSection *dtorsSec; // The first and last .pdata sections in the output file. // @@ -278,57 +278,57 @@ private: // are entirely linker-generated we can keep track of their locations using // the chunks that the linker creates. All .pdata chunks come from input // files, so we need to keep track of them separately. - Chunk *FirstPdata = nullptr; - Chunk *LastPdata; + Chunk *firstPdata = nullptr; + Chunk *lastPdata; }; } // anonymous namespace namespace lld { namespace coff { -static Timer CodeLayoutTimer("Code Layout", Timer::root()); -static Timer DiskCommitTimer("Commit Output File", Timer::root()); +static Timer codeLayoutTimer("Code Layout", Timer::root()); +static Timer diskCommitTimer("Commit Output File", Timer::root()); void writeResult() { Writer().run(); } -void OutputSection::addChunk(Chunk *C) { - Chunks.push_back(C); +void OutputSection::addChunk(Chunk *c) { + chunks.push_back(c); } -void OutputSection::insertChunkAtStart(Chunk *C) { - Chunks.insert(Chunks.begin(), C); +void OutputSection::insertChunkAtStart(Chunk *c) { + chunks.insert(chunks.begin(), c); } -void OutputSection::setPermissions(uint32_t C) { - Header.Characteristics &= ~PermMask; - Header.Characteristics |= C; +void OutputSection::setPermissions(uint32_t c) { + header.Characteristics &= ~permMask; + header.Characteristics |= c; } -void OutputSection::merge(OutputSection *Other) { - Chunks.insert(Chunks.end(), Other->Chunks.begin(), Other->Chunks.end()); - Other->Chunks.clear(); - ContribSections.insert(ContribSections.end(), Other->ContribSections.begin(), - Other->ContribSections.end()); - Other->ContribSections.clear(); +void OutputSection::merge(OutputSection *other) { + chunks.insert(chunks.end(), other->chunks.begin(), other->chunks.end()); + other->chunks.clear(); + contribSections.insert(contribSections.end(), other->contribSections.begin(), + other->contribSections.end()); + other->contribSections.clear(); } // Write the section header to a given buffer. -void OutputSection::writeHeaderTo(uint8_t *Buf) { - auto *Hdr = reinterpret_cast<coff_section *>(Buf); - *Hdr = Header; - if (StringTableOff) { +void OutputSection::writeHeaderTo(uint8_t *buf) { + auto *hdr = reinterpret_cast<coff_section *>(buf); + *hdr = header; + if (stringTableOff) { // If name is too long, write offset into the string table as a name. - sprintf(Hdr->Name, "/%d", StringTableOff); + sprintf(hdr->Name, "/%d", stringTableOff); } else { - assert(!Config->Debug || Name.size() <= COFF::NameSize || - (Hdr->Characteristics & IMAGE_SCN_MEM_DISCARDABLE) == 0); - strncpy(Hdr->Name, Name.data(), - std::min(Name.size(), (size_t)COFF::NameSize)); + assert(!config->debug || name.size() <= COFF::NameSize || + (hdr->Characteristics & IMAGE_SCN_MEM_DISCARDABLE) == 0); + strncpy(hdr->Name, name.data(), + std::min(name.size(), (size_t)COFF::NameSize)); } } -void OutputSection::addContributingPartialSection(PartialSection *Sec) { - ContribSections.push_back(Sec); +void OutputSection::addContributingPartialSection(PartialSection *sec) { + contribSections.push_back(sec); } } // namespace coff @@ -336,27 +336,27 @@ void OutputSection::addContributingPartialSection(PartialSection *Sec) { // Check whether the target address S is in range from a relocation // of type RelType at address P. -static bool isInRange(uint16_t RelType, uint64_t S, uint64_t P, int Margin) { - if (Config->Machine == ARMNT) { - int64_t Diff = AbsoluteDifference(S, P + 4) + Margin; - switch (RelType) { +static bool isInRange(uint16_t relType, uint64_t s, uint64_t p, int margin) { + if (config->machine == ARMNT) { + int64_t diff = AbsoluteDifference(s, p + 4) + margin; + switch (relType) { case IMAGE_REL_ARM_BRANCH20T: - return isInt<21>(Diff); + return isInt<21>(diff); case IMAGE_REL_ARM_BRANCH24T: case IMAGE_REL_ARM_BLX23T: - return isInt<25>(Diff); + return isInt<25>(diff); default: return true; } - } else if (Config->Machine == ARM64) { - int64_t Diff = AbsoluteDifference(S, P) + Margin; - switch (RelType) { + } else if (config->machine == ARM64) { + int64_t diff = AbsoluteDifference(s, p) + margin; + switch (relType) { case IMAGE_REL_ARM64_BRANCH26: - return isInt<28>(Diff); + return isInt<28>(diff); case IMAGE_REL_ARM64_BRANCH19: - return isInt<21>(Diff); + return isInt<21>(diff); case IMAGE_REL_ARM64_BRANCH14: - return isInt<16>(Diff); + return isInt<16>(diff); default: return true; } @@ -368,25 +368,25 @@ static bool isInRange(uint16_t RelType, uint64_t S, uint64_t P, int Margin) { // Return the last thunk for the given target if it is in range, // or create a new one. static std::pair<Defined *, bool> -getThunk(DenseMap<uint64_t, Defined *> &LastThunks, Defined *Target, uint64_t P, - uint16_t Type, int Margin) { - Defined *&LastThunk = LastThunks[Target->getRVA()]; - if (LastThunk && isInRange(Type, LastThunk->getRVA(), P, Margin)) - return {LastThunk, false}; - Chunk *C; - switch (Config->Machine) { +getThunk(DenseMap<uint64_t, Defined *> &lastThunks, Defined *target, uint64_t p, + uint16_t type, int margin) { + Defined *&lastThunk = lastThunks[target->getRVA()]; + if (lastThunk && isInRange(type, lastThunk->getRVA(), p, margin)) + return {lastThunk, false}; + Chunk *c; + switch (config->machine) { case ARMNT: - C = make<RangeExtensionThunkARM>(Target); + c = make<RangeExtensionThunkARM>(target); break; case ARM64: - C = make<RangeExtensionThunkARM64>(Target); + c = make<RangeExtensionThunkARM64>(target); break; default: llvm_unreachable("Unexpected architecture"); } - Defined *D = make<DefinedSynthetic>("", C); - LastThunk = D; - return {D, true}; + Defined *d = make<DefinedSynthetic>("", c); + lastThunk = d; + return {d, true}; } // This checks all relocations, and for any relocation which isn't in range @@ -400,124 +400,124 @@ getThunk(DenseMap<uint64_t, Defined *> &LastThunks, Defined *Target, uint64_t P, // After adding thunks, we verify that all relocations are in range (with // no extra margin requirements). If this failed, we restart (throwing away // the previously created thunks) and retry with a wider margin. -static bool createThunks(OutputSection *OS, int Margin) { - bool AddressesChanged = false; - DenseMap<uint64_t, Defined *> LastThunks; - DenseMap<std::pair<ObjFile *, Defined *>, uint32_t> ThunkSymtabIndices; - size_t ThunksSize = 0; +static bool createThunks(OutputSection *os, int margin) { + bool addressesChanged = false; + DenseMap<uint64_t, Defined *> lastThunks; + DenseMap<std::pair<ObjFile *, Defined *>, uint32_t> thunkSymtabIndices; + size_t thunksSize = 0; // Recheck Chunks.size() each iteration, since we can insert more // elements into it. - for (size_t I = 0; I != OS->Chunks.size(); ++I) { - SectionChunk *SC = dyn_cast_or_null<SectionChunk>(OS->Chunks[I]); - if (!SC) + for (size_t i = 0; i != os->chunks.size(); ++i) { + SectionChunk *sc = dyn_cast_or_null<SectionChunk>(os->chunks[i]); + if (!sc) continue; - size_t ThunkInsertionSpot = I + 1; + size_t thunkInsertionSpot = i + 1; // Try to get a good enough estimate of where new thunks will be placed. // Offset this by the size of the new thunks added so far, to make the // estimate slightly better. - size_t ThunkInsertionRVA = SC->getRVA() + SC->getSize() + ThunksSize; - ObjFile *File = SC->File; - std::vector<std::pair<uint32_t, uint32_t>> RelocReplacements; - ArrayRef<coff_relocation> OriginalRelocs = - File->getCOFFObj()->getRelocations(SC->Header); - for (size_t J = 0, E = OriginalRelocs.size(); J < E; ++J) { - const coff_relocation &Rel = OriginalRelocs[J]; - Symbol *RelocTarget = File->getSymbol(Rel.SymbolTableIndex); + size_t thunkInsertionRVA = sc->getRVA() + sc->getSize() + thunksSize; + ObjFile *file = sc->file; + std::vector<std::pair<uint32_t, uint32_t>> relocReplacements; + ArrayRef<coff_relocation> originalRelocs = + file->getCOFFObj()->getRelocations(sc->header); + for (size_t j = 0, e = originalRelocs.size(); j < e; ++j) { + const coff_relocation &rel = originalRelocs[j]; + Symbol *relocTarget = file->getSymbol(rel.SymbolTableIndex); // The estimate of the source address P should be pretty accurate, // but we don't know whether the target Symbol address should be // offset by ThunkSize or not (or by some of ThunksSize but not all of // it), giving us some uncertainty once we have added one thunk. - uint64_t P = SC->getRVA() + Rel.VirtualAddress + ThunksSize; + uint64_t p = sc->getRVA() + rel.VirtualAddress + thunksSize; - Defined *Sym = dyn_cast_or_null<Defined>(RelocTarget); - if (!Sym) + Defined *sym = dyn_cast_or_null<Defined>(relocTarget); + if (!sym) continue; - uint64_t S = Sym->getRVA(); + uint64_t s = sym->getRVA(); - if (isInRange(Rel.Type, S, P, Margin)) + if (isInRange(rel.Type, s, p, margin)) continue; // If the target isn't in range, hook it up to an existing or new // thunk. - Defined *Thunk; - bool WasNew; - std::tie(Thunk, WasNew) = getThunk(LastThunks, Sym, P, Rel.Type, Margin); - if (WasNew) { - Chunk *ThunkChunk = Thunk->getChunk(); - ThunkChunk->setRVA( - ThunkInsertionRVA); // Estimate of where it will be located. - OS->Chunks.insert(OS->Chunks.begin() + ThunkInsertionSpot, ThunkChunk); - ThunkInsertionSpot++; - ThunksSize += ThunkChunk->getSize(); - ThunkInsertionRVA += ThunkChunk->getSize(); - AddressesChanged = true; + Defined *thunk; + bool wasNew; + std::tie(thunk, wasNew) = getThunk(lastThunks, sym, p, rel.Type, margin); + if (wasNew) { + Chunk *thunkChunk = thunk->getChunk(); + thunkChunk->setRVA( + thunkInsertionRVA); // Estimate of where it will be located. + os->chunks.insert(os->chunks.begin() + thunkInsertionSpot, thunkChunk); + thunkInsertionSpot++; + thunksSize += thunkChunk->getSize(); + thunkInsertionRVA += thunkChunk->getSize(); + addressesChanged = true; } // To redirect the relocation, add a symbol to the parent object file's // symbol table, and replace the relocation symbol table index with the // new index. - auto Insertion = ThunkSymtabIndices.insert({{File, Thunk}, ~0U}); - uint32_t &ThunkSymbolIndex = Insertion.first->second; - if (Insertion.second) - ThunkSymbolIndex = File->addRangeThunkSymbol(Thunk); - RelocReplacements.push_back({J, ThunkSymbolIndex}); + auto insertion = thunkSymtabIndices.insert({{file, thunk}, ~0U}); + uint32_t &thunkSymbolIndex = insertion.first->second; + if (insertion.second) + thunkSymbolIndex = file->addRangeThunkSymbol(thunk); + relocReplacements.push_back({j, thunkSymbolIndex}); } // Get a writable copy of this section's relocations so they can be // modified. If the relocations point into the object file, allocate new // memory. Otherwise, this must be previously allocated memory that can be // modified in place. - ArrayRef<coff_relocation> CurRelocs = SC->getRelocs(); - MutableArrayRef<coff_relocation> NewRelocs; - if (OriginalRelocs.data() == CurRelocs.data()) { - NewRelocs = makeMutableArrayRef( - BAlloc.Allocate<coff_relocation>(OriginalRelocs.size()), - OriginalRelocs.size()); + ArrayRef<coff_relocation> curRelocs = sc->getRelocs(); + MutableArrayRef<coff_relocation> newRelocs; + if (originalRelocs.data() == curRelocs.data()) { + newRelocs = makeMutableArrayRef( + bAlloc.Allocate<coff_relocation>(originalRelocs.size()), + originalRelocs.size()); } else { - NewRelocs = makeMutableArrayRef( - const_cast<coff_relocation *>(CurRelocs.data()), CurRelocs.size()); + newRelocs = makeMutableArrayRef( + const_cast<coff_relocation *>(curRelocs.data()), curRelocs.size()); } // Copy each relocation, but replace the symbol table indices which need // thunks. - auto NextReplacement = RelocReplacements.begin(); - auto EndReplacement = RelocReplacements.end(); - for (size_t I = 0, E = OriginalRelocs.size(); I != E; ++I) { - NewRelocs[I] = OriginalRelocs[I]; - if (NextReplacement != EndReplacement && NextReplacement->first == I) { - NewRelocs[I].SymbolTableIndex = NextReplacement->second; - ++NextReplacement; + auto nextReplacement = relocReplacements.begin(); + auto endReplacement = relocReplacements.end(); + for (size_t i = 0, e = originalRelocs.size(); i != e; ++i) { + newRelocs[i] = originalRelocs[i]; + if (nextReplacement != endReplacement && nextReplacement->first == i) { + newRelocs[i].SymbolTableIndex = nextReplacement->second; + ++nextReplacement; } } - SC->setRelocs(NewRelocs); + sc->setRelocs(newRelocs); } - return AddressesChanged; + return addressesChanged; } // Verify that all relocations are in range, with no extra margin requirements. -static bool verifyRanges(const std::vector<Chunk *> Chunks) { - for (Chunk *C : Chunks) { - SectionChunk *SC = dyn_cast_or_null<SectionChunk>(C); - if (!SC) +static bool verifyRanges(const std::vector<Chunk *> chunks) { + for (Chunk *c : chunks) { + SectionChunk *sc = dyn_cast_or_null<SectionChunk>(c); + if (!sc) continue; - ArrayRef<coff_relocation> Relocs = SC->getRelocs(); - for (size_t J = 0, E = Relocs.size(); J < E; ++J) { - const coff_relocation &Rel = Relocs[J]; - Symbol *RelocTarget = SC->File->getSymbol(Rel.SymbolTableIndex); + ArrayRef<coff_relocation> relocs = sc->getRelocs(); + for (size_t j = 0, e = relocs.size(); j < e; ++j) { + const coff_relocation &rel = relocs[j]; + Symbol *relocTarget = sc->file->getSymbol(rel.SymbolTableIndex); - Defined *Sym = dyn_cast_or_null<Defined>(RelocTarget); - if (!Sym) + Defined *sym = dyn_cast_or_null<Defined>(relocTarget); + if (!sym) continue; - uint64_t P = SC->getRVA() + Rel.VirtualAddress; - uint64_t S = Sym->getRVA(); + uint64_t p = sc->getRVA() + rel.VirtualAddress; + uint64_t s = sym->getRVA(); - if (!isInRange(Rel.Type, S, P, 0)) + if (!isInRange(rel.Type, s, p, 0)) return false; } } @@ -527,68 +527,68 @@ static bool verifyRanges(const std::vector<Chunk *> Chunks) { // Assign addresses and add thunks if necessary. void Writer::finalizeAddresses() { assignAddresses(); - if (Config->Machine != ARMNT && Config->Machine != ARM64) + if (config->machine != ARMNT && config->machine != ARM64) return; - size_t OrigNumChunks = 0; - for (OutputSection *Sec : OutputSections) { - Sec->OrigChunks = Sec->Chunks; - OrigNumChunks += Sec->Chunks.size(); + size_t origNumChunks = 0; + for (OutputSection *sec : outputSections) { + sec->origChunks = sec->chunks; + origNumChunks += sec->chunks.size(); } - int Pass = 0; - int Margin = 1024 * 100; + int pass = 0; + int margin = 1024 * 100; while (true) { // First check whether we need thunks at all, or if the previous pass of // adding them turned out ok. - bool RangesOk = true; - size_t NumChunks = 0; - for (OutputSection *Sec : OutputSections) { - if (!verifyRanges(Sec->Chunks)) { - RangesOk = false; + bool rangesOk = true; + size_t numChunks = 0; + for (OutputSection *sec : outputSections) { + if (!verifyRanges(sec->chunks)) { + rangesOk = false; break; } - NumChunks += Sec->Chunks.size(); + numChunks += sec->chunks.size(); } - if (RangesOk) { - if (Pass > 0) - log("Added " + Twine(NumChunks - OrigNumChunks) + " thunks with " + - "margin " + Twine(Margin) + " in " + Twine(Pass) + " passes"); + if (rangesOk) { + if (pass > 0) + log("Added " + Twine(numChunks - origNumChunks) + " thunks with " + + "margin " + Twine(margin) + " in " + Twine(pass) + " passes"); return; } - if (Pass >= 10) - fatal("adding thunks hasn't converged after " + Twine(Pass) + " passes"); + if (pass >= 10) + fatal("adding thunks hasn't converged after " + Twine(pass) + " passes"); - if (Pass > 0) { + if (pass > 0) { // If the previous pass didn't work out, reset everything back to the // original conditions before retrying with a wider margin. This should // ideally never happen under real circumstances. - for (OutputSection *Sec : OutputSections) - Sec->Chunks = Sec->OrigChunks; - Margin *= 2; + for (OutputSection *sec : outputSections) + sec->chunks = sec->origChunks; + margin *= 2; } // Try adding thunks everywhere where it is needed, with a margin // to avoid things going out of range due to the added thunks. - bool AddressesChanged = false; - for (OutputSection *Sec : OutputSections) - AddressesChanged |= createThunks(Sec, Margin); + bool addressesChanged = false; + for (OutputSection *sec : outputSections) + addressesChanged |= createThunks(sec, margin); // If the verification above thought we needed thunks, we should have // added some. - assert(AddressesChanged); + assert(addressesChanged); // Recalculate the layout for the whole image (and verify the ranges at // the start of the next round). assignAddresses(); - Pass++; + pass++; } } // The main function of the writer. void Writer::run() { - ScopedTimer T1(CodeLayoutTimer); + ScopedTimer t1(codeLayoutTimer); createImportTables(); createSections(); @@ -603,12 +603,12 @@ void Writer::run() { setSectionPermissions(); createSymbolAndStringTable(); - if (FileSize > UINT32_MAX) - fatal("image size (" + Twine(FileSize) + ") " + + if (fileSize > UINT32_MAX) + fatal("image size (" + Twine(fileSize) + ") " + "exceeds maximum allowable size (" + Twine(UINT32_MAX) + ")"); - openFile(Config->OutputFile); - if (Config->is64()) { + openFile(config->outputFile); + if (config->is64()) { writeHeader<pe32plus_header>(); } else { writeHeader<pe32_header>(); @@ -616,58 +616,58 @@ void Writer::run() { writeSections(); sortExceptionTable(); - T1.stop(); + t1.stop(); - if (!Config->PDBPath.empty() && Config->Debug) { - assert(BuildId); - createPDB(Symtab, OutputSections, SectionTable, BuildId->BuildId); + if (!config->pdbPath.empty() && config->debug) { + assert(buildId); + createPDB(symtab, outputSections, sectionTable, buildId->buildId); } writeBuildId(); - writeMapFile(OutputSections); + writeMapFile(outputSections); - ScopedTimer T2(DiskCommitTimer); - if (auto E = Buffer->commit()) - fatal("failed to write the output file: " + toString(std::move(E))); + ScopedTimer t2(diskCommitTimer); + if (auto e = buffer->commit()) + fatal("failed to write the output file: " + toString(std::move(e))); } -static StringRef getOutputSectionName(StringRef Name) { - StringRef S = Name.split('$').first; +static StringRef getOutputSectionName(StringRef name) { + StringRef s = name.split('$').first; // Treat a later period as a separator for MinGW, for sections like // ".ctors.01234". - return S.substr(0, S.find('.', 1)); + return s.substr(0, s.find('.', 1)); } // For /order. -static void sortBySectionOrder(std::vector<Chunk *> &Chunks) { - auto GetPriority = [](const Chunk *C) { - if (auto *Sec = dyn_cast<SectionChunk>(C)) - if (Sec->Sym) - return Config->Order.lookup(Sec->Sym->getName()); +static void sortBySectionOrder(std::vector<Chunk *> &chunks) { + auto getPriority = [](const Chunk *c) { + if (auto *sec = dyn_cast<SectionChunk>(c)) + if (sec->sym) + return config->order.lookup(sec->sym->getName()); return 0; }; - llvm::stable_sort(Chunks, [=](const Chunk *A, const Chunk *B) { - return GetPriority(A) < GetPriority(B); + llvm::stable_sort(chunks, [=](const Chunk *a, const Chunk *b) { + return getPriority(a) < getPriority(b); }); } // Change the characteristics of existing PartialSections that belong to the // section Name to Chars. -void Writer::fixPartialSectionChars(StringRef Name, uint32_t Chars) { - for (auto It : PartialSections) { - PartialSection *PSec = It.second; - StringRef CurName = PSec->Name; - if (!CurName.consume_front(Name) || - (!CurName.empty() && !CurName.startswith("$"))) +void Writer::fixPartialSectionChars(StringRef name, uint32_t chars) { + for (auto it : partialSections) { + PartialSection *pSec = it.second; + StringRef curName = pSec->name; + if (!curName.consume_front(name) || + (!curName.empty() && !curName.startswith("$"))) continue; - if (PSec->Characteristics == Chars) + if (pSec->characteristics == chars) continue; - PartialSection *DestSec = createPartialSection(PSec->Name, Chars); - DestSec->Chunks.insert(DestSec->Chunks.end(), PSec->Chunks.begin(), - PSec->Chunks.end()); - PSec->Chunks.clear(); + PartialSection *destSec = createPartialSection(pSec->name, chars); + destSec->chunks.insert(destSec->chunks.end(), pSec->chunks.begin(), + pSec->chunks.end()); + pSec->chunks.clear(); } } @@ -682,249 +682,249 @@ void Writer::fixPartialSectionChars(StringRef Name, uint32_t Chars) { // to be grouped by library, and sorted alphabetically within each library // (which makes sure the header comes first and the trailer last). bool Writer::fixGnuImportChunks() { - uint32_t RDATA = IMAGE_SCN_CNT_INITIALIZED_DATA | IMAGE_SCN_MEM_READ; + uint32_t rdata = IMAGE_SCN_CNT_INITIALIZED_DATA | IMAGE_SCN_MEM_READ; // Make sure all .idata$* section chunks are mapped as RDATA in order to // be sorted into the same sections as our own synthesized .idata chunks. - fixPartialSectionChars(".idata", RDATA); + fixPartialSectionChars(".idata", rdata); - bool HasIdata = false; + bool hasIdata = false; // Sort all .idata$* chunks, grouping chunks from the same library, // with alphabetical ordering of the object fils within a library. - for (auto It : PartialSections) { - PartialSection *PSec = It.second; - if (!PSec->Name.startswith(".idata")) + for (auto it : partialSections) { + PartialSection *pSec = it.second; + if (!pSec->name.startswith(".idata")) continue; - if (!PSec->Chunks.empty()) - HasIdata = true; - llvm::stable_sort(PSec->Chunks, [&](Chunk *S, Chunk *T) { - SectionChunk *SC1 = dyn_cast_or_null<SectionChunk>(S); - SectionChunk *SC2 = dyn_cast_or_null<SectionChunk>(T); - if (!SC1 || !SC2) { + if (!pSec->chunks.empty()) + hasIdata = true; + llvm::stable_sort(pSec->chunks, [&](Chunk *s, Chunk *t) { + SectionChunk *sc1 = dyn_cast_or_null<SectionChunk>(s); + SectionChunk *sc2 = dyn_cast_or_null<SectionChunk>(t); + if (!sc1 || !sc2) { // if SC1, order them ascending. If SC2 or both null, // S is not less than T. - return SC1 != nullptr; + return sc1 != nullptr; } // Make a string with "libraryname/objectfile" for sorting, achieving // both grouping by library and sorting of objects within a library, // at once. - std::string Key1 = - (SC1->File->ParentName + "/" + SC1->File->getName()).str(); - std::string Key2 = - (SC2->File->ParentName + "/" + SC2->File->getName()).str(); - return Key1 < Key2; + std::string key1 = + (sc1->file->parentName + "/" + sc1->file->getName()).str(); + std::string key2 = + (sc2->file->parentName + "/" + sc2->file->getName()).str(); + return key1 < key2; }); } - return HasIdata; + return hasIdata; } // Add generated idata chunks, for imported symbols and DLLs, and a // terminator in .idata$2. void Writer::addSyntheticIdata() { - uint32_t RDATA = IMAGE_SCN_CNT_INITIALIZED_DATA | IMAGE_SCN_MEM_READ; - Idata.create(); + uint32_t rdata = IMAGE_SCN_CNT_INITIALIZED_DATA | IMAGE_SCN_MEM_READ; + idata.create(); // Add the .idata content in the right section groups, to allow // chunks from other linked in object files to be grouped together. // See Microsoft PE/COFF spec 5.4 for details. - auto Add = [&](StringRef N, std::vector<Chunk *> &V) { - PartialSection *PSec = createPartialSection(N, RDATA); - PSec->Chunks.insert(PSec->Chunks.end(), V.begin(), V.end()); + auto add = [&](StringRef n, std::vector<Chunk *> &v) { + PartialSection *pSec = createPartialSection(n, rdata); + pSec->chunks.insert(pSec->chunks.end(), v.begin(), v.end()); }; // The loader assumes a specific order of data. // Add each type in the correct order. - Add(".idata$2", Idata.Dirs); - Add(".idata$4", Idata.Lookups); - Add(".idata$5", Idata.Addresses); - Add(".idata$6", Idata.Hints); - Add(".idata$7", Idata.DLLNames); + add(".idata$2", idata.dirs); + add(".idata$4", idata.lookups); + add(".idata$5", idata.addresses); + add(".idata$6", idata.hints); + add(".idata$7", idata.dllNames); } // Locate the first Chunk and size of the import directory list and the // IAT. void Writer::locateImportTables() { - uint32_t RDATA = IMAGE_SCN_CNT_INITIALIZED_DATA | IMAGE_SCN_MEM_READ; + uint32_t rdata = IMAGE_SCN_CNT_INITIALIZED_DATA | IMAGE_SCN_MEM_READ; - if (PartialSection *ImportDirs = findPartialSection(".idata$2", RDATA)) { - if (!ImportDirs->Chunks.empty()) - ImportTableStart = ImportDirs->Chunks.front(); - for (Chunk *C : ImportDirs->Chunks) - ImportTableSize += C->getSize(); + if (PartialSection *importDirs = findPartialSection(".idata$2", rdata)) { + if (!importDirs->chunks.empty()) + importTableStart = importDirs->chunks.front(); + for (Chunk *c : importDirs->chunks) + importTableSize += c->getSize(); } - if (PartialSection *ImportAddresses = findPartialSection(".idata$5", RDATA)) { - if (!ImportAddresses->Chunks.empty()) - IATStart = ImportAddresses->Chunks.front(); - for (Chunk *C : ImportAddresses->Chunks) - IATSize += C->getSize(); + if (PartialSection *importAddresses = findPartialSection(".idata$5", rdata)) { + if (!importAddresses->chunks.empty()) + iatStart = importAddresses->chunks.front(); + for (Chunk *c : importAddresses->chunks) + iatSize += c->getSize(); } } // Create output section objects and add them to OutputSections. void Writer::createSections() { // First, create the builtin sections. - const uint32_t DATA = IMAGE_SCN_CNT_INITIALIZED_DATA; - const uint32_t BSS = IMAGE_SCN_CNT_UNINITIALIZED_DATA; - const uint32_t CODE = IMAGE_SCN_CNT_CODE; - const uint32_t DISCARDABLE = IMAGE_SCN_MEM_DISCARDABLE; - const uint32_t R = IMAGE_SCN_MEM_READ; - const uint32_t W = IMAGE_SCN_MEM_WRITE; - const uint32_t X = IMAGE_SCN_MEM_EXECUTE; - - SmallDenseMap<std::pair<StringRef, uint32_t>, OutputSection *> Sections; - auto CreateSection = [&](StringRef Name, uint32_t OutChars) { - OutputSection *&Sec = Sections[{Name, OutChars}]; - if (!Sec) { - Sec = make<OutputSection>(Name, OutChars); - OutputSections.push_back(Sec); + const uint32_t data = IMAGE_SCN_CNT_INITIALIZED_DATA; + const uint32_t bss = IMAGE_SCN_CNT_UNINITIALIZED_DATA; + const uint32_t code = IMAGE_SCN_CNT_CODE; + const uint32_t discardable = IMAGE_SCN_MEM_DISCARDABLE; + const uint32_t r = IMAGE_SCN_MEM_READ; + const uint32_t w = IMAGE_SCN_MEM_WRITE; + const uint32_t x = IMAGE_SCN_MEM_EXECUTE; + + SmallDenseMap<std::pair<StringRef, uint32_t>, OutputSection *> sections; + auto createSection = [&](StringRef name, uint32_t outChars) { + OutputSection *&sec = sections[{name, outChars}]; + if (!sec) { + sec = make<OutputSection>(name, outChars); + outputSections.push_back(sec); } - return Sec; + return sec; }; // Try to match the section order used by link.exe. - TextSec = CreateSection(".text", CODE | R | X); - CreateSection(".bss", BSS | R | W); - RdataSec = CreateSection(".rdata", DATA | R); - BuildidSec = CreateSection(".buildid", DATA | R); - DataSec = CreateSection(".data", DATA | R | W); - PdataSec = CreateSection(".pdata", DATA | R); - IdataSec = CreateSection(".idata", DATA | R); - EdataSec = CreateSection(".edata", DATA | R); - DidatSec = CreateSection(".didat", DATA | R); - RsrcSec = CreateSection(".rsrc", DATA | R); - RelocSec = CreateSection(".reloc", DATA | DISCARDABLE | R); - CtorsSec = CreateSection(".ctors", DATA | R | W); - DtorsSec = CreateSection(".dtors", DATA | R | W); + textSec = createSection(".text", code | r | x); + createSection(".bss", bss | r | w); + rdataSec = createSection(".rdata", data | r); + buildidSec = createSection(".buildid", data | r); + dataSec = createSection(".data", data | r | w); + pdataSec = createSection(".pdata", data | r); + idataSec = createSection(".idata", data | r); + edataSec = createSection(".edata", data | r); + didatSec = createSection(".didat", data | r); + rsrcSec = createSection(".rsrc", data | r); + relocSec = createSection(".reloc", data | discardable | r); + ctorsSec = createSection(".ctors", data | r | w); + dtorsSec = createSection(".dtors", data | r | w); // Then bin chunks by name and output characteristics. - for (Chunk *C : Symtab->getChunks()) { - auto *SC = dyn_cast<SectionChunk>(C); - if (SC && !SC->Live) { - if (Config->Verbose) - SC->printDiscardedMessage(); + for (Chunk *c : symtab->getChunks()) { + auto *sc = dyn_cast<SectionChunk>(c); + if (sc && !sc->live) { + if (config->verbose) + sc->printDiscardedMessage(); continue; } - StringRef Name = C->getSectionName(); + StringRef name = c->getSectionName(); // On MinGW, comdat groups are formed by putting the comdat group name // after the '$' in the section name. Such a section name suffix shouldn't // imply separate alphabetical sorting of those section chunks though. - if (Config->MinGW && SC && SC->isCOMDAT()) - Name = Name.split('$').first; - PartialSection *PSec = createPartialSection(Name, - C->getOutputCharacteristics()); - PSec->Chunks.push_back(C); + if (config->mingw && sc && sc->isCOMDAT()) + name = name.split('$').first; + PartialSection *pSec = createPartialSection(name, + c->getOutputCharacteristics()); + pSec->chunks.push_back(c); } - fixPartialSectionChars(".rsrc", DATA | R); + fixPartialSectionChars(".rsrc", data | r); // Even in non MinGW cases, we might need to link against GNU import // libraries. - bool HasIdata = fixGnuImportChunks(); - if (!Idata.empty()) - HasIdata = true; + bool hasIdata = fixGnuImportChunks(); + if (!idata.empty()) + hasIdata = true; - if (HasIdata) + if (hasIdata) addSyntheticIdata(); // Process an /order option. - if (!Config->Order.empty()) - for (auto It : PartialSections) - sortBySectionOrder(It.second->Chunks); + if (!config->order.empty()) + for (auto it : partialSections) + sortBySectionOrder(it.second->chunks); - if (HasIdata) + if (hasIdata) locateImportTables(); // Then create an OutputSection for each section. // '$' and all following characters in input section names are // discarded when determining output section. So, .text$foo // contributes to .text, for example. See PE/COFF spec 3.2. - for (auto It : PartialSections) { - PartialSection *PSec = It.second; - StringRef Name = getOutputSectionName(PSec->Name); - uint32_t OutChars = PSec->Characteristics; + for (auto it : partialSections) { + PartialSection *pSec = it.second; + StringRef name = getOutputSectionName(pSec->name); + uint32_t outChars = pSec->characteristics; - if (Name == ".CRT") { + if (name == ".CRT") { // In link.exe, there is a special case for the I386 target where .CRT // sections are treated as if they have output characteristics DATA | R if // their characteristics are DATA | R | W. This implements the same // special case for all architectures. - OutChars = DATA | R; + outChars = data | r; - log("Processing section " + PSec->Name + " -> " + Name); + log("Processing section " + pSec->name + " -> " + name); - sortCRTSectionChunks(PSec->Chunks); + sortCRTSectionChunks(pSec->chunks); } - OutputSection *Sec = CreateSection(Name, OutChars); - for (Chunk *C : PSec->Chunks) - Sec->addChunk(C); + OutputSection *sec = createSection(name, outChars); + for (Chunk *c : pSec->chunks) + sec->addChunk(c); - Sec->addContributingPartialSection(PSec); + sec->addContributingPartialSection(pSec); } // Finally, move some output sections to the end. - auto SectionOrder = [&](const OutputSection *S) { + auto sectionOrder = [&](const OutputSection *s) { // Move DISCARDABLE (or non-memory-mapped) sections to the end of file // because the loader cannot handle holes. Stripping can remove other // discardable ones than .reloc, which is first of them (created early). - if (S->Header.Characteristics & IMAGE_SCN_MEM_DISCARDABLE) + if (s->header.Characteristics & IMAGE_SCN_MEM_DISCARDABLE) return 2; // .rsrc should come at the end of the non-discardable sections because its // size may change by the Win32 UpdateResources() function, causing // subsequent sections to move (see https://crbug.com/827082). - if (S == RsrcSec) + if (s == rsrcSec) return 1; return 0; }; - llvm::stable_sort(OutputSections, - [&](const OutputSection *S, const OutputSection *T) { - return SectionOrder(S) < SectionOrder(T); + llvm::stable_sort(outputSections, + [&](const OutputSection *s, const OutputSection *t) { + return sectionOrder(s) < sectionOrder(t); }); } void Writer::createMiscChunks() { - for (MergeChunk *P : MergeChunk::Instances) { - if (P) { - P->finalizeContents(); - RdataSec->addChunk(P); + for (MergeChunk *p : MergeChunk::instances) { + if (p) { + p->finalizeContents(); + rdataSec->addChunk(p); } } // Create thunks for locally-dllimported symbols. - if (!Symtab->LocalImportChunks.empty()) { - for (Chunk *C : Symtab->LocalImportChunks) - RdataSec->addChunk(C); + if (!symtab->localImportChunks.empty()) { + for (Chunk *c : symtab->localImportChunks) + rdataSec->addChunk(c); } // Create Debug Information Chunks - OutputSection *DebugInfoSec = Config->MinGW ? BuildidSec : RdataSec; - if (Config->Debug || Config->Repro) { - DebugDirectory = make<DebugDirectoryChunk>(DebugRecords, Config->Repro); - DebugInfoSec->addChunk(DebugDirectory); + OutputSection *debugInfoSec = config->mingw ? buildidSec : rdataSec; + if (config->debug || config->repro) { + debugDirectory = make<DebugDirectoryChunk>(debugRecords, config->repro); + debugInfoSec->addChunk(debugDirectory); } - if (Config->Debug) { + if (config->debug) { // Make a CVDebugRecordChunk even when /DEBUG:CV is not specified. We // output a PDB no matter what, and this chunk provides the only means of // allowing a debugger to match a PDB and an executable. So we need it even // if we're ultimately not going to write CodeView data to the PDB. - BuildId = make<CVDebugRecordChunk>(); - DebugRecords.push_back(BuildId); + buildId = make<CVDebugRecordChunk>(); + debugRecords.push_back(buildId); - for (Chunk *C : DebugRecords) - DebugInfoSec->addChunk(C); + for (Chunk *c : debugRecords) + debugInfoSec->addChunk(c); } // Create SEH table. x86-only. - if (Config->Machine == I386) + if (config->machine == I386) createSEHTable(); // Create /guard:cf tables if requested. - if (Config->GuardCF != GuardCFLevel::Off) + if (config->guardCF != GuardCFLevel::Off) createGuardCFTables(); - if (Config->MinGW) { + if (config->mingw) { createRuntimePseudoRelocs(); insertCtorDtorSymbols(); @@ -939,123 +939,123 @@ void Writer::createImportTables() { // Initialize DLLOrder so that import entries are ordered in // the same order as in the command line. (That affects DLL // initialization order, and this ordering is MSVC-compatible.) - for (ImportFile *File : ImportFile::Instances) { - if (!File->Live) + for (ImportFile *file : ImportFile::instances) { + if (!file->live) continue; - std::string DLL = StringRef(File->DLLName).lower(); - if (Config->DLLOrder.count(DLL) == 0) - Config->DLLOrder[DLL] = Config->DLLOrder.size(); - - if (File->ImpSym && !isa<DefinedImportData>(File->ImpSym)) - fatal(toString(*File->ImpSym) + " was replaced"); - DefinedImportData *ImpSym = cast_or_null<DefinedImportData>(File->ImpSym); - if (Config->DelayLoads.count(StringRef(File->DLLName).lower())) { - if (!File->ThunkSym) - fatal("cannot delay-load " + toString(File) + - " due to import of data: " + toString(*ImpSym)); - DelayIdata.add(ImpSym); + std::string dll = StringRef(file->dllName).lower(); + if (config->dllOrder.count(dll) == 0) + config->dllOrder[dll] = config->dllOrder.size(); + + if (file->impSym && !isa<DefinedImportData>(file->impSym)) + fatal(toString(*file->impSym) + " was replaced"); + DefinedImportData *impSym = cast_or_null<DefinedImportData>(file->impSym); + if (config->delayLoads.count(StringRef(file->dllName).lower())) { + if (!file->thunkSym) + fatal("cannot delay-load " + toString(file) + + " due to import of data: " + toString(*impSym)); + delayIdata.add(impSym); } else { - Idata.add(ImpSym); + idata.add(impSym); } } } void Writer::appendImportThunks() { - if (ImportFile::Instances.empty()) + if (ImportFile::instances.empty()) return; - for (ImportFile *File : ImportFile::Instances) { - if (!File->Live) + for (ImportFile *file : ImportFile::instances) { + if (!file->live) continue; - if (!File->ThunkSym) + if (!file->thunkSym) continue; - if (!isa<DefinedImportThunk>(File->ThunkSym)) - fatal(toString(*File->ThunkSym) + " was replaced"); - DefinedImportThunk *Thunk = cast<DefinedImportThunk>(File->ThunkSym); - if (File->ThunkLive) - TextSec->addChunk(Thunk->getChunk()); + if (!isa<DefinedImportThunk>(file->thunkSym)) + fatal(toString(*file->thunkSym) + " was replaced"); + DefinedImportThunk *thunk = cast<DefinedImportThunk>(file->thunkSym); + if (file->thunkLive) + textSec->addChunk(thunk->getChunk()); } - if (!DelayIdata.empty()) { - Defined *Helper = cast<Defined>(Config->DelayLoadHelper); - DelayIdata.create(Helper); - for (Chunk *C : DelayIdata.getChunks()) - DidatSec->addChunk(C); - for (Chunk *C : DelayIdata.getDataChunks()) - DataSec->addChunk(C); - for (Chunk *C : DelayIdata.getCodeChunks()) - TextSec->addChunk(C); + if (!delayIdata.empty()) { + Defined *helper = cast<Defined>(config->delayLoadHelper); + delayIdata.create(helper); + for (Chunk *c : delayIdata.getChunks()) + didatSec->addChunk(c); + for (Chunk *c : delayIdata.getDataChunks()) + dataSec->addChunk(c); + for (Chunk *c : delayIdata.getCodeChunks()) + textSec->addChunk(c); } } void Writer::createExportTable() { - if (Config->Exports.empty()) + if (config->exports.empty()) return; - for (Chunk *C : Edata.Chunks) - EdataSec->addChunk(C); + for (Chunk *c : edata.chunks) + edataSec->addChunk(c); } void Writer::removeUnusedSections() { // Remove sections that we can be sure won't get content, to avoid // allocating space for their section headers. - auto IsUnused = [this](OutputSection *S) { - if (S == RelocSec) + auto isUnused = [this](OutputSection *s) { + if (s == relocSec) return false; // This section is populated later. // MergeChunks have zero size at this point, as their size is finalized // later. Only remove sections that have no Chunks at all. - return S->Chunks.empty(); + return s->chunks.empty(); }; - OutputSections.erase( - std::remove_if(OutputSections.begin(), OutputSections.end(), IsUnused), - OutputSections.end()); + outputSections.erase( + std::remove_if(outputSections.begin(), outputSections.end(), isUnused), + outputSections.end()); } // The Windows loader doesn't seem to like empty sections, // so we remove them if any. void Writer::removeEmptySections() { - auto IsEmpty = [](OutputSection *S) { return S->getVirtualSize() == 0; }; - OutputSections.erase( - std::remove_if(OutputSections.begin(), OutputSections.end(), IsEmpty), - OutputSections.end()); + auto isEmpty = [](OutputSection *s) { return s->getVirtualSize() == 0; }; + outputSections.erase( + std::remove_if(outputSections.begin(), outputSections.end(), isEmpty), + outputSections.end()); } void Writer::assignOutputSectionIndices() { // Assign final output section indices, and assign each chunk to its output // section. - uint32_t Idx = 1; - for (OutputSection *OS : OutputSections) { - OS->SectionIndex = Idx; - for (Chunk *C : OS->Chunks) - C->setOutputSectionIdx(Idx); - ++Idx; + uint32_t idx = 1; + for (OutputSection *os : outputSections) { + os->sectionIndex = idx; + for (Chunk *c : os->chunks) + c->setOutputSectionIdx(idx); + ++idx; } // Merge chunks are containers of chunks, so assign those an output section // too. - for (MergeChunk *MC : MergeChunk::Instances) - if (MC) - for (SectionChunk *SC : MC->Sections) - if (SC && SC->Live) - SC->setOutputSectionIdx(MC->getOutputSectionIdx()); + for (MergeChunk *mc : MergeChunk::instances) + if (mc) + for (SectionChunk *sc : mc->sections) + if (sc && sc->live) + sc->setOutputSectionIdx(mc->getOutputSectionIdx()); } -size_t Writer::addEntryToStringTable(StringRef Str) { - assert(Str.size() > COFF::NameSize); - size_t OffsetOfEntry = Strtab.size() + 4; // +4 for the size field - Strtab.insert(Strtab.end(), Str.begin(), Str.end()); - Strtab.push_back('\0'); - return OffsetOfEntry; +size_t Writer::addEntryToStringTable(StringRef str) { + assert(str.size() > COFF::NameSize); + size_t offsetOfEntry = strtab.size() + 4; // +4 for the size field + strtab.insert(strtab.end(), str.begin(), str.end()); + strtab.push_back('\0'); + return offsetOfEntry; } -Optional<coff_symbol16> Writer::createSymbol(Defined *Def) { - coff_symbol16 Sym; - switch (Def->kind()) { +Optional<coff_symbol16> Writer::createSymbol(Defined *def) { + coff_symbol16 sym; + switch (def->kind()) { case Symbol::DefinedAbsoluteKind: - Sym.Value = Def->getRVA(); - Sym.SectionNumber = IMAGE_SYM_ABSOLUTE; + sym.Value = def->getRVA(); + sym.SectionNumber = IMAGE_SYM_ABSOLUTE; break; case Symbol::DefinedSyntheticKind: // Relative symbols are unrepresentable in a COFF symbol table. @@ -1063,38 +1063,38 @@ Optional<coff_symbol16> Writer::createSymbol(Defined *Def) { default: { // Don't write symbols that won't be written to the output to the symbol // table. - Chunk *C = Def->getChunk(); - if (!C) + Chunk *c = def->getChunk(); + if (!c) return None; - OutputSection *OS = C->getOutputSection(); - if (!OS) + OutputSection *os = c->getOutputSection(); + if (!os) return None; - Sym.Value = Def->getRVA() - OS->getRVA(); - Sym.SectionNumber = OS->SectionIndex; + sym.Value = def->getRVA() - os->getRVA(); + sym.SectionNumber = os->sectionIndex; break; } } - StringRef Name = Def->getName(); - if (Name.size() > COFF::NameSize) { - Sym.Name.Offset.Zeroes = 0; - Sym.Name.Offset.Offset = addEntryToStringTable(Name); + StringRef name = def->getName(); + if (name.size() > COFF::NameSize) { + sym.Name.Offset.Zeroes = 0; + sym.Name.Offset.Offset = addEntryToStringTable(name); } else { - memset(Sym.Name.ShortName, 0, COFF::NameSize); - memcpy(Sym.Name.ShortName, Name.data(), Name.size()); + memset(sym.Name.ShortName, 0, COFF::NameSize); + memcpy(sym.Name.ShortName, name.data(), name.size()); } - if (auto *D = dyn_cast<DefinedCOFF>(Def)) { - COFFSymbolRef Ref = D->getCOFFSymbol(); - Sym.Type = Ref.getType(); - Sym.StorageClass = Ref.getStorageClass(); + if (auto *d = dyn_cast<DefinedCOFF>(def)) { + COFFSymbolRef ref = d->getCOFFSymbol(); + sym.Type = ref.getType(); + sym.StorageClass = ref.getStorageClass(); } else { - Sym.Type = IMAGE_SYM_TYPE_NULL; - Sym.StorageClass = IMAGE_SYM_CLASS_EXTERNAL; + sym.Type = IMAGE_SYM_TYPE_NULL; + sym.StorageClass = IMAGE_SYM_CLASS_EXTERNAL; } - Sym.NumberOfAuxSymbols = 0; - return Sym; + sym.NumberOfAuxSymbols = 0; + return sym; } void Writer::createSymbolAndStringTable() { @@ -1106,120 +1106,120 @@ void Writer::createSymbolAndStringTable() { // solution where discardable sections have long names preserved and // non-discardable sections have their names truncated, to ensure that any // section which is mapped at runtime also has its name mapped at runtime. - for (OutputSection *Sec : OutputSections) { - if (Sec->Name.size() <= COFF::NameSize) + for (OutputSection *sec : outputSections) { + if (sec->name.size() <= COFF::NameSize) continue; - if ((Sec->Header.Characteristics & IMAGE_SCN_MEM_DISCARDABLE) == 0) + if ((sec->header.Characteristics & IMAGE_SCN_MEM_DISCARDABLE) == 0) continue; - Sec->setStringTableOff(addEntryToStringTable(Sec->Name)); + sec->setStringTableOff(addEntryToStringTable(sec->name)); } - if (Config->DebugDwarf || Config->DebugSymtab) { - for (ObjFile *File : ObjFile::Instances) { - for (Symbol *B : File->getSymbols()) { - auto *D = dyn_cast_or_null<Defined>(B); - if (!D || D->WrittenToSymtab) + if (config->debugDwarf || config->debugSymtab) { + for (ObjFile *file : ObjFile::instances) { + for (Symbol *b : file->getSymbols()) { + auto *d = dyn_cast_or_null<Defined>(b); + if (!d || d->writtenToSymtab) continue; - D->WrittenToSymtab = true; + d->writtenToSymtab = true; - if (Optional<coff_symbol16> Sym = createSymbol(D)) - OutputSymtab.push_back(*Sym); + if (Optional<coff_symbol16> sym = createSymbol(d)) + outputSymtab.push_back(*sym); } } } - if (OutputSymtab.empty() && Strtab.empty()) + if (outputSymtab.empty() && strtab.empty()) return; // We position the symbol table to be adjacent to the end of the last section. - uint64_t FileOff = FileSize; - PointerToSymbolTable = FileOff; - FileOff += OutputSymtab.size() * sizeof(coff_symbol16); - FileOff += 4 + Strtab.size(); - FileSize = alignTo(FileOff, Config->FileAlign); + uint64_t fileOff = fileSize; + pointerToSymbolTable = fileOff; + fileOff += outputSymtab.size() * sizeof(coff_symbol16); + fileOff += 4 + strtab.size(); + fileSize = alignTo(fileOff, config->fileAlign); } void Writer::mergeSections() { - if (!PdataSec->Chunks.empty()) { - FirstPdata = PdataSec->Chunks.front(); - LastPdata = PdataSec->Chunks.back(); + if (!pdataSec->chunks.empty()) { + firstPdata = pdataSec->chunks.front(); + lastPdata = pdataSec->chunks.back(); } - for (auto &P : Config->Merge) { - StringRef ToName = P.second; - if (P.first == ToName) + for (auto &p : config->merge) { + StringRef toName = p.second; + if (p.first == toName) continue; - StringSet<> Names; + StringSet<> names; while (1) { - if (!Names.insert(ToName).second) - fatal("/merge: cycle found for section '" + P.first + "'"); - auto I = Config->Merge.find(ToName); - if (I == Config->Merge.end()) + if (!names.insert(toName).second) + fatal("/merge: cycle found for section '" + p.first + "'"); + auto i = config->merge.find(toName); + if (i == config->merge.end()) break; - ToName = I->second; + toName = i->second; } - OutputSection *From = findSection(P.first); - OutputSection *To = findSection(ToName); - if (!From) + OutputSection *from = findSection(p.first); + OutputSection *to = findSection(toName); + if (!from) continue; - if (!To) { - From->Name = ToName; + if (!to) { + from->name = toName; continue; } - To->merge(From); + to->merge(from); } } // Visits all sections to assign incremental, non-overlapping RVAs and // file offsets. void Writer::assignAddresses() { - SizeOfHeaders = DOSStubSize + sizeof(PEMagic) + sizeof(coff_file_header) + - sizeof(data_directory) * NumberOfDataDirectory + - sizeof(coff_section) * OutputSections.size(); - SizeOfHeaders += - Config->is64() ? sizeof(pe32plus_header) : sizeof(pe32_header); - SizeOfHeaders = alignTo(SizeOfHeaders, Config->FileAlign); - uint64_t RVA = PageSize; // The first page is kept unmapped. - FileSize = SizeOfHeaders; - - for (OutputSection *Sec : OutputSections) { - if (Sec == RelocSec) + sizeOfHeaders = dosStubSize + sizeof(PEMagic) + sizeof(coff_file_header) + + sizeof(data_directory) * numberOfDataDirectory + + sizeof(coff_section) * outputSections.size(); + sizeOfHeaders += + config->is64() ? sizeof(pe32plus_header) : sizeof(pe32_header); + sizeOfHeaders = alignTo(sizeOfHeaders, config->fileAlign); + uint64_t rva = pageSize; // The first page is kept unmapped. + fileSize = sizeOfHeaders; + + for (OutputSection *sec : outputSections) { + if (sec == relocSec) addBaserels(); - uint64_t RawSize = 0, VirtualSize = 0; - Sec->Header.VirtualAddress = RVA; + uint64_t rawSize = 0, virtualSize = 0; + sec->header.VirtualAddress = rva; // If /FUNCTIONPADMIN is used, functions are padded in order to create a // hotpatchable image. - const bool IsCodeSection = - (Sec->Header.Characteristics & IMAGE_SCN_CNT_CODE) && - (Sec->Header.Characteristics & IMAGE_SCN_MEM_READ) && - (Sec->Header.Characteristics & IMAGE_SCN_MEM_EXECUTE); - uint32_t Padding = IsCodeSection ? Config->FunctionPadMin : 0; - - for (Chunk *C : Sec->Chunks) { - if (Padding && C->isHotPatchable()) - VirtualSize += Padding; - VirtualSize = alignTo(VirtualSize, C->getAlignment()); - C->setRVA(RVA + VirtualSize); - VirtualSize += C->getSize(); - if (C->HasData) - RawSize = alignTo(VirtualSize, Config->FileAlign); + const bool isCodeSection = + (sec->header.Characteristics & IMAGE_SCN_CNT_CODE) && + (sec->header.Characteristics & IMAGE_SCN_MEM_READ) && + (sec->header.Characteristics & IMAGE_SCN_MEM_EXECUTE); + uint32_t padding = isCodeSection ? config->functionPadMin : 0; + + for (Chunk *c : sec->chunks) { + if (padding && c->isHotPatchable()) + virtualSize += padding; + virtualSize = alignTo(virtualSize, c->getAlignment()); + c->setRVA(rva + virtualSize); + virtualSize += c->getSize(); + if (c->hasData) + rawSize = alignTo(virtualSize, config->fileAlign); } - if (VirtualSize > UINT32_MAX) - error("section larger than 4 GiB: " + Sec->Name); - Sec->Header.VirtualSize = VirtualSize; - Sec->Header.SizeOfRawData = RawSize; - if (RawSize != 0) - Sec->Header.PointerToRawData = FileSize; - RVA += alignTo(VirtualSize, PageSize); - FileSize += alignTo(RawSize, Config->FileAlign); + if (virtualSize > UINT32_MAX) + error("section larger than 4 GiB: " + sec->name); + sec->header.VirtualSize = virtualSize; + sec->header.SizeOfRawData = rawSize; + if (rawSize != 0) + sec->header.PointerToRawData = fileSize; + rva += alignTo(virtualSize, pageSize); + fileSize += alignTo(rawSize, config->fileAlign); } - SizeOfImage = alignTo(RVA, PageSize); + sizeOfImage = alignTo(rva, pageSize); // Assign addresses to sections in MergeChunks. - for (MergeChunk *MC : MergeChunk::Instances) - if (MC) - MC->assignSubsectionRVAs(); + for (MergeChunk *mc : MergeChunk::instances) + if (mc) + mc->assignSubsectionRVAs(); } template <typename PEHeaderTy> void Writer::writeHeader() { @@ -1228,249 +1228,249 @@ template <typename PEHeaderTy> void Writer::writeHeader() { // under DOS, that program gets run (usually to just print an error message). // When run under Windows, the loader looks at AddressOfNewExeHeader and uses // the PE header instead. - uint8_t *Buf = Buffer->getBufferStart(); - auto *DOS = reinterpret_cast<dos_header *>(Buf); - Buf += sizeof(dos_header); - DOS->Magic[0] = 'M'; - DOS->Magic[1] = 'Z'; - DOS->UsedBytesInTheLastPage = DOSStubSize % 512; - DOS->FileSizeInPages = divideCeil(DOSStubSize, 512); - DOS->HeaderSizeInParagraphs = sizeof(dos_header) / 16; - - DOS->AddressOfRelocationTable = sizeof(dos_header); - DOS->AddressOfNewExeHeader = DOSStubSize; + uint8_t *buf = buffer->getBufferStart(); + auto *dos = reinterpret_cast<dos_header *>(buf); + buf += sizeof(dos_header); + dos->Magic[0] = 'M'; + dos->Magic[1] = 'Z'; + dos->UsedBytesInTheLastPage = dosStubSize % 512; + dos->FileSizeInPages = divideCeil(dosStubSize, 512); + dos->HeaderSizeInParagraphs = sizeof(dos_header) / 16; + + dos->AddressOfRelocationTable = sizeof(dos_header); + dos->AddressOfNewExeHeader = dosStubSize; // Write DOS program. - memcpy(Buf, DOSProgram, sizeof(DOSProgram)); - Buf += sizeof(DOSProgram); + memcpy(buf, dosProgram, sizeof(dosProgram)); + buf += sizeof(dosProgram); // Write PE magic - memcpy(Buf, PEMagic, sizeof(PEMagic)); - Buf += sizeof(PEMagic); + memcpy(buf, PEMagic, sizeof(PEMagic)); + buf += sizeof(PEMagic); // Write COFF header - auto *COFF = reinterpret_cast<coff_file_header *>(Buf); - Buf += sizeof(*COFF); - COFF->Machine = Config->Machine; - COFF->NumberOfSections = OutputSections.size(); - COFF->Characteristics = IMAGE_FILE_EXECUTABLE_IMAGE; - if (Config->LargeAddressAware) - COFF->Characteristics |= IMAGE_FILE_LARGE_ADDRESS_AWARE; - if (!Config->is64()) - COFF->Characteristics |= IMAGE_FILE_32BIT_MACHINE; - if (Config->DLL) - COFF->Characteristics |= IMAGE_FILE_DLL; - if (!Config->Relocatable) - COFF->Characteristics |= IMAGE_FILE_RELOCS_STRIPPED; - if (Config->SwaprunCD) - COFF->Characteristics |= IMAGE_FILE_REMOVABLE_RUN_FROM_SWAP; - if (Config->SwaprunNet) - COFF->Characteristics |= IMAGE_FILE_NET_RUN_FROM_SWAP; - COFF->SizeOfOptionalHeader = - sizeof(PEHeaderTy) + sizeof(data_directory) * NumberOfDataDirectory; + auto *coff = reinterpret_cast<coff_file_header *>(buf); + buf += sizeof(*coff); + coff->Machine = config->machine; + coff->NumberOfSections = outputSections.size(); + coff->Characteristics = IMAGE_FILE_EXECUTABLE_IMAGE; + if (config->largeAddressAware) + coff->Characteristics |= IMAGE_FILE_LARGE_ADDRESS_AWARE; + if (!config->is64()) + coff->Characteristics |= IMAGE_FILE_32BIT_MACHINE; + if (config->dll) + coff->Characteristics |= IMAGE_FILE_DLL; + if (!config->relocatable) + coff->Characteristics |= IMAGE_FILE_RELOCS_STRIPPED; + if (config->swaprunCD) + coff->Characteristics |= IMAGE_FILE_REMOVABLE_RUN_FROM_SWAP; + if (config->swaprunNet) + coff->Characteristics |= IMAGE_FILE_NET_RUN_FROM_SWAP; + coff->SizeOfOptionalHeader = + sizeof(PEHeaderTy) + sizeof(data_directory) * numberOfDataDirectory; // Write PE header - auto *PE = reinterpret_cast<PEHeaderTy *>(Buf); - Buf += sizeof(*PE); - PE->Magic = Config->is64() ? PE32Header::PE32_PLUS : PE32Header::PE32; + auto *pe = reinterpret_cast<PEHeaderTy *>(buf); + buf += sizeof(*pe); + pe->Magic = config->is64() ? PE32Header::PE32_PLUS : PE32Header::PE32; // If {Major,Minor}LinkerVersion is left at 0.0, then for some // reason signing the resulting PE file with Authenticode produces a // signature that fails to validate on Windows 7 (but is OK on 10). // Set it to 14.0, which is what VS2015 outputs, and which avoids // that problem. - PE->MajorLinkerVersion = 14; - PE->MinorLinkerVersion = 0; - - PE->ImageBase = Config->ImageBase; - PE->SectionAlignment = PageSize; - PE->FileAlignment = Config->FileAlign; - PE->MajorImageVersion = Config->MajorImageVersion; - PE->MinorImageVersion = Config->MinorImageVersion; - PE->MajorOperatingSystemVersion = Config->MajorOSVersion; - PE->MinorOperatingSystemVersion = Config->MinorOSVersion; - PE->MajorSubsystemVersion = Config->MajorOSVersion; - PE->MinorSubsystemVersion = Config->MinorOSVersion; - PE->Subsystem = Config->Subsystem; - PE->SizeOfImage = SizeOfImage; - PE->SizeOfHeaders = SizeOfHeaders; - if (!Config->NoEntry) { - Defined *Entry = cast<Defined>(Config->Entry); - PE->AddressOfEntryPoint = Entry->getRVA(); + pe->MajorLinkerVersion = 14; + pe->MinorLinkerVersion = 0; + + pe->ImageBase = config->imageBase; + pe->SectionAlignment = pageSize; + pe->FileAlignment = config->fileAlign; + pe->MajorImageVersion = config->majorImageVersion; + pe->MinorImageVersion = config->minorImageVersion; + pe->MajorOperatingSystemVersion = config->majorOSVersion; + pe->MinorOperatingSystemVersion = config->minorOSVersion; + pe->MajorSubsystemVersion = config->majorOSVersion; + pe->MinorSubsystemVersion = config->minorOSVersion; + pe->Subsystem = config->subsystem; + pe->SizeOfImage = sizeOfImage; + pe->SizeOfHeaders = sizeOfHeaders; + if (!config->noEntry) { + Defined *entry = cast<Defined>(config->entry); + pe->AddressOfEntryPoint = entry->getRVA(); // Pointer to thumb code must have the LSB set, so adjust it. - if (Config->Machine == ARMNT) - PE->AddressOfEntryPoint |= 1; - } - PE->SizeOfStackReserve = Config->StackReserve; - PE->SizeOfStackCommit = Config->StackCommit; - PE->SizeOfHeapReserve = Config->HeapReserve; - PE->SizeOfHeapCommit = Config->HeapCommit; - if (Config->AppContainer) - PE->DLLCharacteristics |= IMAGE_DLL_CHARACTERISTICS_APPCONTAINER; - if (Config->DynamicBase) - PE->DLLCharacteristics |= IMAGE_DLL_CHARACTERISTICS_DYNAMIC_BASE; - if (Config->HighEntropyVA) - PE->DLLCharacteristics |= IMAGE_DLL_CHARACTERISTICS_HIGH_ENTROPY_VA; - if (!Config->AllowBind) - PE->DLLCharacteristics |= IMAGE_DLL_CHARACTERISTICS_NO_BIND; - if (Config->NxCompat) - PE->DLLCharacteristics |= IMAGE_DLL_CHARACTERISTICS_NX_COMPAT; - if (!Config->AllowIsolation) - PE->DLLCharacteristics |= IMAGE_DLL_CHARACTERISTICS_NO_ISOLATION; - if (Config->GuardCF != GuardCFLevel::Off) - PE->DLLCharacteristics |= IMAGE_DLL_CHARACTERISTICS_GUARD_CF; - if (Config->IntegrityCheck) - PE->DLLCharacteristics |= IMAGE_DLL_CHARACTERISTICS_FORCE_INTEGRITY; - if (SetNoSEHCharacteristic) - PE->DLLCharacteristics |= IMAGE_DLL_CHARACTERISTICS_NO_SEH; - if (Config->TerminalServerAware) - PE->DLLCharacteristics |= IMAGE_DLL_CHARACTERISTICS_TERMINAL_SERVER_AWARE; - PE->NumberOfRvaAndSize = NumberOfDataDirectory; - if (TextSec->getVirtualSize()) { - PE->BaseOfCode = TextSec->getRVA(); - PE->SizeOfCode = TextSec->getRawSize(); - } - PE->SizeOfInitializedData = getSizeOfInitializedData(); + if (config->machine == ARMNT) + pe->AddressOfEntryPoint |= 1; + } + pe->SizeOfStackReserve = config->stackReserve; + pe->SizeOfStackCommit = config->stackCommit; + pe->SizeOfHeapReserve = config->heapReserve; + pe->SizeOfHeapCommit = config->heapCommit; + if (config->appContainer) + pe->DLLCharacteristics |= IMAGE_DLL_CHARACTERISTICS_APPCONTAINER; + if (config->dynamicBase) + pe->DLLCharacteristics |= IMAGE_DLL_CHARACTERISTICS_DYNAMIC_BASE; + if (config->highEntropyVA) + pe->DLLCharacteristics |= IMAGE_DLL_CHARACTERISTICS_HIGH_ENTROPY_VA; + if (!config->allowBind) + pe->DLLCharacteristics |= IMAGE_DLL_CHARACTERISTICS_NO_BIND; + if (config->nxCompat) + pe->DLLCharacteristics |= IMAGE_DLL_CHARACTERISTICS_NX_COMPAT; + if (!config->allowIsolation) + pe->DLLCharacteristics |= IMAGE_DLL_CHARACTERISTICS_NO_ISOLATION; + if (config->guardCF != GuardCFLevel::Off) + pe->DLLCharacteristics |= IMAGE_DLL_CHARACTERISTICS_GUARD_CF; + if (config->integrityCheck) + pe->DLLCharacteristics |= IMAGE_DLL_CHARACTERISTICS_FORCE_INTEGRITY; + if (setNoSEHCharacteristic) + pe->DLLCharacteristics |= IMAGE_DLL_CHARACTERISTICS_NO_SEH; + if (config->terminalServerAware) + pe->DLLCharacteristics |= IMAGE_DLL_CHARACTERISTICS_TERMINAL_SERVER_AWARE; + pe->NumberOfRvaAndSize = numberOfDataDirectory; + if (textSec->getVirtualSize()) { + pe->BaseOfCode = textSec->getRVA(); + pe->SizeOfCode = textSec->getRawSize(); + } + pe->SizeOfInitializedData = getSizeOfInitializedData(); // Write data directory - auto *Dir = reinterpret_cast<data_directory *>(Buf); - Buf += sizeof(*Dir) * NumberOfDataDirectory; - if (!Config->Exports.empty()) { - Dir[EXPORT_TABLE].RelativeVirtualAddress = Edata.getRVA(); - Dir[EXPORT_TABLE].Size = Edata.getSize(); - } - if (ImportTableStart) { - Dir[IMPORT_TABLE].RelativeVirtualAddress = ImportTableStart->getRVA(); - Dir[IMPORT_TABLE].Size = ImportTableSize; - } - if (IATStart) { - Dir[IAT].RelativeVirtualAddress = IATStart->getRVA(); - Dir[IAT].Size = IATSize; - } - if (RsrcSec->getVirtualSize()) { - Dir[RESOURCE_TABLE].RelativeVirtualAddress = RsrcSec->getRVA(); - Dir[RESOURCE_TABLE].Size = RsrcSec->getVirtualSize(); - } - if (FirstPdata) { - Dir[EXCEPTION_TABLE].RelativeVirtualAddress = FirstPdata->getRVA(); - Dir[EXCEPTION_TABLE].Size = - LastPdata->getRVA() + LastPdata->getSize() - FirstPdata->getRVA(); - } - if (RelocSec->getVirtualSize()) { - Dir[BASE_RELOCATION_TABLE].RelativeVirtualAddress = RelocSec->getRVA(); - Dir[BASE_RELOCATION_TABLE].Size = RelocSec->getVirtualSize(); - } - if (Symbol *Sym = Symtab->findUnderscore("_tls_used")) { - if (Defined *B = dyn_cast<Defined>(Sym)) { - Dir[TLS_TABLE].RelativeVirtualAddress = B->getRVA(); - Dir[TLS_TABLE].Size = Config->is64() + auto *dir = reinterpret_cast<data_directory *>(buf); + buf += sizeof(*dir) * numberOfDataDirectory; + if (!config->exports.empty()) { + dir[EXPORT_TABLE].RelativeVirtualAddress = edata.getRVA(); + dir[EXPORT_TABLE].Size = edata.getSize(); + } + if (importTableStart) { + dir[IMPORT_TABLE].RelativeVirtualAddress = importTableStart->getRVA(); + dir[IMPORT_TABLE].Size = importTableSize; + } + if (iatStart) { + dir[IAT].RelativeVirtualAddress = iatStart->getRVA(); + dir[IAT].Size = iatSize; + } + if (rsrcSec->getVirtualSize()) { + dir[RESOURCE_TABLE].RelativeVirtualAddress = rsrcSec->getRVA(); + dir[RESOURCE_TABLE].Size = rsrcSec->getVirtualSize(); + } + if (firstPdata) { + dir[EXCEPTION_TABLE].RelativeVirtualAddress = firstPdata->getRVA(); + dir[EXCEPTION_TABLE].Size = + lastPdata->getRVA() + lastPdata->getSize() - firstPdata->getRVA(); + } + if (relocSec->getVirtualSize()) { + dir[BASE_RELOCATION_TABLE].RelativeVirtualAddress = relocSec->getRVA(); + dir[BASE_RELOCATION_TABLE].Size = relocSec->getVirtualSize(); + } + if (Symbol *sym = symtab->findUnderscore("_tls_used")) { + if (Defined *b = dyn_cast<Defined>(sym)) { + dir[TLS_TABLE].RelativeVirtualAddress = b->getRVA(); + dir[TLS_TABLE].Size = config->is64() ? sizeof(object::coff_tls_directory64) : sizeof(object::coff_tls_directory32); } } - if (DebugDirectory) { - Dir[DEBUG_DIRECTORY].RelativeVirtualAddress = DebugDirectory->getRVA(); - Dir[DEBUG_DIRECTORY].Size = DebugDirectory->getSize(); + if (debugDirectory) { + dir[DEBUG_DIRECTORY].RelativeVirtualAddress = debugDirectory->getRVA(); + dir[DEBUG_DIRECTORY].Size = debugDirectory->getSize(); } - if (Symbol *Sym = Symtab->findUnderscore("_load_config_used")) { - if (auto *B = dyn_cast<DefinedRegular>(Sym)) { - SectionChunk *SC = B->getChunk(); - assert(B->getRVA() >= SC->getRVA()); - uint64_t OffsetInChunk = B->getRVA() - SC->getRVA(); - if (!SC->HasData || OffsetInChunk + 4 > SC->getSize()) + if (Symbol *sym = symtab->findUnderscore("_load_config_used")) { + if (auto *b = dyn_cast<DefinedRegular>(sym)) { + SectionChunk *sc = b->getChunk(); + assert(b->getRVA() >= sc->getRVA()); + uint64_t offsetInChunk = b->getRVA() - sc->getRVA(); + if (!sc->hasData || offsetInChunk + 4 > sc->getSize()) fatal("_load_config_used is malformed"); - ArrayRef<uint8_t> SecContents = SC->getContents(); - uint32_t LoadConfigSize = - *reinterpret_cast<const ulittle32_t *>(&SecContents[OffsetInChunk]); - if (OffsetInChunk + LoadConfigSize > SC->getSize()) + ArrayRef<uint8_t> secContents = sc->getContents(); + uint32_t loadConfigSize = + *reinterpret_cast<const ulittle32_t *>(&secContents[offsetInChunk]); + if (offsetInChunk + loadConfigSize > sc->getSize()) fatal("_load_config_used is too large"); - Dir[LOAD_CONFIG_TABLE].RelativeVirtualAddress = B->getRVA(); - Dir[LOAD_CONFIG_TABLE].Size = LoadConfigSize; + dir[LOAD_CONFIG_TABLE].RelativeVirtualAddress = b->getRVA(); + dir[LOAD_CONFIG_TABLE].Size = loadConfigSize; } } - if (!DelayIdata.empty()) { - Dir[DELAY_IMPORT_DESCRIPTOR].RelativeVirtualAddress = - DelayIdata.getDirRVA(); - Dir[DELAY_IMPORT_DESCRIPTOR].Size = DelayIdata.getDirSize(); + if (!delayIdata.empty()) { + dir[DELAY_IMPORT_DESCRIPTOR].RelativeVirtualAddress = + delayIdata.getDirRVA(); + dir[DELAY_IMPORT_DESCRIPTOR].Size = delayIdata.getDirSize(); } // Write section table - for (OutputSection *Sec : OutputSections) { - Sec->writeHeaderTo(Buf); - Buf += sizeof(coff_section); + for (OutputSection *sec : outputSections) { + sec->writeHeaderTo(buf); + buf += sizeof(coff_section); } - SectionTable = ArrayRef<uint8_t>( - Buf - OutputSections.size() * sizeof(coff_section), Buf); + sectionTable = ArrayRef<uint8_t>( + buf - outputSections.size() * sizeof(coff_section), buf); - if (OutputSymtab.empty() && Strtab.empty()) + if (outputSymtab.empty() && strtab.empty()) return; - COFF->PointerToSymbolTable = PointerToSymbolTable; - uint32_t NumberOfSymbols = OutputSymtab.size(); - COFF->NumberOfSymbols = NumberOfSymbols; - auto *SymbolTable = reinterpret_cast<coff_symbol16 *>( - Buffer->getBufferStart() + COFF->PointerToSymbolTable); - for (size_t I = 0; I != NumberOfSymbols; ++I) - SymbolTable[I] = OutputSymtab[I]; + coff->PointerToSymbolTable = pointerToSymbolTable; + uint32_t numberOfSymbols = outputSymtab.size(); + coff->NumberOfSymbols = numberOfSymbols; + auto *symbolTable = reinterpret_cast<coff_symbol16 *>( + buffer->getBufferStart() + coff->PointerToSymbolTable); + for (size_t i = 0; i != numberOfSymbols; ++i) + symbolTable[i] = outputSymtab[i]; // Create the string table, it follows immediately after the symbol table. // The first 4 bytes is length including itself. - Buf = reinterpret_cast<uint8_t *>(&SymbolTable[NumberOfSymbols]); - write32le(Buf, Strtab.size() + 4); - if (!Strtab.empty()) - memcpy(Buf + 4, Strtab.data(), Strtab.size()); + buf = reinterpret_cast<uint8_t *>(&symbolTable[numberOfSymbols]); + write32le(buf, strtab.size() + 4); + if (!strtab.empty()) + memcpy(buf + 4, strtab.data(), strtab.size()); } -void Writer::openFile(StringRef Path) { - Buffer = CHECK( - FileOutputBuffer::create(Path, FileSize, FileOutputBuffer::F_executable), - "failed to open " + Path); +void Writer::openFile(StringRef path) { + buffer = CHECK( + FileOutputBuffer::create(path, fileSize, FileOutputBuffer::F_executable), + "failed to open " + path); } void Writer::createSEHTable() { // Set the no SEH characteristic on x86 binaries unless we find exception // handlers. - SetNoSEHCharacteristic = true; + setNoSEHCharacteristic = true; - SymbolRVASet Handlers; - for (ObjFile *File : ObjFile::Instances) { + SymbolRVASet handlers; + for (ObjFile *file : ObjFile::instances) { // FIXME: We should error here instead of earlier unless /safeseh:no was // passed. - if (!File->hasSafeSEH()) + if (!file->hasSafeSEH()) return; - markSymbolsForRVATable(File, File->getSXDataChunks(), Handlers); + markSymbolsForRVATable(file, file->getSXDataChunks(), handlers); } // Remove the "no SEH" characteristic if all object files were built with // safeseh, we found some exception handlers, and there is a load config in // the object. - SetNoSEHCharacteristic = - Handlers.empty() || !Symtab->findUnderscore("_load_config_used"); + setNoSEHCharacteristic = + handlers.empty() || !symtab->findUnderscore("_load_config_used"); - maybeAddRVATable(std::move(Handlers), "__safe_se_handler_table", + maybeAddRVATable(std::move(handlers), "__safe_se_handler_table", "__safe_se_handler_count"); } // Add a symbol to an RVA set. Two symbols may have the same RVA, but an RVA set // cannot contain duplicates. Therefore, the set is uniqued by Chunk and the // symbol's offset into that Chunk. -static void addSymbolToRVASet(SymbolRVASet &RVASet, Defined *S) { - Chunk *C = S->getChunk(); - if (auto *SC = dyn_cast<SectionChunk>(C)) - C = SC->Repl; // Look through ICF replacement. - uint32_t Off = S->getRVA() - (C ? C->getRVA() : 0); - RVASet.insert({C, Off}); +static void addSymbolToRVASet(SymbolRVASet &rvaSet, Defined *s) { + Chunk *c = s->getChunk(); + if (auto *sc = dyn_cast<SectionChunk>(c)) + c = sc->repl; // Look through ICF replacement. + uint32_t off = s->getRVA() - (c ? c->getRVA() : 0); + rvaSet.insert({c, off}); } // Given a symbol, add it to the GFIDs table if it is a live, defined, function // symbol in an executable section. -static void maybeAddAddressTakenFunction(SymbolRVASet &AddressTakenSyms, - Symbol *S) { - if (!S) +static void maybeAddAddressTakenFunction(SymbolRVASet &addressTakenSyms, + Symbol *s) { + if (!s) return; - switch (S->kind()) { + switch (s->kind()) { case Symbol::DefinedLocalImportKind: case Symbol::DefinedImportDataKind: // Defines an __imp_ pointer, so it is data, so it is ignored. @@ -1491,19 +1491,19 @@ static void maybeAddAddressTakenFunction(SymbolRVASet &AddressTakenSyms, case Symbol::DefinedImportThunkKind: // Thunks are always code, include them. - addSymbolToRVASet(AddressTakenSyms, cast<Defined>(S)); + addSymbolToRVASet(addressTakenSyms, cast<Defined>(s)); break; case Symbol::DefinedRegularKind: { // This is a regular, defined, symbol from a COFF file. Mark the symbol as // address taken if the symbol type is function and it's in an executable // section. - auto *D = cast<DefinedRegular>(S); - if (D->getCOFFSymbol().getComplexType() == COFF::IMAGE_SYM_DTYPE_FUNCTION) { - SectionChunk *SC = dyn_cast<SectionChunk>(D->getChunk()); - if (SC && SC->Live && - SC->getOutputCharacteristics() & IMAGE_SCN_MEM_EXECUTE) - addSymbolToRVASet(AddressTakenSyms, D); + auto *d = cast<DefinedRegular>(s); + if (d->getCOFFSymbol().getComplexType() == COFF::IMAGE_SYM_DTYPE_FUNCTION) { + SectionChunk *sc = dyn_cast<SectionChunk>(d->getChunk()); + if (sc && sc->live && + sc->getOutputCharacteristics() & IMAGE_SCN_MEM_EXECUTE) + addSymbolToRVASet(addressTakenSyms, d); } break; } @@ -1512,23 +1512,23 @@ static void maybeAddAddressTakenFunction(SymbolRVASet &AddressTakenSyms, // Visit all relocations from all section contributions of this object file and // mark the relocation target as address-taken. -static void markSymbolsWithRelocations(ObjFile *File, - SymbolRVASet &UsedSymbols) { - for (Chunk *C : File->getChunks()) { +static void markSymbolsWithRelocations(ObjFile *file, + SymbolRVASet &usedSymbols) { + for (Chunk *c : file->getChunks()) { // We only care about live section chunks. Common chunks and other chunks // don't generally contain relocations. - SectionChunk *SC = dyn_cast<SectionChunk>(C); - if (!SC || !SC->Live) + SectionChunk *sc = dyn_cast<SectionChunk>(c); + if (!sc || !sc->live) continue; - for (const coff_relocation &Reloc : SC->getRelocs()) { - if (Config->Machine == I386 && Reloc.Type == COFF::IMAGE_REL_I386_REL32) + for (const coff_relocation &reloc : sc->getRelocs()) { + if (config->machine == I386 && reloc.Type == COFF::IMAGE_REL_I386_REL32) // Ignore relative relocations on x86. On x86_64 they can't be ignored // since they're also used to compute absolute addresses. continue; - Symbol *Ref = SC->File->getSymbol(Reloc.SymbolTableIndex); - maybeAddAddressTakenFunction(UsedSymbols, Ref); + Symbol *ref = sc->file->getSymbol(reloc.SymbolTableIndex); + maybeAddAddressTakenFunction(usedSymbols, ref); } } } @@ -1537,89 +1537,89 @@ static void markSymbolsWithRelocations(ObjFile *File, // address-taken functions. It is sorted and uniqued, just like the safe SEH // table. void Writer::createGuardCFTables() { - SymbolRVASet AddressTakenSyms; - SymbolRVASet LongJmpTargets; - for (ObjFile *File : ObjFile::Instances) { + SymbolRVASet addressTakenSyms; + SymbolRVASet longJmpTargets; + for (ObjFile *file : ObjFile::instances) { // If the object was compiled with /guard:cf, the address taken symbols // are in .gfids$y sections, and the longjmp targets are in .gljmp$y // sections. If the object was not compiled with /guard:cf, we assume there // were no setjmp targets, and that all code symbols with relocations are // possibly address-taken. - if (File->hasGuardCF()) { - markSymbolsForRVATable(File, File->getGuardFidChunks(), AddressTakenSyms); - markSymbolsForRVATable(File, File->getGuardLJmpChunks(), LongJmpTargets); + if (file->hasGuardCF()) { + markSymbolsForRVATable(file, file->getGuardFidChunks(), addressTakenSyms); + markSymbolsForRVATable(file, file->getGuardLJmpChunks(), longJmpTargets); } else { - markSymbolsWithRelocations(File, AddressTakenSyms); + markSymbolsWithRelocations(file, addressTakenSyms); } } // Mark the image entry as address-taken. - if (Config->Entry) - maybeAddAddressTakenFunction(AddressTakenSyms, Config->Entry); + if (config->entry) + maybeAddAddressTakenFunction(addressTakenSyms, config->entry); // Mark exported symbols in executable sections as address-taken. - for (Export &E : Config->Exports) - maybeAddAddressTakenFunction(AddressTakenSyms, E.Sym); + for (Export &e : config->exports) + maybeAddAddressTakenFunction(addressTakenSyms, e.sym); // Ensure sections referenced in the gfid table are 16-byte aligned. - for (const ChunkAndOffset &C : AddressTakenSyms) - if (C.InputChunk->getAlignment() < 16) - C.InputChunk->setAlignment(16); + for (const ChunkAndOffset &c : addressTakenSyms) + if (c.inputChunk->getAlignment() < 16) + c.inputChunk->setAlignment(16); - maybeAddRVATable(std::move(AddressTakenSyms), "__guard_fids_table", + maybeAddRVATable(std::move(addressTakenSyms), "__guard_fids_table", "__guard_fids_count"); // Add the longjmp target table unless the user told us not to. - if (Config->GuardCF == GuardCFLevel::Full) - maybeAddRVATable(std::move(LongJmpTargets), "__guard_longjmp_table", + if (config->guardCF == GuardCFLevel::Full) + maybeAddRVATable(std::move(longJmpTargets), "__guard_longjmp_table", "__guard_longjmp_count"); // Set __guard_flags, which will be used in the load config to indicate that // /guard:cf was enabled. - uint32_t GuardFlags = uint32_t(coff_guard_flags::CFInstrumented) | + uint32_t guardFlags = uint32_t(coff_guard_flags::CFInstrumented) | uint32_t(coff_guard_flags::HasFidTable); - if (Config->GuardCF == GuardCFLevel::Full) - GuardFlags |= uint32_t(coff_guard_flags::HasLongJmpTable); - Symbol *FlagSym = Symtab->findUnderscore("__guard_flags"); - cast<DefinedAbsolute>(FlagSym)->setVA(GuardFlags); + if (config->guardCF == GuardCFLevel::Full) + guardFlags |= uint32_t(coff_guard_flags::HasLongJmpTable); + Symbol *flagSym = symtab->findUnderscore("__guard_flags"); + cast<DefinedAbsolute>(flagSym)->setVA(guardFlags); } // Take a list of input sections containing symbol table indices and add those // symbols to an RVA table. The challenge is that symbol RVAs are not known and // depend on the table size, so we can't directly build a set of integers. -void Writer::markSymbolsForRVATable(ObjFile *File, - ArrayRef<SectionChunk *> SymIdxChunks, - SymbolRVASet &TableSymbols) { - for (SectionChunk *C : SymIdxChunks) { +void Writer::markSymbolsForRVATable(ObjFile *file, + ArrayRef<SectionChunk *> symIdxChunks, + SymbolRVASet &tableSymbols) { + for (SectionChunk *c : symIdxChunks) { // Skip sections discarded by linker GC. This comes up when a .gfids section // is associated with something like a vtable and the vtable is discarded. // In this case, the associated gfids section is discarded, and we don't // mark the virtual member functions as address-taken by the vtable. - if (!C->Live) + if (!c->live) continue; // Validate that the contents look like symbol table indices. - ArrayRef<uint8_t> Data = C->getContents(); - if (Data.size() % 4 != 0) { - warn("ignoring " + C->getSectionName() + - " symbol table index section in object " + toString(File)); + ArrayRef<uint8_t> data = c->getContents(); + if (data.size() % 4 != 0) { + warn("ignoring " + c->getSectionName() + + " symbol table index section in object " + toString(file)); continue; } // Read each symbol table index and check if that symbol was included in the // final link. If so, add it to the table symbol set. - ArrayRef<ulittle32_t> SymIndices( - reinterpret_cast<const ulittle32_t *>(Data.data()), Data.size() / 4); - ArrayRef<Symbol *> ObjSymbols = File->getSymbols(); - for (uint32_t SymIndex : SymIndices) { - if (SymIndex >= ObjSymbols.size()) { + ArrayRef<ulittle32_t> symIndices( + reinterpret_cast<const ulittle32_t *>(data.data()), data.size() / 4); + ArrayRef<Symbol *> objSymbols = file->getSymbols(); + for (uint32_t symIndex : symIndices) { + if (symIndex >= objSymbols.size()) { warn("ignoring invalid symbol table index in section " + - C->getSectionName() + " in object " + toString(File)); + c->getSectionName() + " in object " + toString(file)); continue; } - if (Symbol *S = ObjSymbols[SymIndex]) { - if (S->isLive()) - addSymbolToRVASet(TableSymbols, cast<Defined>(S)); + if (Symbol *s = objSymbols[symIndex]) { + if (s->isLive()) + addSymbolToRVASet(tableSymbols, cast<Defined>(s)); } } } @@ -1628,18 +1628,18 @@ void Writer::markSymbolsForRVATable(ObjFile *File, // Replace the absolute table symbol with a synthetic symbol pointing to // TableChunk so that we can emit base relocations for it and resolve section // relative relocations. -void Writer::maybeAddRVATable(SymbolRVASet TableSymbols, StringRef TableSym, - StringRef CountSym) { - if (TableSymbols.empty()) +void Writer::maybeAddRVATable(SymbolRVASet tableSymbols, StringRef tableSym, + StringRef countSym) { + if (tableSymbols.empty()) return; - RVATableChunk *TableChunk = make<RVATableChunk>(std::move(TableSymbols)); - RdataSec->addChunk(TableChunk); + RVATableChunk *tableChunk = make<RVATableChunk>(std::move(tableSymbols)); + rdataSec->addChunk(tableChunk); - Symbol *T = Symtab->findUnderscore(TableSym); - Symbol *C = Symtab->findUnderscore(CountSym); - replaceSymbol<DefinedSynthetic>(T, T->getName(), TableChunk); - cast<DefinedAbsolute>(C)->setVA(TableChunk->getSize() / 4); + Symbol *t = symtab->findUnderscore(tableSym); + Symbol *c = symtab->findUnderscore(countSym); + replaceSymbol<DefinedSynthetic>(t, t->getName(), tableChunk); + cast<DefinedAbsolute>(c)->setVA(tableChunk->getSize() / 4); } // MinGW specific. Gather all relocations that are imported from a DLL even @@ -1647,26 +1647,26 @@ void Writer::maybeAddRVATable(SymbolRVASet TableSymbols, StringRef TableSym, // uses for fixing them up, and provide the synthetic symbols that the // runtime uses for finding the table. void Writer::createRuntimePseudoRelocs() { - std::vector<RuntimePseudoReloc> Rels; + std::vector<RuntimePseudoReloc> rels; - for (Chunk *C : Symtab->getChunks()) { - auto *SC = dyn_cast<SectionChunk>(C); - if (!SC || !SC->Live) + for (Chunk *c : symtab->getChunks()) { + auto *sc = dyn_cast<SectionChunk>(c); + if (!sc || !sc->live) continue; - SC->getRuntimePseudoRelocs(Rels); + sc->getRuntimePseudoRelocs(rels); } - if (!Rels.empty()) - log("Writing " + Twine(Rels.size()) + " runtime pseudo relocations"); - PseudoRelocTableChunk *Table = make<PseudoRelocTableChunk>(Rels); - RdataSec->addChunk(Table); - EmptyChunk *EndOfList = make<EmptyChunk>(); - RdataSec->addChunk(EndOfList); + if (!rels.empty()) + log("Writing " + Twine(rels.size()) + " runtime pseudo relocations"); + PseudoRelocTableChunk *table = make<PseudoRelocTableChunk>(rels); + rdataSec->addChunk(table); + EmptyChunk *endOfList = make<EmptyChunk>(); + rdataSec->addChunk(endOfList); - Symbol *HeadSym = Symtab->findUnderscore("__RUNTIME_PSEUDO_RELOC_LIST__"); - Symbol *EndSym = Symtab->findUnderscore("__RUNTIME_PSEUDO_RELOC_LIST_END__"); - replaceSymbol<DefinedSynthetic>(HeadSym, HeadSym->getName(), Table); - replaceSymbol<DefinedSynthetic>(EndSym, EndSym->getName(), EndOfList); + Symbol *headSym = symtab->findUnderscore("__RUNTIME_PSEUDO_RELOC_LIST__"); + Symbol *endSym = symtab->findUnderscore("__RUNTIME_PSEUDO_RELOC_LIST_END__"); + replaceSymbol<DefinedSynthetic>(headSym, headSym->getName(), table); + replaceSymbol<DefinedSynthetic>(endSym, endSym->getName(), endOfList); } // MinGW specific. @@ -1675,32 +1675,32 @@ void Writer::createRuntimePseudoRelocs() { // There's a symbol pointing to the start sentinel pointer, __CTOR_LIST__ // and __DTOR_LIST__ respectively. void Writer::insertCtorDtorSymbols() { - AbsolutePointerChunk *CtorListHead = make<AbsolutePointerChunk>(-1); - AbsolutePointerChunk *CtorListEnd = make<AbsolutePointerChunk>(0); - AbsolutePointerChunk *DtorListHead = make<AbsolutePointerChunk>(-1); - AbsolutePointerChunk *DtorListEnd = make<AbsolutePointerChunk>(0); - CtorsSec->insertChunkAtStart(CtorListHead); - CtorsSec->addChunk(CtorListEnd); - DtorsSec->insertChunkAtStart(DtorListHead); - DtorsSec->addChunk(DtorListEnd); - - Symbol *CtorListSym = Symtab->findUnderscore("__CTOR_LIST__"); - Symbol *DtorListSym = Symtab->findUnderscore("__DTOR_LIST__"); - replaceSymbol<DefinedSynthetic>(CtorListSym, CtorListSym->getName(), - CtorListHead); - replaceSymbol<DefinedSynthetic>(DtorListSym, DtorListSym->getName(), - DtorListHead); + AbsolutePointerChunk *ctorListHead = make<AbsolutePointerChunk>(-1); + AbsolutePointerChunk *ctorListEnd = make<AbsolutePointerChunk>(0); + AbsolutePointerChunk *dtorListHead = make<AbsolutePointerChunk>(-1); + AbsolutePointerChunk *dtorListEnd = make<AbsolutePointerChunk>(0); + ctorsSec->insertChunkAtStart(ctorListHead); + ctorsSec->addChunk(ctorListEnd); + dtorsSec->insertChunkAtStart(dtorListHead); + dtorsSec->addChunk(dtorListEnd); + + Symbol *ctorListSym = symtab->findUnderscore("__CTOR_LIST__"); + Symbol *dtorListSym = symtab->findUnderscore("__DTOR_LIST__"); + replaceSymbol<DefinedSynthetic>(ctorListSym, ctorListSym->getName(), + ctorListHead); + replaceSymbol<DefinedSynthetic>(dtorListSym, dtorListSym->getName(), + dtorListHead); } // Handles /section options to allow users to overwrite // section attributes. void Writer::setSectionPermissions() { - for (auto &P : Config->Section) { - StringRef Name = P.first; - uint32_t Perm = P.second; - for (OutputSection *Sec : OutputSections) - if (Sec->Name == Name) - Sec->setPermissions(Perm); + for (auto &p : config->section) { + StringRef name = p.first; + uint32_t perm = p.second; + for (OutputSection *sec : outputSections) + if (sec->name == name) + sec->setPermissions(perm); } } @@ -1708,18 +1708,18 @@ void Writer::setSectionPermissions() { void Writer::writeSections() { // Record the number of sections to apply section index relocations // against absolute symbols. See applySecIdx in Chunks.cpp.. - DefinedAbsolute::NumOutputSections = OutputSections.size(); + DefinedAbsolute::numOutputSections = outputSections.size(); - uint8_t *Buf = Buffer->getBufferStart(); - for (OutputSection *Sec : OutputSections) { - uint8_t *SecBuf = Buf + Sec->getFileOff(); + uint8_t *buf = buffer->getBufferStart(); + for (OutputSection *sec : outputSections) { + uint8_t *secBuf = buf + sec->getFileOff(); // Fill gaps between functions in .text with INT3 instructions // instead of leaving as NUL bytes (which can be interpreted as // ADD instructions). - if (Sec->Header.Characteristics & IMAGE_SCN_CNT_CODE) - memset(SecBuf, 0xCC, Sec->getRawSize()); - parallelForEach(Sec->Chunks, [&](Chunk *C) { - C->writeTo(SecBuf + C->getRVA() - Sec->getRVA()); + if (sec->header.Characteristics & IMAGE_SCN_CNT_CODE) + memset(secBuf, 0xCC, sec->getRawSize()); + parallelForEach(sec->chunks, [&](Chunk *c) { + c->writeTo(secBuf + c->getRVA() - sec->getRVA()); }); } } @@ -1731,8 +1731,8 @@ void Writer::writeBuildId() { // 2) In all cases, the PE COFF file header also contains a timestamp. // For reproducibility, instead of a timestamp we want to use a hash of the // PE contents. - if (Config->Debug) { - assert(BuildId && "BuildId is not set!"); + if (config->debug) { + assert(buildId && "BuildId is not set!"); // BuildId->BuildId was filled in when the PDB was written. } @@ -1740,65 +1740,65 @@ void Writer::writeBuildId() { // "timestamp" in the COFF file header, and the ones in the coff debug // directory. Now we can hash the file and write that hash to the various // timestamp fields in the file. - StringRef OutputFileData( - reinterpret_cast<const char *>(Buffer->getBufferStart()), - Buffer->getBufferSize()); + StringRef outputFileData( + reinterpret_cast<const char *>(buffer->getBufferStart()), + buffer->getBufferSize()); - uint32_t Timestamp = Config->Timestamp; - uint64_t Hash = 0; - bool GenerateSyntheticBuildId = - Config->MinGW && Config->Debug && Config->PDBPath.empty(); + uint32_t timestamp = config->timestamp; + uint64_t hash = 0; + bool generateSyntheticBuildId = + config->mingw && config->debug && config->pdbPath.empty(); - if (Config->Repro || GenerateSyntheticBuildId) - Hash = xxHash64(OutputFileData); + if (config->repro || generateSyntheticBuildId) + hash = xxHash64(outputFileData); - if (Config->Repro) - Timestamp = static_cast<uint32_t>(Hash); + if (config->repro) + timestamp = static_cast<uint32_t>(hash); - if (GenerateSyntheticBuildId) { + if (generateSyntheticBuildId) { // For MinGW builds without a PDB file, we still generate a build id // to allow associating a crash dump to the executable. - BuildId->BuildId->PDB70.CVSignature = OMF::Signature::PDB70; - BuildId->BuildId->PDB70.Age = 1; - memcpy(BuildId->BuildId->PDB70.Signature, &Hash, 8); + buildId->buildId->PDB70.CVSignature = OMF::Signature::PDB70; + buildId->buildId->PDB70.Age = 1; + memcpy(buildId->buildId->PDB70.Signature, &hash, 8); // xxhash only gives us 8 bytes, so put some fixed data in the other half. - memcpy(&BuildId->BuildId->PDB70.Signature[8], "LLD PDB.", 8); + memcpy(&buildId->buildId->PDB70.Signature[8], "LLD PDB.", 8); } - if (DebugDirectory) - DebugDirectory->setTimeDateStamp(Timestamp); + if (debugDirectory) + debugDirectory->setTimeDateStamp(timestamp); - uint8_t *Buf = Buffer->getBufferStart(); - Buf += DOSStubSize + sizeof(PEMagic); - object::coff_file_header *CoffHeader = - reinterpret_cast<coff_file_header *>(Buf); - CoffHeader->TimeDateStamp = Timestamp; + uint8_t *buf = buffer->getBufferStart(); + buf += dosStubSize + sizeof(PEMagic); + object::coff_file_header *coffHeader = + reinterpret_cast<coff_file_header *>(buf); + coffHeader->TimeDateStamp = timestamp; } // Sort .pdata section contents according to PE/COFF spec 5.5. void Writer::sortExceptionTable() { - if (!FirstPdata) + if (!firstPdata) return; // We assume .pdata contains function table entries only. - auto BufAddr = [&](Chunk *C) { - OutputSection *OS = C->getOutputSection(); - return Buffer->getBufferStart() + OS->getFileOff() + C->getRVA() - - OS->getRVA(); + auto bufAddr = [&](Chunk *c) { + OutputSection *os = c->getOutputSection(); + return buffer->getBufferStart() + os->getFileOff() + c->getRVA() - + os->getRVA(); }; - uint8_t *Begin = BufAddr(FirstPdata); - uint8_t *End = BufAddr(LastPdata) + LastPdata->getSize(); - if (Config->Machine == AMD64) { - struct Entry { ulittle32_t Begin, End, Unwind; }; + uint8_t *begin = bufAddr(firstPdata); + uint8_t *end = bufAddr(lastPdata) + lastPdata->getSize(); + if (config->machine == AMD64) { + struct Entry { ulittle32_t begin, end, unwind; }; parallelSort( - MutableArrayRef<Entry>((Entry *)Begin, (Entry *)End), - [](const Entry &A, const Entry &B) { return A.Begin < B.Begin; }); + MutableArrayRef<Entry>((Entry *)begin, (Entry *)end), + [](const Entry &a, const Entry &b) { return a.begin < b.begin; }); return; } - if (Config->Machine == ARMNT || Config->Machine == ARM64) { - struct Entry { ulittle32_t Begin, Unwind; }; + if (config->machine == ARMNT || config->machine == ARM64) { + struct Entry { ulittle32_t begin, unwind; }; parallelSort( - MutableArrayRef<Entry>((Entry *)Begin, (Entry *)End), - [](const Entry &A, const Entry &B) { return A.Begin < B.Begin; }); + MutableArrayRef<Entry>((Entry *)begin, (Entry *)end), + [](const Entry &a, const Entry &b) { return a.begin < b.begin; }); return; } errs() << "warning: don't know how to handle .pdata.\n"; @@ -1818,92 +1818,92 @@ void Writer::sortExceptionTable() { // pointers in the order that they are listed in the object file (top to // bottom), otherwise global objects might not be initialized in the // correct order. -void Writer::sortCRTSectionChunks(std::vector<Chunk *> &Chunks) { - auto SectionChunkOrder = [](const Chunk *A, const Chunk *B) { - auto SA = dyn_cast<SectionChunk>(A); - auto SB = dyn_cast<SectionChunk>(B); - assert(SA && SB && "Non-section chunks in CRT section!"); +void Writer::sortCRTSectionChunks(std::vector<Chunk *> &chunks) { + auto sectionChunkOrder = [](const Chunk *a, const Chunk *b) { + auto sa = dyn_cast<SectionChunk>(a); + auto sb = dyn_cast<SectionChunk>(b); + assert(sa && sb && "Non-section chunks in CRT section!"); - StringRef SAObj = SA->File->MB.getBufferIdentifier(); - StringRef SBObj = SB->File->MB.getBufferIdentifier(); + StringRef sAObj = sa->file->mb.getBufferIdentifier(); + StringRef sBObj = sb->file->mb.getBufferIdentifier(); - return SAObj == SBObj && SA->getSectionNumber() < SB->getSectionNumber(); + return sAObj == sBObj && sa->getSectionNumber() < sb->getSectionNumber(); }; - llvm::stable_sort(Chunks, SectionChunkOrder); + llvm::stable_sort(chunks, sectionChunkOrder); - if (Config->Verbose) { - for (auto &C : Chunks) { - auto SC = dyn_cast<SectionChunk>(C); - log(" " + SC->File->MB.getBufferIdentifier().str() + - ", SectionID: " + Twine(SC->getSectionNumber())); + if (config->verbose) { + for (auto &c : chunks) { + auto sc = dyn_cast<SectionChunk>(c); + log(" " + sc->file->mb.getBufferIdentifier().str() + + ", SectionID: " + Twine(sc->getSectionNumber())); } } } -OutputSection *Writer::findSection(StringRef Name) { - for (OutputSection *Sec : OutputSections) - if (Sec->Name == Name) - return Sec; +OutputSection *Writer::findSection(StringRef name) { + for (OutputSection *sec : outputSections) + if (sec->name == name) + return sec; return nullptr; } uint32_t Writer::getSizeOfInitializedData() { - uint32_t Res = 0; - for (OutputSection *S : OutputSections) - if (S->Header.Characteristics & IMAGE_SCN_CNT_INITIALIZED_DATA) - Res += S->getRawSize(); - return Res; + uint32_t res = 0; + for (OutputSection *s : outputSections) + if (s->header.Characteristics & IMAGE_SCN_CNT_INITIALIZED_DATA) + res += s->getRawSize(); + return res; } // Add base relocations to .reloc section. void Writer::addBaserels() { - if (!Config->Relocatable) + if (!config->relocatable) return; - RelocSec->Chunks.clear(); - std::vector<Baserel> V; - for (OutputSection *Sec : OutputSections) { - if (Sec->Header.Characteristics & IMAGE_SCN_MEM_DISCARDABLE) + relocSec->chunks.clear(); + std::vector<Baserel> v; + for (OutputSection *sec : outputSections) { + if (sec->header.Characteristics & IMAGE_SCN_MEM_DISCARDABLE) continue; // Collect all locations for base relocations. - for (Chunk *C : Sec->Chunks) - C->getBaserels(&V); + for (Chunk *c : sec->chunks) + c->getBaserels(&v); // Add the addresses to .reloc section. - if (!V.empty()) - addBaserelBlocks(V); - V.clear(); + if (!v.empty()) + addBaserelBlocks(v); + v.clear(); } } // Add addresses to .reloc section. Note that addresses are grouped by page. -void Writer::addBaserelBlocks(std::vector<Baserel> &V) { - const uint32_t Mask = ~uint32_t(PageSize - 1); - uint32_t Page = V[0].RVA & Mask; - size_t I = 0, J = 1; - for (size_t E = V.size(); J < E; ++J) { - uint32_t P = V[J].RVA & Mask; - if (P == Page) +void Writer::addBaserelBlocks(std::vector<Baserel> &v) { + const uint32_t mask = ~uint32_t(pageSize - 1); + uint32_t page = v[0].rva & mask; + size_t i = 0, j = 1; + for (size_t e = v.size(); j < e; ++j) { + uint32_t p = v[j].rva & mask; + if (p == page) continue; - RelocSec->addChunk(make<BaserelChunk>(Page, &V[I], &V[0] + J)); - I = J; - Page = P; + relocSec->addChunk(make<BaserelChunk>(page, &v[i], &v[0] + j)); + i = j; + page = p; } - if (I == J) + if (i == j) return; - RelocSec->addChunk(make<BaserelChunk>(Page, &V[I], &V[0] + J)); + relocSec->addChunk(make<BaserelChunk>(page, &v[i], &v[0] + j)); } -PartialSection *Writer::createPartialSection(StringRef Name, - uint32_t OutChars) { - PartialSection *&PSec = PartialSections[{Name, OutChars}]; - if (PSec) - return PSec; - PSec = make<PartialSection>(Name, OutChars); - return PSec; +PartialSection *Writer::createPartialSection(StringRef name, + uint32_t outChars) { + PartialSection *&pSec = partialSections[{name, outChars}]; + if (pSec) + return pSec; + pSec = make<PartialSection>(name, outChars); + return pSec; } -PartialSection *Writer::findPartialSection(StringRef Name, uint32_t OutChars) { - auto It = PartialSections.find({Name, OutChars}); - if (It != PartialSections.end()) - return It->second; +PartialSection *Writer::findPartialSection(StringRef name, uint32_t outChars) { + auto it = partialSections.find({name, outChars}); + if (it != partialSections.end()) + return it->second; return nullptr; } |