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); }
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
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);
// 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() {}
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;
// 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;
void locateImportTables();
void createExportTable();
void mergeSections();
- void readRelocTargets();
void removeUnusedSections();
void assignAddresses();
void finalizeAddresses();
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.
// 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
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;
}
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)
// 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;
}
appendImportThunks();
createExportTable();
mergeSections();
- readRelocTargets();
removeUnusedSections();
finalizeAddresses();
removeEmptySections();
}
}
-// 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() {