From: Reid Kleckner Date: Thu, 28 Mar 2019 18:30:03 +0000 (+0000) Subject: [COFF] Optimize range extension thunk insertion memory usage X-Git-Tag: llvmorg-10-init~8956 X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=1600490af16e6be1f48fb3e52f3c9498cf87b15f;p=platform%2Fupstream%2Fllvm.git [COFF] Optimize range extension thunk insertion memory usage Summary: This avoids allocating O(#relocs) of intermediate data for each section when range extension thunks aren't needed for that section. This also removes a std::vector from SectionChunk, which further reduces its size. Instead, this change adds the range extension thunk symbols to the object files that contain sections that need extension thunks. By adding them to the symbol table of the parent object, that means they now have a symbol table index. Then we can then modify the original relocation, after copying it to read-write memory, to use the new symbol table index. This makes linking browser_tests.exe with no PDB 10.46% faster, moving it from 11.364s to 10.288s averaged over five runs. Reviewers: mstorsjo, ruiu Subscribers: aganea, llvm-commits Tags: #llvm Differential Revision: https://reviews.llvm.org/D59902 llvm-svn: 357200 --- diff --git a/lld/COFF/Chunks.cpp b/lld/COFF/Chunks.cpp index 4f12ecb..8199414 100644 --- a/lld/COFF/Chunks.cpp +++ b/lld/COFF/Chunks.cpp @@ -44,22 +44,6 @@ SectionChunk::SectionChunk(ObjFile *F, const coff_section *H) Live = !Config->DoGC || !isCOMDAT(); } -// Initialize the RelocTargets vector, to allow redirecting certain relocations -// to a thunk instead of the actual symbol the relocation's symbol table index -// indicates. -void SectionChunk::readRelocTargets() { - assert(RelocTargets.empty()); - RelocTargets.reserve(Relocs.size()); - for (const coff_relocation &Rel : Relocs) - RelocTargets.push_back(File->getSymbol(Rel.SymbolTableIndex)); -} - -// Reset RelocTargets to their original targets before thunks were added. -void SectionChunk::resetRelocTargets() { - for (size_t I = 0, E = Relocs.size(); I < E; ++I) - RelocTargets[I] = File->getSymbol(Relocs[I].SymbolTableIndex); -} - static void add16(uint8_t *P, int16_t V) { write16le(P, read16le(P) + V); } static void add32(uint8_t *P, int32_t V) { write32le(P, read32le(P) + V); } static void add64(uint8_t *P, int64_t V) { write64le(P, read64le(P) + V); } @@ -367,9 +351,8 @@ void SectionChunk::writeTo(uint8_t *Buf) const { uint8_t *Off = Buf + OutputSectionOff + Rel.VirtualAddress; - // Use the potentially remapped Symbol instead of the one that the - // relocation points to. - auto *Sym = dyn_cast_or_null(RelocTargets[I]); + auto *Sym = + dyn_cast_or_null(File->getSymbol(Rel.SymbolTableIndex)); // Get the output section of the symbol for this relocation. The output // section is needed to compute SECREL and SECTION relocations used in debug @@ -449,9 +432,7 @@ void SectionChunk::getBaserels(std::vector *Res) { uint8_t Ty = getBaserelType(Rel); if (Ty == IMAGE_REL_BASED_ABSOLUTE) continue; - // Use the potentially remapped Symbol instead of the one that the - // relocation points to. - Symbol *Target = RelocTargets[I]; + Symbol *Target = File->getSymbol(Rel.SymbolTableIndex); if (!Target || isa(Target)) continue; Res->emplace_back(RVA + Rel.VirtualAddress, Ty); diff --git a/lld/COFF/Chunks.h b/lld/COFF/Chunks.h index 8939853..9cc1f32e 100644 --- a/lld/COFF/Chunks.h +++ b/lld/COFF/Chunks.h @@ -63,13 +63,6 @@ public: // before calling this function. virtual void writeTo(uint8_t *Buf) const {} - // Called by the writer once before assigning addresses and writing - // the output. - virtual void readRelocTargets() {} - - // Called if restarting thunk addition. - virtual void resetRelocTargets() {} - // Called by the writer after an RVA is assigned, but before calling // getSize(). virtual void finalizeContents() {} @@ -153,8 +146,6 @@ public: SectionChunk(ObjFile *File, const coff_section *Header); static bool classof(const Chunk *C) { return C->kind() == SectionKind; } - void readRelocTargets() override; - void resetRelocTargets() override; size_t getSize() const override { return Header->SizeOfRawData; } ArrayRef getContents() const; void writeTo(uint8_t *Buf) const override; @@ -243,10 +234,6 @@ public: // Used by the garbage collector. bool Live; - // When inserting a thunk, we need to adjust a relocation to point to - // the thunk instead of the actual original target Symbol. - std::vector RelocTargets; - private: StringRef SectionName; std::vector AssocChildren; diff --git a/lld/COFF/InputFiles.h b/lld/COFF/InputFiles.h index 45ab4b3..ddffa7c 100644 --- a/lld/COFF/InputFiles.h +++ b/lld/COFF/InputFiles.h @@ -127,6 +127,13 @@ public: // Returns the underlying COFF file. COFFObjectFile *getCOFFObj() { return COFFObj.get(); } + // Add a symbol for a range extension thunk. Return the new symbol table + // index. This index can be used to modify a relocation. + uint32_t addRangeThunkSymbol(Symbol *Thunk) { + Symbols.push_back(Thunk); + return Symbols.size() - 1; + } + static std::vector Instances; // Flags in the absolute @feat.00 symbol if it is present. These usually diff --git a/lld/COFF/PDB.cpp b/lld/COFF/PDB.cpp index 9ef43c7..bf1438e 100644 --- a/lld/COFF/PDB.cpp +++ b/lld/COFF/PDB.cpp @@ -1082,7 +1082,6 @@ static ArrayRef relocateDebugChunk(BumpPtrAllocator &Alloc, uint8_t *Buffer = Alloc.Allocate(DebugChunk.getSize()); assert(DebugChunk.OutputSectionOff == 0 && "debug sections should not be in output sections"); - DebugChunk.readRelocTargets(); DebugChunk.writeTo(Buffer); return makeArrayRef(Buffer, DebugChunk.getSize()); } diff --git a/lld/COFF/Writer.cpp b/lld/COFF/Writer.cpp index 678dd66..07190af 100644 --- a/lld/COFF/Writer.cpp +++ b/lld/COFF/Writer.cpp @@ -198,7 +198,6 @@ private: void locateImportTables(); void createExportTable(); void mergeSections(); - void readRelocTargets(); void removeUnusedSections(); void assignAddresses(); void finalizeAddresses(); @@ -402,6 +401,7 @@ getThunk(DenseMap &LastThunks, Defined *Target, uint64_t P, static bool createThunks(OutputSection *OS, int Margin) { bool AddressesChanged = false; DenseMap LastThunks; + DenseMap, uint32_t> ThunkSymtabIndices; size_t ThunksSize = 0; // Recheck Chunks.size() each iteration, since we can insert more // elements into it. @@ -415,9 +415,13 @@ static bool createThunks(OutputSection *OS, int Margin) { // 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; - for (size_t J = 0, E = SC->Relocs.size(); J < E; ++J) { - const coff_relocation &Rel = SC->Relocs[J]; - Symbol *&RelocTarget = SC->RelocTargets[J]; + ObjFile *File = SC->File; + std::vector> RelocReplacements; + ArrayRef 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 @@ -450,8 +454,44 @@ static bool createThunks(OutputSection *OS, int Margin) { ThunkInsertionRVA += ThunkChunk->getSize(); AddressesChanged = true; } - RelocTarget = Thunk; + + // 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}); + } + + // 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. + MutableArrayRef NewRelocs; + if (OriginalRelocs.data() == SC->Relocs.data()) { + NewRelocs = makeMutableArrayRef( + BAlloc.Allocate(OriginalRelocs.size()), + OriginalRelocs.size()); + } else { + NewRelocs = makeMutableArrayRef( + const_cast(SC->Relocs.data()), SC->Relocs.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; + } } + + SC->Relocs = makeArrayRef(NewRelocs.data(), NewRelocs.size()); } return AddressesChanged; } @@ -465,7 +505,7 @@ static bool verifyRanges(const std::vector Chunks) { for (size_t J = 0, E = SC->Relocs.size(); J < E; ++J) { const coff_relocation &Rel = SC->Relocs[J]; - Symbol *RelocTarget = SC->RelocTargets[J]; + Symbol *RelocTarget = SC->File->getSymbol(Rel.SymbolTableIndex); Defined *Sym = dyn_cast_or_null(RelocTarget); if (!Sym) @@ -521,11 +561,8 @@ void Writer::finalizeAddresses() { // 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) { + for (OutputSection *Sec : OutputSections) Sec->Chunks = Sec->OrigChunks; - for (Chunk *C : Sec->Chunks) - C->resetRelocTargets(); - } Margin *= 2; } @@ -556,7 +593,6 @@ void Writer::run() { appendImportThunks(); createExportTable(); mergeSections(); - readRelocTargets(); removeUnusedSections(); finalizeAddresses(); removeEmptySections(); @@ -1094,12 +1130,6 @@ void Writer::mergeSections() { } } -// Visits all sections to initialize their relocation targets. -void Writer::readRelocTargets() { - for (OutputSection *Sec : OutputSections) - parallelForEach(Sec->Chunks, [&](Chunk *C) { C->readRelocTargets(); }); -} - // Visits all sections to assign incremental, non-overlapping RVAs and // file offsets. void Writer::assignAddresses() {