diff options
-rw-r--r-- | lld/COFF/Chunks.cpp | 25 | ||||
-rw-r--r-- | lld/COFF/Chunks.h | 13 | ||||
-rw-r--r-- | lld/COFF/InputFiles.h | 7 | ||||
-rw-r--r-- | lld/COFF/PDB.cpp | 1 | ||||
-rw-r--r-- | lld/COFF/Writer.cpp | 64 |
5 files changed, 57 insertions, 53 deletions
diff --git a/lld/COFF/Chunks.cpp b/lld/COFF/Chunks.cpp index 4f12ecb3d87..81994146699 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<Defined>(RelocTargets[I]); + auto *Sym = + dyn_cast_or_null<Defined>(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<Baserel> *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<DefinedAbsolute>(Target)) continue; Res->emplace_back(RVA + Rel.VirtualAddress, Ty); diff --git a/lld/COFF/Chunks.h b/lld/COFF/Chunks.h index 8939853ba0d..9cc1f32e677 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<uint8_t> 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<Symbol *> RelocTargets; - private: StringRef SectionName; std::vector<SectionChunk *> AssocChildren; diff --git a/lld/COFF/InputFiles.h b/lld/COFF/InputFiles.h index 45ab4b3ebe9..ddffa7cf463 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<ObjFile *> 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 9ef43c79202..bf1438e7407 100644 --- a/lld/COFF/PDB.cpp +++ b/lld/COFF/PDB.cpp @@ -1082,7 +1082,6 @@ static ArrayRef<uint8_t> relocateDebugChunk(BumpPtrAllocator &Alloc, uint8_t *Buffer = Alloc.Allocate<uint8_t>(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 678dd66bfa6..07190aff287 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<uint64_t, Defined *> &LastThunks, Defined *Target, uint64_t P, 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. @@ -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<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 @@ -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<coff_relocation> NewRelocs; + if (OriginalRelocs.data() == SC->Relocs.data()) { + NewRelocs = makeMutableArrayRef( + BAlloc.Allocate<coff_relocation>(OriginalRelocs.size()), + OriginalRelocs.size()); + } else { + NewRelocs = makeMutableArrayRef( + const_cast<coff_relocation *>(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<Chunk *> 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<Defined>(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() { |