diff --git a/lld/COFF/Chunks.h b/lld/COFF/Chunks.h --- a/lld/COFF/Chunks.h +++ b/lld/COFF/Chunks.h @@ -63,13 +63,6 @@ // 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() {} @@ -155,8 +148,6 @@ 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; @@ -257,10 +248,6 @@ // Relocations for this section. ArrayRef Relocs; - // 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; - // The CRC of the contents as described in the COFF spec 4.5.5. // Auxiliary Format 5: Section Definitions. Used for ICF. uint32_t Checksum = 0; diff --git a/lld/COFF/Chunks.cpp b/lld/COFF/Chunks.cpp --- a/lld/COFF/Chunks.cpp +++ b/lld/COFF/Chunks.cpp @@ -47,23 +47,7 @@ // SectionChunk is one of the most frequently allocated classes, so it is // important to keep it as compact as possible. 168 happens to be the size of // the class on x64 as of this writing. -static_assert(sizeof(SectionChunk) <= 152, "SectionChunk grew unexpectedly"); - -// 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_assert(sizeof(SectionChunk) <= 128, "SectionChunk grew unexpectedly"); 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); } @@ -372,9 +356,8 @@ 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 @@ -458,9 +441,7 @@ 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/InputFiles.h b/lld/COFF/InputFiles.h --- a/lld/COFF/InputFiles.h +++ b/lld/COFF/InputFiles.h @@ -127,6 +127,13 @@ // 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 --- a/lld/COFF/PDB.cpp +++ b/lld/COFF/PDB.cpp @@ -1082,7 +1082,6 @@ 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 --- a/lld/COFF/Writer.cpp +++ b/lld/COFF/Writer.cpp @@ -198,7 +198,6 @@ void locateImportTables(); void createExportTable(); void mergeSections(); - void readRelocTargets(); void removeUnusedSections(); void assignAddresses(); void finalizeAddresses(); @@ -402,6 +401,7 @@ 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 @@ // 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 @@ ThunkInsertionRVA += ThunkChunk->getSize(); AddressesChanged = true; } - RelocTarget = Thunk; + + // To redirect the relocation, we add a fake symbol to the parent object + // file. Only add each thunk once to each input file. + 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}); + } + + // Create a modified relocation table with replacement symbol table indices + // for thunks. + MutableArrayRef NewRelocs; + if (OriginalRelocs.data() == SC->Relocs.data()) { + // If this is the first thunk creation pass, allocate new memory and copy + // the relocations. + NewRelocs = makeMutableArrayRef( + BAlloc.Allocate(OriginalRelocs.size()), + OriginalRelocs.size()); + } else { + // If not, simply modify the previously copied relocations in place. + 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 @@ 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 @@ // 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 @@ appendImportThunks(); createExportTable(); mergeSections(); - readRelocTargets(); removeUnusedSections(); finalizeAddresses(); removeEmptySections(); @@ -1094,12 +1130,6 @@ } } -// 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() {