[lld] r329370 - COFF: Create output sections early. NFCI.
Peter Collingbourne via llvm-commits
llvm-commits at lists.llvm.org
Thu Apr 5 20:25:49 PDT 2018
Author: pcc
Date: Thu Apr 5 20:25:49 2018
New Revision: 329370
URL: http://llvm.org/viewvc/llvm-project?rev=329370&view=rev
Log:
COFF: Create output sections early. NFCI.
With this, all output sections are created in one place. This will make
it simpler to implement merging of builtin sections.
Differential Revision: https://reviews.llvm.org/D45349
Modified:
lld/trunk/COFF/Writer.cpp
Modified: lld/trunk/COFF/Writer.cpp
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/COFF/Writer.cpp?rev=329370&r1=329369&r2=329370&view=diff
==============================================================================
--- lld/trunk/COFF/Writer.cpp (original)
+++ lld/trunk/COFF/Writer.cpp Thu Apr 5 20:25:49 2018
@@ -163,14 +163,13 @@ private:
void createSymbolAndStringTable();
void openFile(StringRef OutputPath);
template <typename PEHeaderTy> void writeHeader();
- void createSEHTable(OutputSection *RData);
- void createGuardCFTables(OutputSection *RData);
- void createGLJmpTable(OutputSection *RData);
+ void createSEHTable();
+ void createGuardCFTables();
void markSymbolsForRVATable(ObjFile *File,
ArrayRef<SectionChunk *> SymIdxChunks,
SymbolRVASet &TableSymbols);
- void maybeAddRVATable(OutputSection *RData, SymbolRVASet TableSymbols,
- StringRef TableSym, StringRef CountSym);
+ void maybeAddRVATable(SymbolRVASet TableSymbols, StringRef TableSym,
+ StringRef CountSym);
void setSectionPermissions();
void writeSections();
void writeBuildId();
@@ -180,9 +179,8 @@ private:
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);
+ void addBaserels();
+ void addBaserelBlocks(std::vector<Baserel> &V);
uint32_t getSizeOfInitializedData();
std::map<StringRef, std::vector<DefinedImportData *>> binImports();
@@ -207,6 +205,16 @@ private:
uint32_t PointerToSymbolTable = 0;
uint64_t SizeOfImage;
uint64_t SizeOfHeaders;
+
+ OutputSection *TextSec;
+ OutputSection *RdataSec;
+ OutputSection *DataSec;
+ OutputSection *PdataSec;
+ OutputSection *IdataSec;
+ OutputSection *EdataSec;
+ OutputSection *DidatSec;
+ OutputSection *RsrcSec;
+ OutputSection *RelocSec;
};
} // anonymous namespace
@@ -318,8 +326,6 @@ void Writer::run() {
createMiscChunks();
createImportTables();
createExportTable();
- if (Config->Relocatable)
- createSection(".reloc");
assignAddresses();
removeEmptySections();
setSectionPermissions();
@@ -386,7 +392,37 @@ static void sortBySectionOrder(std::vect
// Create output section objects and add them to OutputSections.
void Writer::createSections() {
- // First, bin chunks by name.
+ // 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<StringRef, OutputSection *> Sections;
+ auto CreateSection = [&](StringRef Name, uint32_t Perms) {
+ auto Sec = make<OutputSection>(Name);
+ Sec->addPermissions(Perms);
+ OutputSections.push_back(Sec);
+ Sections[Name] = 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);
+ 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);
+
+ // Then bin chunks by name.
std::map<StringRef, std::vector<Chunk *>> Map;
for (Chunk *C : Symtab->getChunks()) {
auto *SC = dyn_cast<SectionChunk>(C);
@@ -407,7 +443,6 @@ void Writer::createSections() {
// '$' 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.
- SmallDenseMap<StringRef, OutputSection *> Sections;
for (auto Pair : Map) {
StringRef Name = getOutputSection(Pair.first);
OutputSection *&Sec = Sections[Name];
@@ -421,18 +456,38 @@ void Writer::createSections() {
Sec->addPermissions(C->getPermissions());
}
}
+
+ // Finally, move some output sections to the end.
+ auto SectionOrder = [&](OutputSection *S) {
+ // .reloc should come last of all since it refers to RVAs of data in the
+ // previous sections.
+ if (S == RelocSec)
+ return 3;
+ // Move DISCARDABLE (or non-memory-mapped) sections to the end of file because
+ // the loader cannot handle holes.
+ if (S->getPermissions() & 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)
+ return 1;
+ return 0;
+ };
+ std::stable_sort(OutputSections.begin(), OutputSections.end(),
+ [&](OutputSection *S, OutputSection *T) {
+ return SectionOrder(S) < SectionOrder(T);
+ });
}
void Writer::createMiscChunks() {
- OutputSection *RData = createSection(".rdata");
-
for (auto &P : MergeChunk::Instances)
- RData->addChunk(P.second);
+ RdataSec->addChunk(P.second);
// Create thunks for locally-dllimported symbols.
if (!Symtab->LocalImportChunks.empty()) {
for (Chunk *C : Symtab->LocalImportChunks)
- RData->addChunk(C);
+ RdataSec->addChunk(C);
}
// Create Debug Information Chunks
@@ -447,18 +502,18 @@ void Writer::createMiscChunks() {
BuildId = CVChunk;
DebugRecords.push_back(CVChunk);
- RData->addChunk(DebugDirectory);
+ RdataSec->addChunk(DebugDirectory);
for (Chunk *C : DebugRecords)
- RData->addChunk(C);
+ RdataSec->addChunk(C);
}
// Create SEH table. x86-only.
if (Config->Machine == I386)
- createSEHTable(RData);
+ createSEHTable();
// Create /guard:cf tables if requested.
if (Config->GuardCF != GuardCFLevel::Off)
- createGuardCFTables(RData);
+ createGuardCFTables();
}
// Create .idata section for the DLL-imported symbol table.
@@ -481,13 +536,12 @@ void Writer::createImportTables() {
Config->DLLOrder[DLL] = Config->DLLOrder.size();
}
- OutputSection *Text = createSection(".text");
for (ImportFile *File : ImportFile::Instances) {
if (!File->Live)
continue;
if (DefinedImportThunk *Thunk = File->ThunkSym)
- Text->addChunk(Thunk->getChunk());
+ TextSec->addChunk(Thunk->getChunk());
if (Config->DelayLoads.count(StringRef(File->DLLName).lower())) {
if (!File->ThunkSym)
@@ -499,33 +553,27 @@ void Writer::createImportTables() {
}
}
- if (!Idata.empty()) {
- OutputSection *Sec = createSection(".idata");
+ if (!Idata.empty())
for (Chunk *C : Idata.getChunks())
- Sec->addChunk(C);
- }
+ IdataSec->addChunk(C);
if (!DelayIdata.empty()) {
Defined *Helper = cast<Defined>(Config->DelayLoadHelper);
DelayIdata.create(Helper);
- OutputSection *Sec = createSection(".didat");
for (Chunk *C : DelayIdata.getChunks())
- Sec->addChunk(C);
- Sec = createSection(".data");
+ DidatSec->addChunk(C);
for (Chunk *C : DelayIdata.getDataChunks())
- Sec->addChunk(C);
- Sec = createSection(".text");
+ DataSec->addChunk(C);
for (Chunk *C : DelayIdata.getCodeChunks())
- Sec->addChunk(C);
+ TextSec->addChunk(C);
}
}
void Writer::createExportTable() {
if (Config->Exports.empty())
return;
- OutputSection *Sec = createSection(".edata");
for (Chunk *C : Edata.Chunks)
- Sec->addChunk(C);
+ EdataSec->addChunk(C);
}
// The Windows loader doesn't seem to like empty sections,
@@ -644,29 +692,6 @@ void Writer::createSymbolAndStringTable(
FileSize = alignTo(FileOff, SectorSize);
}
-static int sectionIndex(OutputSection *S) {
- // Move DISCARDABLE (or non-memory-mapped) sections to the end of file because
- // the loader cannot handle holes.
- if (S->getPermissions() & IMAGE_SCN_MEM_DISCARDABLE)
- return 101;
-
- // Try to match the section order used by link.exe. In particular, it's
- // important that .reloc comes last since it refers to RVA's of data in
- // the previous sections. .rsrc should come late because its size may
- // change by the Win32 UpdateResources() function, causing subsequent
- // sections to move (see https://crbug.com/827082).
- return StringSwitch<int>(S->Name)
- .Case(".text", 1)
- .Case(".bss", 2)
- .Case(".rdata", 3)
- .Case(".data", 4)
- .Case(".pdata", 5)
- .Case(".idata", 6)
- .Case(".rsrc", 99)
- .Case(".reloc", 100)
- .Default(50); // Default to somewhere in the middle.
-}
-
// Visits all sections to assign incremental, non-overlapping RVAs and
// file offsets.
void Writer::assignAddresses() {
@@ -679,15 +704,9 @@ void Writer::assignAddresses() {
uint64_t RVA = PageSize; // The first page is kept unmapped.
FileSize = SizeOfHeaders;
- // Reorder the sections.
- std::stable_sort(OutputSections.begin(), OutputSections.end(),
- [](OutputSection *S, OutputSection *T) {
- return sectionIndex(S) < sectionIndex(T);
- });
-
for (OutputSection *Sec : OutputSections) {
- if (Sec->Name == ".reloc")
- addBaserels(Sec);
+ if (Sec == RelocSec)
+ addBaserels();
uint64_t RawSize = 0, VirtualSize = 0;
Sec->Header.VirtualAddress = RVA;
for (Chunk *C : Sec->getChunks()) {
@@ -810,18 +829,18 @@ template <typename PEHeaderTy> void Writ
if (Config->TerminalServerAware)
PE->DLLCharacteristics |= IMAGE_DLL_CHARACTERISTICS_TERMINAL_SERVER_AWARE;
PE->NumberOfRvaAndSize = NumberfOfDataDirectory;
- if (OutputSection *Text = findSection(".text")) {
- PE->BaseOfCode = Text->getRVA();
- PE->SizeOfCode = Text->getRawSize();
+ 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) * NumberfOfDataDirectory;
- if (OutputSection *Sec = findSection(".edata")) {
- Dir[EXPORT_TABLE].RelativeVirtualAddress = Sec->getRVA();
- Dir[EXPORT_TABLE].Size = Sec->getVirtualSize();
+ if (EdataSec->getVirtualSize()) {
+ Dir[EXPORT_TABLE].RelativeVirtualAddress = EdataSec->getRVA();
+ Dir[EXPORT_TABLE].Size = EdataSec->getVirtualSize();
}
if (!Idata.empty()) {
Dir[IMPORT_TABLE].RelativeVirtualAddress = Idata.getDirRVA();
@@ -829,17 +848,17 @@ template <typename PEHeaderTy> void Writ
Dir[IAT].RelativeVirtualAddress = Idata.getIATRVA();
Dir[IAT].Size = Idata.getIATSize();
}
- if (OutputSection *Sec = findSection(".rsrc")) {
- Dir[RESOURCE_TABLE].RelativeVirtualAddress = Sec->getRVA();
- Dir[RESOURCE_TABLE].Size = Sec->getVirtualSize();
- }
- if (OutputSection *Sec = findSection(".pdata")) {
- Dir[EXCEPTION_TABLE].RelativeVirtualAddress = Sec->getRVA();
- Dir[EXCEPTION_TABLE].Size = Sec->getVirtualSize();
- }
- if (OutputSection *Sec = findSection(".reloc")) {
- Dir[BASE_RELOCATION_TABLE].RelativeVirtualAddress = Sec->getRVA();
- Dir[BASE_RELOCATION_TABLE].Size = Sec->getVirtualSize();
+ if (RsrcSec->getVirtualSize()) {
+ Dir[RESOURCE_TABLE].RelativeVirtualAddress = RsrcSec->getRVA();
+ Dir[RESOURCE_TABLE].Size = RsrcSec->getVirtualSize();
+ }
+ if (PdataSec->getVirtualSize()) {
+ Dir[EXCEPTION_TABLE].RelativeVirtualAddress = PdataSec->getRVA();
+ Dir[EXCEPTION_TABLE].Size = PdataSec->getVirtualSize();
+ }
+ 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)) {
@@ -908,7 +927,7 @@ void Writer::openFile(StringRef Path) {
"failed to open " + Path);
}
-void Writer::createSEHTable(OutputSection *RData) {
+void Writer::createSEHTable() {
SymbolRVASet Handlers;
for (ObjFile *File : ObjFile::Instances) {
// FIXME: We should error here instead of earlier unless /safeseh:no was
@@ -919,7 +938,7 @@ void Writer::createSEHTable(OutputSectio
markSymbolsForRVATable(File, File->getSXDataChunks(), Handlers);
}
- maybeAddRVATable(RData, std::move(Handlers), "__safe_se_handler_table",
+ maybeAddRVATable(std::move(Handlers), "__safe_se_handler_table",
"__safe_se_handler_count");
}
@@ -964,7 +983,7 @@ static void markSymbolsWithRelocations(O
// Create the guard function id table. This is a table of RVAs of all
// address-taken functions. It is sorted and uniqued, just like the safe SEH
// table.
-void Writer::createGuardCFTables(OutputSection *RData) {
+void Writer::createGuardCFTables() {
SymbolRVASet AddressTakenSyms;
SymbolRVASet LongJmpTargets;
for (ObjFile *File : ObjFile::Instances) {
@@ -985,12 +1004,12 @@ void Writer::createGuardCFTables(OutputS
if (Config->Entry)
addSymbolToRVASet(AddressTakenSyms, cast<Defined>(Config->Entry));
- maybeAddRVATable(RData, 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(RData, std::move(LongJmpTargets), "__guard_longjmp_table",
+ maybeAddRVATable(std::move(LongJmpTargets), "__guard_longjmp_table",
"__guard_longjmp_count");
// Set __guard_flags, which will be used in the load config to indicate that
@@ -1047,14 +1066,13 @@ void Writer::markSymbolsForRVATable(ObjF
// 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(OutputSection *RData,
- SymbolRVASet TableSymbols,
- StringRef TableSym, StringRef CountSym) {
+void Writer::maybeAddRVATable(SymbolRVASet TableSymbols, StringRef TableSym,
+ StringRef CountSym) {
if (TableSymbols.empty())
return;
RVATableChunk *TableChunk = make<RVATableChunk>(std::move(TableSymbols));
- RData->addChunk(TableChunk);
+ RdataSec->addChunk(TableChunk);
Symbol *T = Symtab->findUnderscore(TableSym);
Symbol *C = Symtab->findUnderscore(CountSym);
@@ -1141,12 +1159,11 @@ void Writer::writeBuildId() {
// Sort .pdata section contents according to PE/COFF spec 5.5.
void Writer::sortExceptionTable() {
- OutputSection *Sec = findSection(".pdata");
- if (!Sec)
+ if (PdataSec->getVirtualSize() == 0)
return;
// We assume .pdata contains function table entries only.
- uint8_t *Begin = Buffer->getBufferStart() + Sec->getFileOff();
- uint8_t *End = Begin + Sec->getVirtualSize();
+ uint8_t *Begin = Buffer->getBufferStart() + PdataSec->getFileOff();
+ uint8_t *End = Begin + PdataSec->getVirtualSize();
if (Config->Machine == AMD64) {
struct Entry { ulittle32_t Begin, End, Unwind; };
sort(parallel::par, (Entry *)Begin, (Entry *)End,
@@ -1177,50 +1194,26 @@ uint32_t Writer::getSizeOfInitializedDat
return Res;
}
-// Returns an existing section or create a new one if not found.
-OutputSection *Writer::createSection(StringRef Name) {
- if (auto *Sec = findSection(Name))
- return Sec;
- const auto DATA = IMAGE_SCN_CNT_INITIALIZED_DATA;
- const auto BSS = IMAGE_SCN_CNT_UNINITIALIZED_DATA;
- const auto CODE = IMAGE_SCN_CNT_CODE;
- const auto DISCARDABLE = IMAGE_SCN_MEM_DISCARDABLE;
- const auto R = IMAGE_SCN_MEM_READ;
- const auto W = IMAGE_SCN_MEM_WRITE;
- const auto X = IMAGE_SCN_MEM_EXECUTE;
- uint32_t Perms = StringSwitch<uint32_t>(Name)
- .Case(".bss", BSS | R | W)
- .Case(".data", DATA | R | W)
- .Cases(".didat", ".edata", ".idata", ".rdata", DATA | R)
- .Case(".reloc", DATA | DISCARDABLE | R)
- .Case(".text", CODE | R | X)
- .Default(0);
- if (!Perms)
- llvm_unreachable("unknown section name");
- auto Sec = make<OutputSection>(Name);
- Sec->addPermissions(Perms);
- OutputSections.push_back(Sec);
- return Sec;
-}
-
-// Dest is .reloc section. Add contents to that section.
-void Writer::addBaserels(OutputSection *Dest) {
+// Add base relocations to .reloc section.
+void Writer::addBaserels() {
+ if (!Config->Relocatable)
+ return;
std::vector<Baserel> V;
for (OutputSection *Sec : OutputSections) {
- if (Sec == Dest)
+ if (Sec == RelocSec)
continue;
// Collect all locations for base relocations.
for (Chunk *C : Sec->getChunks())
C->getBaserels(&V);
// Add the addresses to .reloc section.
if (!V.empty())
- addBaserelBlocks(Dest, V);
+ addBaserelBlocks(V);
V.clear();
}
}
// Add addresses to .reloc section. Note that addresses are grouped by page.
-void Writer::addBaserelBlocks(OutputSection *Dest, std::vector<Baserel> &V) {
+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;
@@ -1228,11 +1221,11 @@ void Writer::addBaserelBlocks(OutputSect
uint32_t P = V[J].RVA & Mask;
if (P == Page)
continue;
- Dest->addChunk(make<BaserelChunk>(Page, &V[I], &V[0] + J));
+ RelocSec->addChunk(make<BaserelChunk>(Page, &V[I], &V[0] + J));
I = J;
Page = P;
}
if (I == J)
return;
- Dest->addChunk(make<BaserelChunk>(Page, &V[I], &V[0] + J));
+ RelocSec->addChunk(make<BaserelChunk>(Page, &V[I], &V[0] + J));
}
More information about the llvm-commits
mailing list