Index: lld/trunk/COFF/Chunks.h =================================================================== --- lld/trunk/COFF/Chunks.h +++ lld/trunk/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() {} @@ -153,8 +146,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; @@ -243,10 +234,6 @@ // 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; Index: lld/trunk/COFF/Chunks.cpp =================================================================== --- lld/trunk/COFF/Chunks.cpp +++ lld/trunk/COFF/Chunks.cpp @@ -44,22 +44,6 @@ 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 @@ 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 @@ 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); Index: lld/trunk/COFF/InputFiles.h =================================================================== --- lld/trunk/COFF/InputFiles.h +++ lld/trunk/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 Index: lld/trunk/COFF/PDB.cpp =================================================================== --- lld/trunk/COFF/PDB.cpp +++ lld/trunk/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()); } Index: lld/trunk/COFF/Writer.cpp =================================================================== --- lld/trunk/COFF/Writer.cpp +++ lld/trunk/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, 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 @@ 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() {