Replace SharedSymbols with Defined when creating copy relocations.

This is slightly simpler to read IMHO. Now if a symbol has a position
in the file, it is Defined.

The main motivation is that with this a SharedSymbol doesn't need a
section, which reduces the size of SymbolUnion.

With this the peak allocation when linking chromium goes from 568.1 to
564.2 MB.

llvm-svn: 330966
This commit is contained in:
Rafael Espindola 2018-04-26 17:58:58 +00:00
parent b09308d82a
commit ab0cce5f1f
9 changed files with 65 additions and 83 deletions

View File

@ -1111,8 +1111,8 @@ ExprValue LinkerScript::getSymbolValue(StringRef Name, const Twine &Loc) {
if (auto *DS = dyn_cast<Defined>(Sym)) if (auto *DS = dyn_cast<Defined>(Sym))
return {DS->Section, false, DS->Value, Loc}; return {DS->Section, false, DS->Value, Loc};
if (auto *SS = dyn_cast<SharedSymbol>(Sym)) if (auto *SS = dyn_cast<SharedSymbol>(Sym))
if (!ErrorOnMissingSection || SS->CopyRelSec) if (!ErrorOnMissingSection)
return {SS->CopyRelSec, false, 0, Loc}; return {nullptr, false, 0, Loc};
} }
error(Loc + ": symbol not found: " + Name); error(Loc + ": symbol not found: " + Name);

View File

