From 685c41cd39b69f3d83d90ebc5e4aa4bd02382878 Mon Sep 17 00:00:00 2001 From: Rui Ueyama Date: Wed, 5 Aug 2015 23:43:53 +0000 Subject: [PATCH] COFF: Simplify Writer interface by hiding Writer class. llvm-svn: 244175 --- lld/COFF/Driver.cpp | 4 +- lld/COFF/Writer.cpp | 209 ++++++++++++++++++++++++++++++++++++++++------------ lld/COFF/Writer.h | 114 ++-------------------------- 3 files changed, 170 insertions(+), 157 deletions(-) diff --git a/lld/COFF/Driver.cpp b/lld/COFF/Driver.cpp index 2254532..fc5d040 100644 --- a/lld/COFF/Driver.cpp +++ b/lld/COFF/Driver.cpp @@ -12,6 +12,7 @@ #include "Error.h" #include "InputFiles.h" #include "SymbolTable.h" +#include "Symbols.h" #include "Writer.h" #include "llvm/ADT/Optional.h" #include "llvm/ADT/STLExtras.h" @@ -725,8 +726,7 @@ bool LinkerDriver::link(llvm::ArrayRef ArgsArr) { touchFile(Arg->getValue()); // Write the result. - Writer Out(&Symtab); - if (auto EC = Out.write(Config->OutputFile)) { + if (auto EC = writeResult(&Symtab, Config->OutputFile)) { llvm::errs() << EC.message() << "\n"; return false; } diff --git a/lld/COFF/Writer.cpp b/lld/COFF/Writer.cpp index 24e1f7c..0d34587 100644 --- a/lld/COFF/Writer.cpp +++ b/lld/COFF/Writer.cpp @@ -8,6 +8,10 @@ //===----------------------------------------------------------------------===// #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" @@ -20,6 +24,7 @@ #include #include #include +#include #include using namespace llvm; @@ -27,6 +32,8 @@ using namespace llvm::COFF; 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; @@ -34,35 +41,115 @@ static const int SectionAlignment = 4096; 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 void writeHeader(); + void fixSafeSEHSymbols(); + void writeSections(); + void sortExceptionTable(); + void applyRelocations(); + + llvm::Optional 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 &V); + + uint32_t getSizeOfInitializedData(); + std::map> binImports(); + + SymbolTable *Symtab; + StringRef OutputPath; + std::unique_ptr Buffer; + llvm::SpecificBumpPtrAllocator CAlloc; + llvm::SpecificBumpPtrAllocator BAlloc; + std::vector OutputSections; + std::vector Strtab; + std::vector OutputSymtab; + IdataContents Idata; + DelayLoadContents DelayIdata; + EdataContents Edata; + std::unique_ptr SEHTable; + + bool Is64; + uint64_t FileSize; + uint32_t PointerToSymbolTable = 0; + uint64_t SizeOfImage; + uint64_t SizeOfHeaders; + + std::vector> 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(); - } else { - writeHeader(); - } - 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 &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 Chunks; +}; + void OutputSection::setRVA(uint64_t RVA) { Header.VirtualAddress = RVA; for (Chunk *C : Chunks) @@ -111,6 +198,54 @@ void OutputSection::writeHeaderTo(uint8_t *Buf) { } } +uint64_t Defined::getSecrel() { + if (auto *D = dyn_cast(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(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(this)) + return D->getChunk()->getOutputSection()->getPermissions() & X; + return isa(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(); + } else { + writeHeader(); + } + 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. @@ -220,7 +355,7 @@ void Writer::createMiscChunks() { if (Config->Machine != I386) return; std::set Handlers; - for (ObjectFile *File : Symtab->ObjectFiles) { + for (lld::coff::ObjectFile *File : Symtab->ObjectFiles) { if (!File->SEHCompat) return; for (SymbolBody *B : File->SEHandlers) @@ -361,7 +496,7 @@ void Writer::createSymbolAndStringTable() { 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(B)) if (Optional Sym = createSymbol(D)) @@ -681,25 +816,3 @@ void Writer::addBaserelBlocks(OutputSection *Dest, std::vector &V) { BaserelChunk *Buf = BAlloc.Allocate(); Dest->addChunk(new (Buf) BaserelChunk(Page, &V[I], &V[0] + J)); } - -uint64_t Defined::getSecrel() { - if (auto *D = dyn_cast(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(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(this)) - return D->getChunk()->getOutputSection()->getPermissions() & X; - return isa(this); -} - -} // namespace coff -} // namespace lld diff --git a/lld/COFF/Writer.h b/lld/COFF/Writer.h index f5f4f12..37caae8 100644 --- a/lld/COFF/Writer.h +++ b/lld/COFF/Writer.h @@ -10,120 +10,20 @@ #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 #include namespace lld { namespace coff { -// Implemented in ICF.cpp. -void doICF(const std::vector &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 &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 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 void writeHeader(); - void fixSafeSEHSymbols(); - void writeSections(); - void sortExceptionTable(); - void applyRelocations(); - - llvm::Optional 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 &V); - - uint32_t getSizeOfInitializedData(); - std::map> binImports(); - - SymbolTable *Symtab; - std::unique_ptr Buffer; - llvm::SpecificBumpPtrAllocator CAlloc; - llvm::SpecificBumpPtrAllocator BAlloc; - std::vector OutputSections; - std::vector Strtab; - std::vector OutputSymtab; - IdataContents Idata; - DelayLoadContents DelayIdata; - EdataContents Edata; - std::unique_ptr SEHTable; - - bool Is64; - uint64_t FileSize; - uint32_t PointerToSymbolTable = 0; - uint64_t SizeOfImage; - uint64_t SizeOfHeaders; - - std::vector> Chunks; -}; +// Implemented in ICF.cpp. +void doICF(const std::vector &Chunks); -} // namespace coff -} // namespace lld +} +} #endif -- 2.7.4