//===----------------------------------------------------------------------===//
#include "Config.h"
+#include "DLL.h"
+#include "InputFiles.h"
+#include "SymbolTable.h"
+#include "Symbols.h"
#include "Writer.h"
#include "llvm/ADT/ArrayRef.h"
#include "llvm/ADT/DenseMap.h"
#include <algorithm>
#include <cstdio>
#include <map>
+#include <memory>
#include <utility>
using namespace llvm;
using namespace llvm::object;
using namespace llvm::support;
using namespace llvm::support::endian;
+using namespace lld;
+using namespace lld::coff;
static const int PageSize = 4096;
static const int FileAlignment = 512;
static const int DOSStubSize = 64;
static const int NumberfOfDataDirectory = 16;
+namespace {
+// The writer writes a SymbolTable result to a file.
+class Writer {
+public:
+ Writer(SymbolTable *T, StringRef S) : Symtab(T), OutputPath(S) {}
+ std::error_code run();
+
+private:
+ void markLive();
+ void dedupCOMDATs();
+ void createSections();
+ void createMiscChunks();
+ void createImportTables();
+ void createExportTable();
+ void assignAddresses();
+ void removeEmptySections();
+ void createSymbolAndStringTable();
+ std::error_code openFile(StringRef OutputPath);
+ template <typename PEHeaderTy> void writeHeader();
+ void fixSafeSEHSymbols();
+ void writeSections();
+ void sortExceptionTable();
+ void applyRelocations();
+
+ llvm::Optional<coff_symbol16> createSymbol(Defined *D);
+ size_t addEntryToStringTable(StringRef Str);
+
+ OutputSection *findSection(StringRef Name);
+ OutputSection *createSection(StringRef Name);
+ void addBaserels(OutputSection *Dest);
+ void addBaserelBlocks(OutputSection *Dest, std::vector<Baserel> &V);
+
+ uint32_t getSizeOfInitializedData();
+ std::map<StringRef, std::vector<DefinedImportData *>> binImports();
+
+ SymbolTable *Symtab;
+ StringRef OutputPath;
+ std::unique_ptr<llvm::FileOutputBuffer> Buffer;
+ llvm::SpecificBumpPtrAllocator<OutputSection> CAlloc;
+ llvm::SpecificBumpPtrAllocator<BaserelChunk> BAlloc;
+ std::vector<OutputSection *> OutputSections;
+ std::vector<char> Strtab;
+ std::vector<llvm::object::coff_symbol16> OutputSymtab;
+ IdataContents Idata;
+ DelayLoadContents DelayIdata;
+ EdataContents Edata;
+ std::unique_ptr<SEHTableChunk> SEHTable;
+
+ bool Is64;
+ uint64_t FileSize;
+ uint32_t PointerToSymbolTable = 0;
+ uint64_t SizeOfImage;
+ uint64_t SizeOfHeaders;
+
+ std::vector<std::unique_ptr<Chunk>> Chunks;
+};
+} // anonymous namespace
+
namespace lld {
namespace coff {
-// The main function of the writer.
-std::error_code Writer::write(StringRef OutputPath) {
- markLive();
- dedupCOMDATs();
- createSections();
- createMiscChunks();
- createImportTables();
- createExportTable();
- if (Config->Relocatable)
- createSection(".reloc");
- assignAddresses();
- removeEmptySections();
- createSymbolAndStringTable();
- if (auto EC = openFile(OutputPath))
- return EC;
- if (Config->is64()) {
- writeHeader<pe32plus_header>();
- } else {
- writeHeader<pe32_header>();
- }
- fixSafeSEHSymbols();
- writeSections();
- sortExceptionTable();
- return Buffer->commit();
+std::error_code writeResult(SymbolTable *T, StringRef Path) {
+ return Writer(T, Path).run();
}
+// OutputSection represents a section in an output file. It's a
+// container of chunks. OutputSection and Chunk are 1:N relationship.
+// Chunks cannot belong to more than one OutputSections. The writer
+// creates multiple OutputSections and assign them unique,
+// non-overlapping file offsets and RVAs.
+class OutputSection {
+public:
+ OutputSection(StringRef N) : Name(N), Header({}) {}
+ void setRVA(uint64_t);
+ void setFileOffset(uint64_t);
+ void addChunk(Chunk *C);
+ StringRef getName() { return Name; }
+ std::vector<Chunk *> &getChunks() { return Chunks; }
+ void addPermissions(uint32_t C);
+ uint32_t getPermissions() { return Header.Characteristics & PermMask; }
+ uint32_t getCharacteristics() { return Header.Characteristics; }
+ uint64_t getRVA() { return Header.VirtualAddress; }
+ uint64_t getFileOff() { return Header.PointerToRawData; }
+ void writeHeaderTo(uint8_t *Buf);
+
+ // Returns the size of this section in an executable memory image.
+ // This may be smaller than the raw size (the raw size is multiple
+ // of disk sector size, so there may be padding at end), or may be
+ // larger (if that's the case, the loader reserves spaces after end
+ // of raw data).
+ uint64_t getVirtualSize() { return Header.VirtualSize; }
+
+ // Returns the size of the section in the output file.
+ uint64_t getRawSize() { return Header.SizeOfRawData; }
+
+ // Set offset into the string table storing this section name.
+ // Used only when the name is longer than 8 bytes.
+ void setStringTableOff(uint32_t V) { StringTableOff = V; }
+
+ // N.B. The section index is one based.
+ uint32_t SectionIndex = 0;
+
+private:
+ StringRef Name;
+ coff_section Header;
+ uint32_t StringTableOff = 0;
+ std::vector<Chunk *> Chunks;
+};
+
void OutputSection::setRVA(uint64_t RVA) {
Header.VirtualAddress = RVA;
for (Chunk *C : Chunks)
}
}
+uint64_t Defined::getSecrel() {
+ if (auto *D = dyn_cast<DefinedRegular>(this))
+ return getRVA() - D->getChunk()->getOutputSection()->getRVA();
+ llvm::report_fatal_error("SECREL relocation points to a non-regular symbol");
+}
+
+uint64_t Defined::getSectionIndex() {
+ if (auto *D = dyn_cast<DefinedRegular>(this))
+ return D->getChunk()->getOutputSection()->SectionIndex;
+ llvm::report_fatal_error("SECTION relocation points to a non-regular symbol");
+}
+
+bool Defined::isExecutable() {
+ const auto X = IMAGE_SCN_MEM_EXECUTE;
+ if (auto *D = dyn_cast<DefinedRegular>(this))
+ return D->getChunk()->getOutputSection()->getPermissions() & X;
+ return isa<DefinedImportThunk>(this);
+}
+
+} // namespace coff
+} // namespace lld
+
+// The main function of the writer.
+std::error_code Writer::run() {
+ markLive();
+ dedupCOMDATs();
+ createSections();
+ createMiscChunks();
+ createImportTables();
+ createExportTable();
+ if (Config->Relocatable)
+ createSection(".reloc");
+ assignAddresses();
+ removeEmptySections();
+ createSymbolAndStringTable();
+ if (auto EC = openFile(OutputPath))
+ return EC;
+ if (Config->is64()) {
+ writeHeader<pe32plus_header>();
+ } else {
+ writeHeader<pe32_header>();
+ }
+ fixSafeSEHSymbols();
+ writeSections();
+ sortExceptionTable();
+ return Buffer->commit();
+}
+
// Set live bit on for each reachable chunk. Unmarked (unreachable)
// COMDAT chunks will be ignored in the next step, so that they don't
// come to the final output file.
if (Config->Machine != I386)
return;
std::set<Defined *> Handlers;
- for (ObjectFile *File : Symtab->ObjectFiles) {
+ for (lld::coff::ObjectFile *File : Symtab->ObjectFiles) {
if (!File->SEHCompat)
return;
for (SymbolBody *B : File->SEHandlers)
Sec->setStringTableOff(addEntryToStringTable(Name));
}
- for (ObjectFile *File : Symtab->ObjectFiles)
+ for (lld::coff::ObjectFile *File : Symtab->ObjectFiles)
for (SymbolBody *B : File->getSymbols())
if (auto *D = dyn_cast<Defined>(B))
if (Optional<coff_symbol16> Sym = createSymbol(D))
BaserelChunk *Buf = BAlloc.Allocate();
Dest->addChunk(new (Buf) BaserelChunk(Page, &V[I], &V[0] + J));
}
-
-uint64_t Defined::getSecrel() {
- if (auto *D = dyn_cast<DefinedRegular>(this))
- return getRVA() - D->getChunk()->getOutputSection()->getRVA();
- llvm::report_fatal_error("SECREL relocation points to a non-regular symbol");
-}
-
-uint64_t Defined::getSectionIndex() {
- if (auto *D = dyn_cast<DefinedRegular>(this))
- return D->getChunk()->getOutputSection()->SectionIndex;
- llvm::report_fatal_error("SECTION relocation points to a non-regular symbol");
-}
-
-bool Defined::isExecutable() {
- const auto X = IMAGE_SCN_MEM_EXECUTE;
- if (auto *D = dyn_cast<DefinedRegular>(this))
- return D->getChunk()->getOutputSection()->getPermissions() & X;
- return isa<DefinedImportThunk>(this);
-}
-
-} // namespace coff
-} // namespace lld
#ifndef LLD_COFF_WRITER_H
#define LLD_COFF_WRITER_H
-#include "DLL.h"
-#include "InputFiles.h"
-#include "SymbolTable.h"
-#include "llvm/ADT/Optional.h"
-#include "llvm/Support/FileOutputBuffer.h"
-#include <memory>
#include <vector>
namespace lld {
namespace coff {
-// Implemented in ICF.cpp.
-void doICF(const std::vector<Chunk *> &Chunks);
-
-// OutputSection represents a section in an output file. It's a
-// container of chunks. OutputSection and Chunk are 1:N relationship.
-// Chunks cannot belong to more than one OutputSections. The writer
-// creates multiple OutputSections and assign them unique,
-// non-overlapping file offsets and RVAs.
-class OutputSection {
-public:
- OutputSection(StringRef N) : Name(N), Header({}) {}
- void setRVA(uint64_t);
- void setFileOffset(uint64_t);
- void addChunk(Chunk *C);
- StringRef getName() { return Name; }
- std::vector<Chunk *> &getChunks() { return Chunks; }
- void addPermissions(uint32_t C);
- uint32_t getPermissions() { return Header.Characteristics & PermMask; }
- uint32_t getCharacteristics() { return Header.Characteristics; }
- uint64_t getRVA() { return Header.VirtualAddress; }
- uint64_t getFileOff() { return Header.PointerToRawData; }
- void writeHeaderTo(uint8_t *Buf);
-
- // Returns the size of this section in an executable memory image.
- // This may be smaller than the raw size (the raw size is multiple
- // of disk sector size, so there may be padding at end), or may be
- // larger (if that's the case, the loader reserves spaces after end
- // of raw data).
- uint64_t getVirtualSize() { return Header.VirtualSize; }
-
- // Returns the size of the section in the output file.
- uint64_t getRawSize() { return Header.SizeOfRawData; }
-
- // Set offset into the string table storing this section name.
- // Used only when the name is longer than 8 bytes.
- void setStringTableOff(uint32_t V) { StringTableOff = V; }
-
- // N.B. The section index is one based.
- uint32_t SectionIndex = 0;
-
-private:
- StringRef Name;
- coff_section Header;
- uint32_t StringTableOff = 0;
- std::vector<Chunk *> Chunks;
-};
+class Chunk;
+class OutputSection;
-// The writer writes a SymbolTable result to a file.
-class Writer {
-public:
- explicit Writer(SymbolTable *T) : Symtab(T) {}
- std::error_code write(StringRef Path);
+std::error_code writeResult(SymbolTable *T, StringRef Path);
-private:
- void markLive();
- void dedupCOMDATs();
- void createSections();
- void createMiscChunks();
- void createImportTables();
- void createExportTable();
- void assignAddresses();
- void removeEmptySections();
- void createSymbolAndStringTable();
- std::error_code openFile(StringRef OutputPath);
- template <typename PEHeaderTy> void writeHeader();
- void fixSafeSEHSymbols();
- void writeSections();
- void sortExceptionTable();
- void applyRelocations();
-
- llvm::Optional<coff_symbol16> createSymbol(Defined *D);
- size_t addEntryToStringTable(StringRef Str);
-
- OutputSection *findSection(StringRef Name);
- OutputSection *createSection(StringRef Name);
- void addBaserels(OutputSection *Dest);
- void addBaserelBlocks(OutputSection *Dest, std::vector<Baserel> &V);
-
- uint32_t getSizeOfInitializedData();
- std::map<StringRef, std::vector<DefinedImportData *>> binImports();
-
- SymbolTable *Symtab;
- std::unique_ptr<llvm::FileOutputBuffer> Buffer;
- llvm::SpecificBumpPtrAllocator<OutputSection> CAlloc;
- llvm::SpecificBumpPtrAllocator<BaserelChunk> BAlloc;
- std::vector<OutputSection *> OutputSections;
- std::vector<char> Strtab;
- std::vector<llvm::object::coff_symbol16> OutputSymtab;
- IdataContents Idata;
- DelayLoadContents DelayIdata;
- EdataContents Edata;
- std::unique_ptr<SEHTableChunk> SEHTable;
-
- bool Is64;
- uint64_t FileSize;
- uint32_t PointerToSymbolTable = 0;
- uint64_t SizeOfImage;
- uint64_t SizeOfHeaders;
-
- std::vector<std::unique_ptr<Chunk>> Chunks;
-};
+// Implemented in ICF.cpp.
+void doICF(const std::vector<Chunk *> &Chunks);
-} // namespace coff
-} // namespace lld
+}
+}
#endif