forked from OSchip/llvm-project
Shrink SectionChunk by combining Relocs and SectionName sizes
SectionChunk is one of the most frequently allocated data structures in LLD, since there are about four per function when optimizations and debug info are enabled (.text, .pdata, .xdata, .debug$S). A PE COFF file cannot be larger than 2GB, so there is an inherent limit on the length of the section name and the number of relocations. Decompose the ArrayRef and StringRef into pointer and size, and put them back together in the accessors for section name and relocation list. I plan to gather complete performance numbers later by padding SectionChunk with dead data and measuring performance after all the size optimizations are done. llvm-svn: 359923
This commit is contained in:
parent
a857e31011
commit
0a1b1d6e62
|
@ -30,11 +30,16 @@ namespace lld {
|
||||||
namespace coff {
|
namespace coff {
|
||||||
|
|
||||||
SectionChunk::SectionChunk(ObjFile *F, const coff_section *H)
|
SectionChunk::SectionChunk(ObjFile *F, const coff_section *H)
|
||||||
: Chunk(SectionKind), File(F), Header(H),
|
: Chunk(SectionKind), File(F), Header(H), Repl(this) {
|
||||||
Relocs(File->getCOFFObj()->getRelocations(Header)), Repl(this) {
|
// Initialize Relocs.
|
||||||
|
setRelocs(File->getCOFFObj()->getRelocations(Header));
|
||||||
|
|
||||||
// Initialize SectionName.
|
// Initialize SectionName.
|
||||||
|
StringRef SectionName;
|
||||||
if (Expected<StringRef> E = File->getCOFFObj()->getSectionName(Header))
|
if (Expected<StringRef> E = File->getCOFFObj()->getSectionName(Header))
|
||||||
SectionName = *E;
|
SectionName = *E;
|
||||||
|
SectionNameData = SectionName.data();
|
||||||
|
SectionNameSize = SectionName.size();
|
||||||
|
|
||||||
Alignment = Header->getAlignment();
|
Alignment = Header->getAlignment();
|
||||||
|
|
||||||
|
@ -48,7 +53,7 @@ SectionChunk::SectionChunk(ObjFile *F, const coff_section *H)
|
||||||
// SectionChunk is one of the most frequently allocated classes, so it is
|
// SectionChunk is one of the most frequently allocated classes, so it is
|
||||||
// important to keep it as compact as possible. As of this writing, the number
|
// important to keep it as compact as possible. As of this writing, the number
|
||||||
// below is the size of this class on x64 platforms.
|
// below is the size of this class on x64 platforms.
|
||||||
static_assert(sizeof(SectionChunk) <= 128, "SectionChunk grew unexpectedly");
|
static_assert(sizeof(SectionChunk) <= 120, "SectionChunk grew unexpectedly");
|
||||||
|
|
||||||
static void add16(uint8_t *P, int16_t V) { write16le(P, read16le(P) + V); }
|
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 add32(uint8_t *P, int32_t V) { write32le(P, read32le(P) + V); }
|
||||||
|
@ -343,8 +348,8 @@ void SectionChunk::writeTo(uint8_t *Buf) const {
|
||||||
|
|
||||||
// Apply relocations.
|
// Apply relocations.
|
||||||
size_t InputSize = getSize();
|
size_t InputSize = getSize();
|
||||||
for (size_t I = 0, E = Relocs.size(); I < E; I++) {
|
for (size_t I = 0, E = RelocsSize; I < E; I++) {
|
||||||
const coff_relocation &Rel = Relocs[I];
|
const coff_relocation &Rel = RelocsData[I];
|
||||||
|
|
||||||
// Check for an invalid relocation offset. This check isn't perfect, because
|
// Check for an invalid relocation offset. This check isn't perfect, because
|
||||||
// we don't have the relocation size, which is only known after checking the
|
// we don't have the relocation size, which is only known after checking the
|
||||||
|
@ -437,8 +442,8 @@ static uint8_t getBaserelType(const coff_relocation &Rel) {
|
||||||
// fixed by the loader if load-time relocation is needed.
|
// fixed by the loader if load-time relocation is needed.
|
||||||
// Only called when base relocation is enabled.
|
// Only called when base relocation is enabled.
|
||||||
void SectionChunk::getBaserels(std::vector<Baserel> *Res) {
|
void SectionChunk::getBaserels(std::vector<Baserel> *Res) {
|
||||||
for (size_t I = 0, E = Relocs.size(); I < E; I++) {
|
for (size_t I = 0, E = RelocsSize; I < E; I++) {
|
||||||
const coff_relocation &Rel = Relocs[I];
|
const coff_relocation &Rel = RelocsData[I];
|
||||||
uint8_t Ty = getBaserelType(Rel);
|
uint8_t Ty = getBaserelType(Rel);
|
||||||
if (Ty == IMAGE_REL_BASED_ABSOLUTE)
|
if (Ty == IMAGE_REL_BASED_ABSOLUTE)
|
||||||
continue;
|
continue;
|
||||||
|
@ -534,7 +539,7 @@ static int getRuntimePseudoRelocSize(uint16_t Type) {
|
||||||
// imported from another DLL).
|
// imported from another DLL).
|
||||||
void SectionChunk::getRuntimePseudoRelocs(
|
void SectionChunk::getRuntimePseudoRelocs(
|
||||||
std::vector<RuntimePseudoReloc> &Res) {
|
std::vector<RuntimePseudoReloc> &Res) {
|
||||||
for (const coff_relocation &Rel : Relocs) {
|
for (const coff_relocation &Rel : getRelocs()) {
|
||||||
auto *Target =
|
auto *Target =
|
||||||
dyn_cast_or_null<Defined>(File->getSymbol(Rel.SymbolTableIndex));
|
dyn_cast_or_null<Defined>(File->getSymbol(Rel.SymbolTableIndex));
|
||||||
if (!Target || !Target->IsRuntimePseudoReloc)
|
if (!Target || !Target->IsRuntimePseudoReloc)
|
||||||
|
@ -587,7 +592,7 @@ ArrayRef<uint8_t> SectionChunk::getContents() const {
|
||||||
|
|
||||||
ArrayRef<uint8_t> SectionChunk::consumeDebugMagic() {
|
ArrayRef<uint8_t> SectionChunk::consumeDebugMagic() {
|
||||||
assert(isCodeView());
|
assert(isCodeView());
|
||||||
return consumeDebugMagic(getContents(), SectionName);
|
return consumeDebugMagic(getContents(), getSectionName());
|
||||||
}
|
}
|
||||||
|
|
||||||
ArrayRef<uint8_t> SectionChunk::consumeDebugMagic(ArrayRef<uint8_t> Data,
|
ArrayRef<uint8_t> SectionChunk::consumeDebugMagic(ArrayRef<uint8_t> Data,
|
||||||
|
|
|
@ -153,7 +153,9 @@ public:
|
||||||
void writeTo(uint8_t *Buf) const override;
|
void writeTo(uint8_t *Buf) const override;
|
||||||
bool hasData() const override;
|
bool hasData() const override;
|
||||||
uint32_t getOutputCharacteristics() const override;
|
uint32_t getOutputCharacteristics() const override;
|
||||||
StringRef getSectionName() const override { return SectionName; }
|
StringRef getSectionName() const override {
|
||||||
|
return StringRef(SectionNameData, SectionNameSize);
|
||||||
|
}
|
||||||
void getBaserels(std::vector<Baserel> *Res) override;
|
void getBaserels(std::vector<Baserel> *Res) override;
|
||||||
bool isCOMDAT() const;
|
bool isCOMDAT() const;
|
||||||
void applyRelX64(uint8_t *Off, uint16_t Type, OutputSection *OS, uint64_t S,
|
void applyRelX64(uint8_t *Off, uint16_t Type, OutputSection *OS, uint64_t S,
|
||||||
|
@ -180,18 +182,29 @@ public:
|
||||||
// True if this is a codeview debug info chunk. These will not be laid out in
|
// True if this is a codeview debug info chunk. These will not be laid out in
|
||||||
// the image. Instead they will end up in the PDB, if one is requested.
|
// the image. Instead they will end up in the PDB, if one is requested.
|
||||||
bool isCodeView() const {
|
bool isCodeView() const {
|
||||||
return SectionName == ".debug" || SectionName.startswith(".debug$");
|
return getSectionName() == ".debug" || getSectionName().startswith(".debug$");
|
||||||
}
|
}
|
||||||
|
|
||||||
// True if this is a DWARF debug info or exception handling chunk.
|
// True if this is a DWARF debug info or exception handling chunk.
|
||||||
bool isDWARF() const {
|
bool isDWARF() const {
|
||||||
return SectionName.startswith(".debug_") || SectionName == ".eh_frame";
|
return getSectionName().startswith(".debug_") || getSectionName() == ".eh_frame";
|
||||||
}
|
}
|
||||||
|
|
||||||
// Allow iteration over the bodies of this chunk's relocated symbols.
|
// Allow iteration over the bodies of this chunk's relocated symbols.
|
||||||
llvm::iterator_range<symbol_iterator> symbols() const {
|
llvm::iterator_range<symbol_iterator> symbols() const {
|
||||||
return llvm::make_range(symbol_iterator(File, Relocs.begin()),
|
return llvm::make_range(symbol_iterator(File, RelocsData),
|
||||||
symbol_iterator(File, Relocs.end()));
|
symbol_iterator(File, RelocsData + RelocsSize));
|
||||||
|
}
|
||||||
|
|
||||||
|
ArrayRef<coff_relocation> getRelocs() const {
|
||||||
|
return llvm::makeArrayRef(RelocsData, RelocsSize);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Reloc setter used by ARM range extension thunk insertion.
|
||||||
|
void setRelocs(ArrayRef<coff_relocation> NewRelocs) {
|
||||||
|
RelocsData = NewRelocs.data();
|
||||||
|
RelocsSize = NewRelocs.size();
|
||||||
|
assert(RelocsSize == NewRelocs.size() && "reloc size truncation");
|
||||||
}
|
}
|
||||||
|
|
||||||
// Single linked list iterator for associated comdat children.
|
// Single linked list iterator for associated comdat children.
|
||||||
|
@ -245,9 +258,6 @@ public:
|
||||||
// The COMDAT leader symbol if this is a COMDAT chunk.
|
// The COMDAT leader symbol if this is a COMDAT chunk.
|
||||||
DefinedRegular *Sym = nullptr;
|
DefinedRegular *Sym = nullptr;
|
||||||
|
|
||||||
// Relocations for this section.
|
|
||||||
ArrayRef<coff_relocation> Relocs;
|
|
||||||
|
|
||||||
// The CRC of the contents as described in the COFF spec 4.5.5.
|
// The CRC of the contents as described in the COFF spec 4.5.5.
|
||||||
// Auxiliary Format 5: Section Definitions. Used for ICF.
|
// Auxiliary Format 5: Section Definitions. Used for ICF.
|
||||||
uint32_t Checksum = 0;
|
uint32_t Checksum = 0;
|
||||||
|
@ -265,12 +275,20 @@ public:
|
||||||
SectionChunk *Repl;
|
SectionChunk *Repl;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
StringRef SectionName;
|
|
||||||
SectionChunk *AssocChildren = nullptr;
|
SectionChunk *AssocChildren = nullptr;
|
||||||
|
|
||||||
// Used for ICF (Identical COMDAT Folding)
|
// Used for ICF (Identical COMDAT Folding)
|
||||||
void replace(SectionChunk *Other);
|
void replace(SectionChunk *Other);
|
||||||
uint32_t Class[2] = {0, 0};
|
uint32_t Class[2] = {0, 0};
|
||||||
|
|
||||||
|
// Relocations for this section. Size is stored below.
|
||||||
|
const coff_relocation *RelocsData;
|
||||||
|
|
||||||
|
// Section name string. Size is stored below.
|
||||||
|
const char *SectionNameData;
|
||||||
|
|
||||||
|
uint32_t RelocsSize = 0;
|
||||||
|
uint32_t SectionNameSize = 0;
|
||||||
};
|
};
|
||||||
|
|
||||||
// This class is used to implement an lld-specific feature (not implemented in
|
// This class is used to implement an lld-specific feature (not implemented in
|
||||||
|
|
|
@ -130,8 +130,8 @@ bool ICF::assocEquals(const SectionChunk *A, const SectionChunk *B) {
|
||||||
auto ChildClasses = [&](const SectionChunk *SC) {
|
auto ChildClasses = [&](const SectionChunk *SC) {
|
||||||
std::vector<uint32_t> Classes;
|
std::vector<uint32_t> Classes;
|
||||||
for (const SectionChunk &C : SC->children())
|
for (const SectionChunk &C : SC->children())
|
||||||
if (!C.SectionName.startswith(".debug") &&
|
if (!C.getSectionName().startswith(".debug") &&
|
||||||
C.SectionName != ".gfids$y" && C.SectionName != ".gljmp$y")
|
C.getSectionName() != ".gfids$y" && C.getSectionName() != ".gljmp$y")
|
||||||
Classes.push_back(C.Class[Cnt % 2]);
|
Classes.push_back(C.Class[Cnt % 2]);
|
||||||
return Classes;
|
return Classes;
|
||||||
};
|
};
|
||||||
|
@ -141,7 +141,7 @@ bool ICF::assocEquals(const SectionChunk *A, const SectionChunk *B) {
|
||||||
// Compare "non-moving" part of two sections, namely everything
|
// Compare "non-moving" part of two sections, namely everything
|
||||||
// except relocation targets.
|
// except relocation targets.
|
||||||
bool ICF::equalsConstant(const SectionChunk *A, const SectionChunk *B) {
|
bool ICF::equalsConstant(const SectionChunk *A, const SectionChunk *B) {
|
||||||
if (A->Relocs.size() != B->Relocs.size())
|
if (A->RelocsSize != B->RelocsSize)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
// Compare relocations.
|
// Compare relocations.
|
||||||
|
@ -160,12 +160,13 @@ bool ICF::equalsConstant(const SectionChunk *A, const SectionChunk *B) {
|
||||||
D1->getChunk()->Class[Cnt % 2] == D2->getChunk()->Class[Cnt % 2];
|
D1->getChunk()->Class[Cnt % 2] == D2->getChunk()->Class[Cnt % 2];
|
||||||
return false;
|
return false;
|
||||||
};
|
};
|
||||||
if (!std::equal(A->Relocs.begin(), A->Relocs.end(), B->Relocs.begin(), Eq))
|
if (!std::equal(A->getRelocs().begin(), A->getRelocs().end(),
|
||||||
|
B->getRelocs().begin(), Eq))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
// Compare section attributes and contents.
|
// Compare section attributes and contents.
|
||||||
return A->getOutputCharacteristics() == B->getOutputCharacteristics() &&
|
return A->getOutputCharacteristics() == B->getOutputCharacteristics() &&
|
||||||
A->SectionName == B->SectionName &&
|
A->getSectionName() == B->getSectionName() &&
|
||||||
A->Header->SizeOfRawData == B->Header->SizeOfRawData &&
|
A->Header->SizeOfRawData == B->Header->SizeOfRawData &&
|
||||||
A->Checksum == B->Checksum && A->getContents() == B->getContents() &&
|
A->Checksum == B->Checksum && A->getContents() == B->getContents() &&
|
||||||
assocEquals(A, B);
|
assocEquals(A, B);
|
||||||
|
@ -184,8 +185,8 @@ bool ICF::equalsVariable(const SectionChunk *A, const SectionChunk *B) {
|
||||||
return D1->getChunk()->Class[Cnt % 2] == D2->getChunk()->Class[Cnt % 2];
|
return D1->getChunk()->Class[Cnt % 2] == D2->getChunk()->Class[Cnt % 2];
|
||||||
return false;
|
return false;
|
||||||
};
|
};
|
||||||
return std::equal(A->Relocs.begin(), A->Relocs.end(), B->Relocs.begin(),
|
return std::equal(A->getRelocs().begin(), A->getRelocs().end(),
|
||||||
Eq) &&
|
B->getRelocs().begin(), Eq) &&
|
||||||
assocEquals(A, B);
|
assocEquals(A, B);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1744,7 +1744,7 @@ static bool findLineTable(const SectionChunk *C, uint32_t Addr,
|
||||||
|
|
||||||
// Build a mapping of SECREL relocations in DbgC that refer to C.
|
// Build a mapping of SECREL relocations in DbgC that refer to C.
|
||||||
DenseMap<uint32_t, uint32_t> Secrels;
|
DenseMap<uint32_t, uint32_t> Secrels;
|
||||||
for (const coff_relocation &R : DbgC->Relocs) {
|
for (const coff_relocation &R : DbgC->getRelocs()) {
|
||||||
if (R.Type != SecrelReloc)
|
if (R.Type != SecrelReloc)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
|
|
|
@ -89,7 +89,7 @@ std::string getSymbolLocations(ObjFile *File, uint32_t SymIndex) {
|
||||||
auto *SC = dyn_cast<SectionChunk>(C);
|
auto *SC = dyn_cast<SectionChunk>(C);
|
||||||
if (!SC)
|
if (!SC)
|
||||||
continue;
|
continue;
|
||||||
for (const coff_relocation &R : SC->Relocs) {
|
for (const coff_relocation &R : SC->getRelocs()) {
|
||||||
if (R.SymbolTableIndex != SymIndex)
|
if (R.SymbolTableIndex != SymIndex)
|
||||||
continue;
|
continue;
|
||||||
std::pair<StringRef, uint32_t> FileLine =
|
std::pair<StringRef, uint32_t> FileLine =
|
||||||
|
@ -183,7 +183,7 @@ bool SymbolTable::handleMinGWAutomaticImport(Symbol *Sym, StringRef Name) {
|
||||||
dyn_cast_or_null<DefinedRegular>(find((".refptr." + Name).str()));
|
dyn_cast_or_null<DefinedRegular>(find((".refptr." + Name).str()));
|
||||||
if (Refptr && Refptr->getChunk()->getSize() == Config->Wordsize) {
|
if (Refptr && Refptr->getChunk()->getSize() == Config->Wordsize) {
|
||||||
SectionChunk *SC = dyn_cast_or_null<SectionChunk>(Refptr->getChunk());
|
SectionChunk *SC = dyn_cast_or_null<SectionChunk>(Refptr->getChunk());
|
||||||
if (SC && SC->Relocs.size() == 1 && *SC->symbols().begin() == Sym) {
|
if (SC && SC->getRelocs().size() == 1 && *SC->symbols().begin() == Sym) {
|
||||||
log("Replacing .refptr." + Name + " with " + Imp->getName());
|
log("Replacing .refptr." + Name + " with " + Imp->getName());
|
||||||
Refptr->getChunk()->Live = false;
|
Refptr->getChunk()->Live = false;
|
||||||
Refptr->replaceKeepingName(Imp, ImpSize);
|
Refptr->replaceKeepingName(Imp, ImpSize);
|
||||||
|
|
|
@ -467,14 +467,15 @@ static bool createThunks(OutputSection *OS, int Margin) {
|
||||||
// modified. If the relocations point into the object file, allocate new
|
// modified. If the relocations point into the object file, allocate new
|
||||||
// memory. Otherwise, this must be previously allocated memory that can be
|
// memory. Otherwise, this must be previously allocated memory that can be
|
||||||
// modified in place.
|
// modified in place.
|
||||||
|
ArrayRef<coff_relocation> CurRelocs = SC->getRelocs();
|
||||||
MutableArrayRef<coff_relocation> NewRelocs;
|
MutableArrayRef<coff_relocation> NewRelocs;
|
||||||
if (OriginalRelocs.data() == SC->Relocs.data()) {
|
if (OriginalRelocs.data() == CurRelocs.data()) {
|
||||||
NewRelocs = makeMutableArrayRef(
|
NewRelocs = makeMutableArrayRef(
|
||||||
BAlloc.Allocate<coff_relocation>(OriginalRelocs.size()),
|
BAlloc.Allocate<coff_relocation>(OriginalRelocs.size()),
|
||||||
OriginalRelocs.size());
|
OriginalRelocs.size());
|
||||||
} else {
|
} else {
|
||||||
NewRelocs = makeMutableArrayRef(
|
NewRelocs = makeMutableArrayRef(
|
||||||
const_cast<coff_relocation *>(SC->Relocs.data()), SC->Relocs.size());
|
const_cast<coff_relocation *>(CurRelocs.data()), CurRelocs.size());
|
||||||
}
|
}
|
||||||
|
|
||||||
// Copy each relocation, but replace the symbol table indices which need
|
// Copy each relocation, but replace the symbol table indices which need
|
||||||
|
@ -489,7 +490,7 @@ static bool createThunks(OutputSection *OS, int Margin) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
SC->Relocs = makeArrayRef(NewRelocs.data(), NewRelocs.size());
|
SC->setRelocs(NewRelocs);
|
||||||
}
|
}
|
||||||
return AddressesChanged;
|
return AddressesChanged;
|
||||||
}
|
}
|
||||||
|
@ -501,8 +502,9 @@ static bool verifyRanges(const std::vector<Chunk *> Chunks) {
|
||||||
if (!SC)
|
if (!SC)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
for (size_t J = 0, E = SC->Relocs.size(); J < E; ++J) {
|
ArrayRef<coff_relocation> Relocs = SC->getRelocs();
|
||||||
const coff_relocation &Rel = SC->Relocs[J];
|
for (size_t J = 0, E = Relocs.size(); J < E; ++J) {
|
||||||
|
const coff_relocation &Rel = Relocs[J];
|
||||||
Symbol *RelocTarget = SC->File->getSymbol(Rel.SymbolTableIndex);
|
Symbol *RelocTarget = SC->File->getSymbol(Rel.SymbolTableIndex);
|
||||||
|
|
||||||
Defined *Sym = dyn_cast_or_null<Defined>(RelocTarget);
|
Defined *Sym = dyn_cast_or_null<Defined>(RelocTarget);
|
||||||
|
@ -1476,7 +1478,7 @@ static void markSymbolsWithRelocations(ObjFile *File,
|
||||||
if (!SC || !SC->Live)
|
if (!SC || !SC->Live)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
for (const coff_relocation &Reloc : SC->Relocs) {
|
for (const coff_relocation &Reloc : SC->getRelocs()) {
|
||||||
if (Config->Machine == I386 && Reloc.Type == COFF::IMAGE_REL_I386_REL32)
|
if (Config->Machine == I386 && Reloc.Type == COFF::IMAGE_REL_I386_REL32)
|
||||||
// Ignore relative relocations on x86. On x86_64 they can't be ignored
|
// Ignore relative relocations on x86. On x86_64 they can't be ignored
|
||||||
// since they're also used to compute absolute addresses.
|
// since they're also used to compute absolute addresses.
|
||||||
|
|
Loading…
Reference in New Issue