@ -38,7 +38,7 @@ using namespace llvm::object;
using namespace lld; using namespace lld;
using namespace lld::elf; using namespace lld::elf;
typedef DenseMap<const SectionBase *, SmallVector<Symbol *, 4>> SymbolMapTy; typedef DenseMap<const SectionBase *, SmallVector<Defined *, 4>> SymbolMapTy;
static const std::string Indent8 = " "; // 8 spaces static const std::string Indent8 = " "; // 8 spaces
static const std::string Indent16 = " "; // 16 spaces static const std::string Indent16 = " "; // 16 spaces
@ -53,44 +53,29 @@ static void writeHeader(raw_ostream &OS, uint64_t VMA, uint64_t LMA,
} }
// Returns a list of all symbols that we want to print out. // Returns a list of all symbols that we want to print out.
static std::vector<Symbol *> getSymbols() { static std::vector<Defined *> getSymbols() {
std::vector<Symbol *> V; std::vector<Defined *> V;
for (InputFile *File : ObjectFiles) { for (InputFile *File : ObjectFiles)
for (Symbol *B : File->getSymbols()) { for (Symbol *B : File->getSymbols())
if (auto *SS = dyn_cast<SharedSymbol>(B))
if (SS->CopyRelSec || SS->NeedsPltAddr)
V.push_back(SS);
if (auto *DR = dyn_cast<Defined>(B)) if (auto *DR = dyn_cast<Defined>(B))
if (DR->File == File && !DR->isSection() && DR->Section && if (!DR->isSection() && DR->Section && DR->Section->Live &&
DR->Section->Live) (DR->File == File || DR->NeedsPltAddr || DR->Section->Bss))
V.push_back(DR); V.push_back(DR);
}
}
return V; return V;
} }
// Returns a map from sections to their symbols. // Returns a map from sections to their symbols.
static SymbolMapTy getSectionSyms(ArrayRef<Symbol *> Syms) { static SymbolMapTy getSectionSyms(ArrayRef<Defined *> Syms) {
SymbolMapTy Ret; SymbolMapTy Ret;
for (Symbol *S : Syms) { for (Defined *DR : Syms)
if (auto *DR = dyn_cast<Defined>(S)) { Ret[DR->Section].push_back(DR);
Ret[DR->Section].push_back(S);
continue;
}
SharedSymbol *SS = cast<SharedSymbol>(S);
if (SS->CopyRelSec)
Ret[SS->CopyRelSec].push_back(S);
else
Ret[InX::Plt].push_back(S);
}
// Sort symbols by address. We want to print out symbols in the // Sort symbols by address. We want to print out symbols in the
// order in the output file rather than the order they appeared // order in the output file rather than the order they appeared
// in the input files. // in the input files.
for (auto &It : Ret) { for (auto &It : Ret) {
SmallVectorImpl<Symbol *> &V = It.second; SmallVectorImpl<Defined *> &V = It.second;
std::stable_sort(V.begin(), V.end(), [](Symbol *A, Symbol *B) { std::stable_sort(V.begin(), V.end(), [](Defined *A, Defined *B) {
return A->getVA() < B->getVA(); return A->getVA() < B->getVA();
}); });
} }
@ -101,7 +86,7 @@ static SymbolMapTy getSectionSyms(ArrayRef<Symbol *> Syms) {
// Demangling symbols (which is what toString() does) is slow, so // Demangling symbols (which is what toString() does) is slow, so
// we do that in batch using parallel-for. // we do that in batch using parallel-for.
static DenseMap<Symbol *, std::string> static DenseMap<Symbol *, std::string>
getSymbolStrings(ArrayRef<Symbol *> Syms) { getSymbolStrings(ArrayRef<Defined *> Syms) {
std::vector<std::string> Str(Syms.size()); std::vector<std::string> Str(Syms.size());
parallelForEachN(0, Syms.size(), [&](size_t I) { parallelForEachN(0, Syms.size(), [&](size_t I) {
raw_string_ostream OS(Str[I]); raw_string_ostream OS(Str[I]);
@ -169,7 +154,7 @@ void elf::writeMapFile() {
} }
// Collect symbol info that we want to print out. // Collect symbol info that we want to print out.
std::vector<Symbol *> Syms = getSymbols(); std::vector<Defined *> Syms = getSymbols();
SymbolMapTy SectionSyms = getSectionSyms(Syms); SymbolMapTy SectionSyms = getSectionSyms(Syms);
DenseMap<Symbol *, std::string> SymStr = getSymbolStrings(Syms); DenseMap<Symbol *, std::string> SymStr = getSymbolStrings(Syms);

View File

@ -461,6 +461,21 @@ static std::vector<SharedSymbol *> getSymbolsAt(SharedSymbol &SS) {
return Ret; return Ret;
} }
static void replaceWithDefined(Symbol &Sym, SectionBase *Sec, uint64_t Value,
uint64_t Size) {
Symbol Old = Sym;
replaceSymbol<Defined>(&Sym, Sym.File, Sym.getName(), Sym.Binding,
Sym.StOther, Sym.Type, Value, Size, Sec);
Sym.PltIndex = Old.PltIndex;
Sym.GotIndex = Old.GotIndex;
Sym.VerdefIndex = Old.VerdefIndex;
Sym.IsInGlobalMipsGot = Old.IsInGlobalMipsGot;
Sym.IsPreemptible = true;
Sym.ExportDynamic = true;
Sym.IsUsedInRegularObj = true;
Sym.Used = true;
}
// Reserve space in .bss or .bss.rel.ro for copy relocation. // Reserve space in .bss or .bss.rel.ro for copy relocation.
// //
// The copy relocation is pretty much a hack. If you use a copy relocation // The copy relocation is pretty much a hack. If you use a copy relocation
@ -522,11 +537,8 @@ template <class ELFT> static void addCopyRelSymbol(SharedSymbol &SS) {
// Look through the DSO's dynamic symbol table for aliases and create a // Look through the DSO's dynamic symbol table for aliases and create a
// dynamic symbol for each one. This causes the copy relocation to correctly // dynamic symbol for each one. This causes the copy relocation to correctly
// interpose any aliases. // interpose any aliases.
for (SharedSymbol *Sym : getSymbolsAt<ELFT>(SS)) { for (SharedSymbol *Sym : getSymbolsAt<ELFT>(SS))
Sym->CopyRelSec = Sec; replaceWithDefined(*Sym, Sec, 0, Sym->Size);
Sym->IsUsedInRegularObj = true;
Sym->Used = true;
}
InX::RelaDyn->addReloc(Target->CopyRel, Sec, 0, &SS); InX::RelaDyn->addReloc(Target->CopyRel, Sec, 0, &SS);
} }
@ -828,10 +840,8 @@ static void processRelocAux(InputSectionBase &Sec, RelExpr Expr, RelType Type,
} }
// If the symbol is undefined we already reported any relevant errors. // If the symbol is undefined we already reported any relevant errors.
if (!Sym.isShared()) { if (Sym.isUndefined())
assert(Sym.isUndefined());
return; return;
}
if (!canDefineSymbolInExecutable(Sym)) { if (!canDefineSymbolInExecutable(Sym)) {
error("cannot preempt symbol: " + toString(Sym) + error("cannot preempt symbol: " + toString(Sym) +
@ -841,14 +851,13 @@ static void processRelocAux(InputSectionBase &Sec, RelExpr Expr, RelType Type,
if (Sym.isObject()) { if (Sym.isObject()) {
// Produce a copy relocation. // Produce a copy relocation.
auto &SS = cast<SharedSymbol>(Sym); if (auto *SS = dyn_cast<SharedSymbol>(&Sym)) {
if (!SS.CopyRelSec) {
if (!Config->ZCopyreloc) if (!Config->ZCopyreloc)
error("unresolvable relocation " + toString(Type) + error("unresolvable relocation " + toString(Type) +
" against symbol '" + toString(SS) + " against symbol '" + toString(*SS) +
"'; recompile with -fPIC or remove '-z nocopyreloc'" + "'; recompile with -fPIC or remove '-z nocopyreloc'" +
getLocation(Sec, Sym, Offset)); getLocation(Sec, Sym, Offset));
addCopyRelSymbol<ELFT>(SS); addCopyRelSymbol<ELFT>(*SS);
} }
Sec.Relocations.push_back({Expr, Type, Offset, Addend, &Sym}); Sec.Relocations.push_back({Expr, Type, Offset, Addend, &Sym});
return; return;
@ -889,8 +898,10 @@ static void processRelocAux(InputSectionBase &Sec, RelExpr Expr, RelType Type,
if (!Sym.isInPlt()) if (!Sym.isInPlt())
addPltEntry<ELFT>(InX::Plt, InX::GotPlt, InX::RelaPlt, Target->PltRel, addPltEntry<ELFT>(InX::Plt, InX::GotPlt, InX::RelaPlt, Target->PltRel,
Sym); Sym);
if (!Sym.isDefined())
replaceWithDefined(Sym, InX::Plt, Sym.getPltOffset(), 0);
Sym.NeedsPltAddr = true; Sym.NeedsPltAddr = true;
Sec.Relocations.push_back({toPlt(Expr), Type, Offset, Addend, &Sym}); Sec.Relocations.push_back({Expr, Type, Offset, Addend, &Sym});
return; return;
} }

View File

@ -97,14 +97,7 @@ static uint64_t getSymVA(const Symbol &Sym, int64_t &Addend) {
} }
return VA; return VA;
} }
case Symbol::SharedKind: { case Symbol::SharedKind:
auto &SS = cast<SharedSymbol>(Sym);
if (SS.CopyRelSec)
return SS.CopyRelSec->getVA(0);
if (SS.NeedsPltAddr)
return Sym.getPltVA();
return 0;
}
case Symbol::UndefinedKind: case Symbol::UndefinedKind:
return 0; return 0;
case Symbol::LazyArchiveKind: case Symbol::LazyArchiveKind:
@ -143,6 +136,11 @@ uint64_t Symbol::getPltVA() const {
return InX::Plt->getVA() + Target->getPltEntryOffset(PltIndex); return InX::Plt->getVA() + Target->getPltEntryOffset(PltIndex);
} }
uint64_t Symbol::getPltOffset() const {
assert(!this->IsInIplt);
return Target->getPltEntryOffset(PltIndex);
}
uint64_t Symbol::getSize() const { uint64_t Symbol::getSize() const {
if (const auto *DR = dyn_cast<Defined>(this)) if (const auto *DR = dyn_cast<Defined>(this))
return DR->Size; return DR->Size;
@ -157,13 +155,6 @@ OutputSection *Symbol::getOutputSection() const {
return Sec->Repl->getOutputSection(); return Sec->Repl->getOutputSection();
return nullptr; return nullptr;
} }
if (auto *S = dyn_cast<SharedSymbol>(this)) {
if (S->CopyRelSec)
return S->CopyRelSec->getParent();
return nullptr;
}
return nullptr; return nullptr;
} }

View File

@ -72,6 +72,9 @@ public:
uint32_t PltIndex = -1; uint32_t PltIndex = -1;
uint32_t GlobalDynIndex = -1; uint32_t GlobalDynIndex = -1;
// This field is a index to the symbol's version definition.
uint32_t VerdefIndex = -1;
// Version definition index. // Version definition index.
uint16_t VersionId; uint16_t VersionId;
@ -146,6 +149,7 @@ public:
uint64_t getGotPltOffset() const; uint64_t getGotPltOffset() const;
uint64_t getGotPltVA() const; uint64_t getGotPltVA() const;
uint64_t getPltVA() const; uint64_t getPltVA() const;
uint64_t getPltOffset() const;
uint64_t getSize() const; uint64_t getSize() const;
OutputSection *getOutputSection() const; OutputSection *getOutputSection() const;
@ -225,8 +229,9 @@ public:
SharedSymbol(InputFile &File, StringRef Name, uint8_t Binding, SharedSymbol(InputFile &File, StringRef Name, uint8_t Binding,
uint8_t StOther, uint8_t Type, uint64_t Value, uint64_t Size, uint8_t StOther, uint8_t Type, uint64_t Value, uint64_t Size,
uint32_t Alignment, uint32_t VerdefIndex) uint32_t Alignment, uint32_t VerdefIndex)
: Symbol(SharedKind, &File, Name, Binding, StOther, Type), Value(Value), : Symbol(SharedKind, &File, Name, Binding, StOther, Type),
Size(Size), VerdefIndex(VerdefIndex), Alignment(Alignment) { Alignment(Alignment), Value(Value), Size(Size) {
this->VerdefIndex = VerdefIndex;
// GNU ifunc is a mechanism to allow user-supplied functions to // GNU ifunc is a mechanism to allow user-supplied functions to
// resolve PLT slot values at load-time. This is contrary to the // resolve PLT slot values at load-time. This is contrary to the
// regular symbol resolution scheme in which symbols are resolved just // regular symbol resolution scheme in which symbols are resolved just
@ -251,16 +256,10 @@ public:
return *cast<SharedFile<ELFT>>(File); return *cast<SharedFile<ELFT>>(File);
} }
// If not null, there is a copy relocation to this section. uint32_t Alignment;
InputSection *CopyRelSec = nullptr;
uint64_t Value; // st_value uint64_t Value; // st_value
uint64_t Size; // st_size uint64_t Size; // st_size
// This field is a index to the symbol's version definition.
uint32_t VerdefIndex;
uint32_t Alignment;
}; };
// LazyArchive and LazyObject represent a symbols that is not yet in the link, // LazyArchive and LazyObject represent a symbols that is not yet in the link,

View File

@ -1646,6 +1646,8 @@ template <class ELFT> void SymbolTableSection<ELFT>::writeTo(uint8_t *Buf) {
CommonSec = dyn_cast_or_null<BssSection>(D->Section); CommonSec = dyn_cast_or_null<BssSection>(D->Section);
if (CommonSec) if (CommonSec)
ESym->st_shndx = SHN_COMMON; ESym->st_shndx = SHN_COMMON;
else if (Sym->NeedsPltAddr)
ESym->st_shndx = SHN_UNDEF;
else if (const OutputSection *OutSec = Sym->getOutputSection()) else if (const OutputSection *OutSec = Sym->getOutputSection())
ESym->st_shndx = OutSec->SectionIndex; ESym->st_shndx = OutSec->SectionIndex;
else if (isa<Defined>(Sym)) else if (isa<Defined>(Sym))
@ -1688,8 +1690,7 @@ template <class ELFT> void SymbolTableSection<ELFT>::writeTo(uint8_t *Buf) {
if (isMicroMips()) { if (isMicroMips()) {
// Set STO_MIPS_MICROMIPS flag and less-significant bit for // Set STO_MIPS_MICROMIPS flag and less-significant bit for
// defined microMIPS symbols and shared symbols with PLT record. // defined microMIPS symbols and shared symbols with PLT record.
if ((Sym->isDefined() && (Sym->StOther & STO_MIPS_MICROMIPS)) || if (Sym->isDefined() && (Sym->StOther & STO_MIPS_MICROMIPS)) {
(Sym->isShared() && Sym->NeedsPltAddr)) {
if (StrTabSec.isDynamic()) if (StrTabSec.isDynamic())
ESym->st_value |= 1; ESym->st_value |= 1;
ESym->st_other |= STO_MIPS_MICROMIPS; ESym->st_other |= STO_MIPS_MICROMIPS;
@ -1831,10 +1832,6 @@ void GnuHashTableSection::addSymbols(std::vector<SymbolTableEntry> &V) {
// its type correctly. // its type correctly.
std::vector<SymbolTableEntry>::iterator Mid = std::vector<SymbolTableEntry>::iterator Mid =
std::stable_partition(V.begin(), V.end(), [](const SymbolTableEntry &S) { std::stable_partition(V.begin(), V.end(), [](const SymbolTableEntry &S) {
// Shared symbols that this executable preempts are special. The dynamic
// linker has to look them up, so they have to be in the hash table.
if (auto *SS = dyn_cast<SharedSymbol>(S.Sym))
return SS->CopyRelSec == nullptr && !SS->NeedsPltAddr;
return !S.Sym->isDefined(); return !S.Sym->isDefined();
}); });
@ -2359,9 +2356,8 @@ VersionNeedSection<ELFT>::VersionNeedSection()
NextIndex = getVerDefNum() + 1; NextIndex = getVerDefNum() + 1;
} }
template <class ELFT> template <class ELFT> void VersionNeedSection<ELFT>::addSymbol(Symbol *SS) {
void VersionNeedSection<ELFT>::addSymbol(SharedSymbol *SS) { auto &File = cast<SharedFile<ELFT>>(*SS->File);
SharedFile<ELFT> &File = SS->getFile<ELFT>();
if (SS->VerdefIndex == VER_NDX_GLOBAL) { if (SS->VerdefIndex == VER_NDX_GLOBAL) {
SS->VersionId = VER_NDX_GLOBAL; SS->VersionId = VER_NDX_GLOBAL;
return; return;

View File

@ -670,7 +670,7 @@ template <class ELFT> class VersionNeedSection final : public SyntheticSection {
public: public:
VersionNeedSection(); VersionNeedSection();
void addSymbol(SharedSymbol *SS); void addSymbol(Symbol *Sym);
void finalizeContents() override; void finalizeContents() override;
void writeTo(uint8_t *Buf) override; void writeTo(uint8_t *Buf) override;
size_t getSize() const override; size_t getSize() const override;

View File

@ -1570,9 +1570,9 @@ template <class ELFT> void Writer<ELFT>::finalizeSections() {
if (InX::DynSymTab && Sym->includeInDynsym()) { if (InX::DynSymTab && Sym->includeInDynsym()) {
InX::DynSymTab->addSymbol(Sym); InX::DynSymTab->addSymbol(Sym);
if (auto *SS = dyn_cast<SharedSymbol>(Sym)) if (auto *File = dyn_cast_or_null<SharedFile<ELFT>>(Sym->File))
if (cast<SharedFile<ELFT>>(Sym->File)->IsNeeded) if (File->IsNeeded && !Sym->isUndefined())
In<ELFT>::VerNeed->addSymbol(SS); In<ELFT>::VerNeed->addSymbol(Sym);
} }
} }

View File

@ -73,8 +73,8 @@ labs = 0x1AB5
// CHECK-NEXT: 20102c 20102c 0 1 baz // CHECK-NEXT: 20102c 20102c 0 1 baz
// CHECK-NEXT: 201030 201030 30 16 .plt // CHECK-NEXT: 201030 201030 30 16 .plt
// CHECK-NEXT: 201030 201030 30 16 <internal>:(.plt) // CHECK-NEXT: 201030 201030 30 16 <internal>:(.plt)
// CHECK-NEXT: 201040 0 0 1 sharedFunc1 // CHECK-NEXT: 201040 201040 0 1 sharedFunc1
// CHECK-NEXT: 201050 0 0 1 sharedFunc2 // CHECK-NEXT: 201050 201050 0 1 sharedFunc2
// CHECK-NEXT: 202000 202000 28 8 .got.plt // CHECK-NEXT: 202000 202000 28 8 .got.plt
// CHECK-NEXT: 202000 202000 28 8 <internal>:(.got.plt) // CHECK-NEXT: 202000 202000 28 8 <internal>:(.got.plt)
// CHECK-NEXT: 203000 203000 100 8 .dynamic // CHECK-NEXT: 203000 203000 100 8 .dynamic