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))
return {DS->Section, false, DS->Value, Loc};
if (auto *SS = dyn_cast<SharedSymbol>(Sym))
if (!ErrorOnMissingSection || SS->CopyRelSec)
return {SS->CopyRelSec, false, 0, Loc};
if (!ErrorOnMissingSection)
return {nullptr, false, 0, Loc};
}
error(Loc + ": symbol not found: " + Name);

View File

@ -38,7 +38,7 @@ using namespace llvm::object;
using namespace lld;
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 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.
static std::vector<Symbol *> getSymbols() {
std::vector<Symbol *> V;
for (InputFile *File : ObjectFiles) {
for (Symbol *B : File->getSymbols()) {
if (auto *SS = dyn_cast<SharedSymbol>(B))
if (SS->CopyRelSec || SS->NeedsPltAddr)
V.push_back(SS);
static std::vector<Defined *> getSymbols() {
std::vector<Defined *> V;
for (InputFile *File : ObjectFiles)
for (Symbol *B : File->getSymbols())
if (auto *DR = dyn_cast<Defined>(B))
if (DR->File == File && !DR->isSection() && DR->Section &&
DR->Section->Live)
if (!DR->isSection() && DR->Section && DR->Section->Live &&
(DR->File == File || DR->NeedsPltAddr || DR->Section->Bss))
V.push_back(DR);
}
}
return V;
}
// Returns a map from sections to their symbols.
static SymbolMapTy getSectionSyms(ArrayRef<Symbol *> Syms) {
static SymbolMapTy getSectionSyms(ArrayRef<Defined *> Syms) {
SymbolMapTy Ret;
for (Symbol *S : Syms) {
if (auto *DR = dyn_cast<Defined>(S)) {
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);
}
for (Defined *DR : Syms)
Ret[DR->Section].push_back(DR);
// Sort symbols by address. We want to print out symbols in the
// order in the output file rather than the order they appeared
// in the input files.
for (auto &It : Ret) {
SmallVectorImpl<Symbol *> &V = It.second;
std::stable_sort(V.begin(), V.end(), [](Symbol *A, Symbol *B) {
SmallVectorImpl<Defined *> &V = It.second;
std::stable_sort(V.begin(), V.end(), [](Defined *A, Defined *B) {
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
// we do that in batch using parallel-for.
static DenseMap<Symbol *, std::string>
getSymbolStrings(ArrayRef<Symbol *> Syms) {
getSymbolStrings(ArrayRef<Defined *> Syms) {
std::vector<std::string> Str(Syms.size());
parallelForEachN(0, Syms.size(), [&](size_t I) {
raw_string_ostream OS(Str[I]);
@ -169,7 +154,7 @@ void elf::writeMapFile() {
}
// Collect symbol info that we want to print out.
std::vector<Symbol *> Syms = getSymbols();
std::vector<Defined *> Syms = getSymbols();
SymbolMapTy SectionSyms = getSectionSyms(Syms);
DenseMap<Symbol *, std::string> SymStr = getSymbolStrings(Syms);

View File

@ -461,6 +461,21 @@ static std::vector<SharedSymbol *> getSymbolsAt(SharedSymbol &SS) {
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.
//
// 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
// dynamic symbol for each one. This causes the copy relocation to correctly
// interpose any aliases.
for (SharedSymbol *Sym : getSymbolsAt<ELFT>(SS)) {
Sym->CopyRelSec = Sec;
Sym->IsUsedInRegularObj = true;
Sym->Used = true;
}
for (SharedSymbol *Sym : getSymbolsAt<ELFT>(SS))
replaceWithDefined(*Sym, Sec, 0, Sym->Size);
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 (!Sym.isShared()) {
assert(Sym.isUndefined());
if (Sym.isUndefined())
return;
}
if (!canDefineSymbolInExecutable(Sym)) {
error("cannot preempt symbol: " + toString(Sym) +
@ -841,14 +851,13 @@ static void processRelocAux(InputSectionBase &Sec, RelExpr Expr, RelType Type,
if (Sym.isObject()) {
// Produce a copy relocation.
auto &SS = cast<SharedSymbol>(Sym);
if (!SS.CopyRelSec) {
if (auto *SS = dyn_cast<SharedSymbol>(&Sym)) {
if (!Config->ZCopyreloc)
error("unresolvable relocation " + toString(Type) +
" against symbol '" + toString(SS) +
" against symbol '" + toString(*SS) +
"'; recompile with -fPIC or remove '-z nocopyreloc'" +
getLocation(Sec, Sym, Offset));
addCopyRelSymbol<ELFT>(SS);
addCopyRelSymbol<ELFT>(*SS);
}
Sec.Relocations.push_back({Expr, Type, Offset, Addend, &Sym});
return;
@ -889,8 +898,10 @@ static void processRelocAux(InputSectionBase &Sec, RelExpr Expr, RelType Type,
if (!Sym.isInPlt())
addPltEntry<ELFT>(InX::Plt, InX::GotPlt, InX::RelaPlt, Target->PltRel,
Sym);
if (!Sym.isDefined())
replaceWithDefined(Sym, InX::Plt, Sym.getPltOffset(), 0);
Sym.NeedsPltAddr = true;
Sec.Relocations.push_back({toPlt(Expr), Type, Offset, Addend, &Sym});
Sec.Relocations.push_back({Expr, Type, Offset, Addend, &Sym});
return;
}

View File

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

View File

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

View File

@ -1646,6 +1646,8 @@ template <class ELFT> void SymbolTableSection<ELFT>::writeTo(uint8_t *Buf) {
CommonSec = dyn_cast_or_null<BssSection>(D->Section);
if (CommonSec)
ESym->st_shndx = SHN_COMMON;
else if (Sym->NeedsPltAddr)
ESym->st_shndx = SHN_UNDEF;
else if (const OutputSection *OutSec = Sym->getOutputSection())
ESym->st_shndx = OutSec->SectionIndex;
else if (isa<Defined>(Sym))
@ -1688,8 +1690,7 @@ template <class ELFT> void SymbolTableSection<ELFT>::writeTo(uint8_t *Buf) {
if (isMicroMips()) {
// Set STO_MIPS_MICROMIPS flag and less-significant bit for
// defined microMIPS symbols and shared symbols with PLT record.
if ((Sym->isDefined() && (Sym->StOther & STO_MIPS_MICROMIPS)) ||
(Sym->isShared() && Sym->NeedsPltAddr)) {
if (Sym->isDefined() && (Sym->StOther & STO_MIPS_MICROMIPS)) {
if (StrTabSec.isDynamic())
ESym->st_value |= 1;
ESym->st_other |= STO_MIPS_MICROMIPS;
@ -1831,10 +1832,6 @@ void GnuHashTableSection::addSymbols(std::vector<SymbolTableEntry> &V) {
// its type correctly.
std::vector<SymbolTableEntry>::iterator Mid =
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();
});
@ -2359,9 +2356,8 @@ VersionNeedSection<ELFT>::VersionNeedSection()
NextIndex = getVerDefNum() + 1;
}
template <class ELFT>
void VersionNeedSection<ELFT>::addSymbol(SharedSymbol *SS) {
SharedFile<ELFT> &File = SS->getFile<ELFT>();
template <class ELFT> void VersionNeedSection<ELFT>::addSymbol(Symbol *SS) {
auto &File = cast<SharedFile<ELFT>>(*SS->File);
if (SS->VerdefIndex == VER_NDX_GLOBAL) {
SS->VersionId = VER_NDX_GLOBAL;
return;

View File

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

View File

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

View File

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