forked from OSchip/llvm-project
Move symbol resolution code out of SymbolTable class.
This is the last patch of the series of patches to make it possible to resolve symbols without asking SymbolTable to do so. The main point of this patch is the introduction of `elf::resolveSymbol(Symbol *Old, Symbol *New)`. That function resolves or merges given symbols by examining symbol types and call replaceSymbol (which memcpy's New to Old) if necessary. With the new function, we have now separated symbol resolution from symbol lookup. If you already have a Symbol pointer, you can directly resolve the symbol without asking SymbolTable to do that. Now that the nice abstraction become available, I can start working on performance improvement of the linker. As a starter, I'm thinking of making --{start,end}-lib faster. --{start,end}-lib is currently unnecessarily slow because it looks up the symbol table twice for each symbol. - The first hash table lookup/insertion occurs when we instantiate a LazyObject file to insert LazyObject symbols. - The second hash table lookup/insertion occurs when we create an ObjFile from LazyObject file. That overwrites LazyObject symbols with Defined symbols. I think it is not too hard to see how we can now eliminate the second hash table lookup. We can keep LazyObject symbols in Step 1, and then call elf::resolveSymbol() to do Step 2. Differential Revision: https://reviews.llvm.org/D61898 llvm-svn: 360975
This commit is contained in:
parent
7ee4307bd4
commit
bbf154cf9c
|
@ -1337,10 +1337,9 @@ static void replaceCommonSymbols() {
|
|||
Bss->File = S->File;
|
||||
Bss->Live = !Config->GcSections;
|
||||
InputSections.push_back(Bss);
|
||||
|
||||
Defined New(S->File, S->getName(), S->Binding, S->StOther, S->Type,
|
||||
/*Value=*/0, S->Size, Bss);
|
||||
replaceSymbol(S, &New);
|
||||
replaceSymbol(S, Defined{S->File, S->getName(), S->Binding, S->StOther,
|
||||
S->Type,
|
||||
/*Value=*/0, S->Size, Bss});
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1355,8 +1354,8 @@ static void demoteSharedSymbols() {
|
|||
continue;
|
||||
|
||||
bool Used = S->Used;
|
||||
Undefined New(nullptr, S->getName(), STB_WEAK, S->StOther, S->Type);
|
||||
replaceSymbol(S, &New);
|
||||
replaceSymbol(
|
||||
S, Undefined{nullptr, S->getName(), STB_WEAK, S->StOther, S->Type});
|
||||
S->Used = Used;
|
||||
}
|
||||
}
|
||||
|
@ -1426,7 +1425,7 @@ static void findKeepUniqueSections(opt::InputArgList &Args) {
|
|||
}
|
||||
|
||||
template <class ELFT> static Symbol *addUndefined(StringRef Name) {
|
||||
return Symtab->addUndefined(
|
||||
return Symtab->addSymbol(
|
||||
Undefined{nullptr, Name, STB_GLOBAL, STV_DEFAULT, 0});
|
||||
}
|
||||
|
||||
|
|
|
@ -911,12 +911,12 @@ template <class ELFT> Symbol *ObjFile<ELFT>::createSymbol(const Elf_Sym *Sym) {
|
|||
|
||||
switch (Sym->st_shndx) {
|
||||
case SHN_UNDEF:
|
||||
return Symtab->addUndefined(Undefined{this, Name, Binding, StOther, Type});
|
||||
return Symtab->addSymbol(Undefined{this, Name, Binding, StOther, Type});
|
||||
case SHN_COMMON:
|
||||
if (Value == 0 || Value >= UINT32_MAX)
|
||||
fatal(toString(this) + ": common symbol '" + Name +
|
||||
"' has invalid alignment: " + Twine(Value));
|
||||
return Symtab->addCommon(
|
||||
return Symtab->addSymbol(
|
||||
CommonSymbol{this, Name, Binding, StOther, Type, Value, Size});
|
||||
}
|
||||
|
||||
|
@ -927,9 +927,8 @@ template <class ELFT> Symbol *ObjFile<ELFT>::createSymbol(const Elf_Sym *Sym) {
|
|||
case STB_WEAK:
|
||||
case STB_GNU_UNIQUE:
|
||||
if (Sec == &InputSection::Discarded)
|
||||
return Symtab->addUndefined(
|
||||
Undefined{this, Name, Binding, StOther, Type});
|
||||
return Symtab->addDefined(
|
||||
return Symtab->addSymbol(Undefined{this, Name, Binding, StOther, Type});
|
||||
return Symtab->addSymbol(
|
||||
Defined{this, Name, Binding, StOther, Type, Value, Size, Sec});
|
||||
}
|
||||
}
|
||||
|
@ -940,7 +939,7 @@ ArchiveFile::ArchiveFile(std::unique_ptr<Archive> &&File)
|
|||
|
||||
void ArchiveFile::parse() {
|
||||
for (const Archive::Symbol &Sym : File->symbols())
|
||||
Symtab->addLazyArchive(LazyArchive{*this, Sym});
|
||||
Symtab->addSymbol(LazyArchive{*this, Sym});
|
||||
}
|
||||
|
||||
// Returns a buffer pointing to a member file containing a given symbol.
|
||||
|
@ -1141,7 +1140,7 @@ template <class ELFT> void SharedFile::parse() {
|
|||
}
|
||||
|
||||
if (Sym.isUndefined()) {
|
||||
Symbol *S = Symtab->addUndefined(
|
||||
Symbol *S = Symtab->addSymbol(
|
||||
Undefined{this, Name, Sym.getBinding(), Sym.st_other, Sym.getType()});
|
||||
S->ExportDynamic = true;
|
||||
continue;
|
||||
|
@ -1157,7 +1156,7 @@ template <class ELFT> void SharedFile::parse() {
|
|||
|
||||
uint32_t Alignment = getAlignment<ELFT>(Sections, Sym);
|
||||
if (!(Versyms[I] & VERSYM_HIDDEN)) {
|
||||
Symtab->addShared(SharedSymbol{*this, Name, Sym.getBinding(),
|
||||
Symtab->addSymbol(SharedSymbol{*this, Name, Sym.getBinding(),
|
||||
Sym.st_other, Sym.getType(), Sym.st_value,
|
||||
Sym.st_size, Alignment, Idx});
|
||||
}
|
||||
|
@ -1179,7 +1178,7 @@ template <class ELFT> void SharedFile::parse() {
|
|||
reinterpret_cast<const Elf_Verdef *>(Verdefs[Idx])->getAux()->vda_name;
|
||||
VersionedNameBuffer.clear();
|
||||
Name = (Name + "@" + VerName).toStringRef(VersionedNameBuffer);
|
||||
Symtab->addShared(SharedSymbol{*this, Saver.save(Name), Sym.getBinding(),
|
||||
Symtab->addSymbol(SharedSymbol{*this, Saver.save(Name), Sym.getBinding(),
|
||||
Sym.st_other, Sym.getType(), Sym.st_value,
|
||||
Sym.st_size, Alignment, Idx});
|
||||
}
|
||||
|
@ -1281,18 +1280,18 @@ static Symbol *createBitcodeSymbol(const std::vector<bool> &KeptComdats,
|
|||
Undefined New(&F, Name, Binding, Visibility, Type);
|
||||
if (CanOmitFromDynSym)
|
||||
New.ExportDynamic = false;
|
||||
return Symtab->addUndefined(New);
|
||||
return Symtab->addSymbol(New);
|
||||
}
|
||||
|
||||
if (ObjSym.isCommon())
|
||||
return Symtab->addCommon(
|
||||
return Symtab->addSymbol(
|
||||
CommonSymbol{&F, Name, Binding, Visibility, STT_OBJECT,
|
||||
ObjSym.getCommonAlignment(), ObjSym.getCommonSize()});
|
||||
|
||||
Defined New(&F, Name, Binding, Visibility, Type, 0, 0, nullptr);
|
||||
if (CanOmitFromDynSym)
|
||||
New.ExportDynamic = false;
|
||||
return Symtab->addDefined(New);
|
||||
return Symtab->addSymbol(New);
|
||||
}
|
||||
|
||||
template <class ELFT>
|
||||
|
@ -1350,12 +1349,12 @@ void BinaryFile::parse() {
|
|||
if (!isAlnum(S[I]))
|
||||
S[I] = '_';
|
||||
|
||||
Symtab->addDefined(Defined{nullptr, Saver.save(S + "_start"), STB_GLOBAL,
|
||||
STV_DEFAULT, STT_OBJECT, 0, 0, Section});
|
||||
Symtab->addDefined(Defined{nullptr, Saver.save(S + "_end"), STB_GLOBAL,
|
||||
STV_DEFAULT, STT_OBJECT, Data.size(), 0, Section});
|
||||
Symtab->addDefined(Defined{nullptr, Saver.save(S + "_size"), STB_GLOBAL,
|
||||
STV_DEFAULT, STT_OBJECT, Data.size(), 0, nullptr});
|
||||
Symtab->addSymbol(Defined{nullptr, Saver.save(S + "_start"), STB_GLOBAL,
|
||||
STV_DEFAULT, STT_OBJECT, 0, 0, Section});
|
||||
Symtab->addSymbol(Defined{nullptr, Saver.save(S + "_end"), STB_GLOBAL,
|
||||
STV_DEFAULT, STT_OBJECT, Data.size(), 0, Section});
|
||||
Symtab->addSymbol(Defined{nullptr, Saver.save(S + "_size"), STB_GLOBAL,
|
||||
STV_DEFAULT, STT_OBJECT, Data.size(), 0, nullptr});
|
||||
}
|
||||
|
||||
InputFile *elf::createObjectFile(MemoryBufferRef MB, StringRef ArchiveName,
|
||||
|
@ -1423,7 +1422,7 @@ template <class ELFT> void LazyObjFile::parse() {
|
|||
for (const lto::InputFile::Symbol &Sym : Obj->symbols()) {
|
||||
if (Sym.isUndefined())
|
||||
continue;
|
||||
Symtab->addLazyObject(LazyObject{*this, Saver.save(Sym.getName())});
|
||||
Symtab->addSymbol(LazyObject{*this, Saver.save(Sym.getName())});
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
@ -1448,7 +1447,7 @@ template <class ELFT> void LazyObjFile::parse() {
|
|||
for (const typename ELFT::Sym &Sym : Syms.slice(FirstGlobal)) {
|
||||
if (Sym.st_shndx == SHN_UNDEF)
|
||||
continue;
|
||||
Symtab->addLazyObject(
|
||||
Symtab->addSymbol(
|
||||
LazyObject{*this, CHECK(Sym.getName(StringTable), this)});
|
||||
}
|
||||
return;
|
||||
|
|
|
@ -152,11 +152,6 @@ BitcodeCompiler::BitcodeCompiler() {
|
|||
|
||||
BitcodeCompiler::~BitcodeCompiler() = default;
|
||||
|
||||
static void undefine(Symbol *S) {
|
||||
Undefined New(nullptr, S->getName(), STB_GLOBAL, STV_DEFAULT, S->Type);
|
||||
replaceSymbol(S, &New);
|
||||
}
|
||||
|
||||
void BitcodeCompiler::add(BitcodeFile &F) {
|
||||
lto::InputFile &Obj = *F.Obj;
|
||||
bool IsExec = !Config->Shared && !Config->Relocatable;
|
||||
|
@ -201,7 +196,8 @@ void BitcodeCompiler::add(BitcodeFile &F) {
|
|||
!(DR->Section == nullptr && (!Sym->File || Sym->File->isElf()));
|
||||
|
||||
if (R.Prevailing)
|
||||
undefine(Sym);
|
||||
replaceSymbol(Sym, Undefined{nullptr, Sym->getName(), STB_GLOBAL,
|
||||
STV_DEFAULT, Sym->Type});
|
||||
|
||||
// We tell LTO to not apply interprocedural optimization for wrapped
|
||||
// (with --wrap) symbols because otherwise LTO would inline them while
|
||||
|
|
|
@ -186,9 +186,9 @@ void LinkerScript::addSymbol(SymbolAssignment *Cmd) {
|
|||
Defined New(nullptr, Cmd->Name, STB_GLOBAL, Visibility, STT_NOTYPE, SymValue,
|
||||
0, Sec);
|
||||
|
||||
Symbol *Sym = Symtab->insert(New);
|
||||
Symtab->mergeProperties(Sym, New);
|
||||
replaceSymbol(Sym, &New);
|
||||
Symbol *Sym = Symtab->insert(Cmd->Name);
|
||||
mergeSymbolProperties(Sym, New);
|
||||
replaceSymbol(Sym, New);
|
||||
Cmd->Sym = cast<Defined>(Sym);
|
||||
}
|
||||
|
||||
|
@ -203,9 +203,9 @@ static void declareSymbol(SymbolAssignment *Cmd) {
|
|||
nullptr);
|
||||
|
||||
// We can't calculate final value right now.
|
||||
Symbol *Sym = Symtab->insert(New);
|
||||
Symtab->mergeProperties(Sym, New);
|
||||
replaceSymbol(Sym, &New);
|
||||
Symbol *Sym = Symtab->insert(Cmd->Name);
|
||||
mergeSymbolProperties(Sym, New);
|
||||
replaceSymbol(Sym, New);
|
||||
|
||||
Cmd->Sym = cast<Defined>(Sym);
|
||||
Cmd->Provide = false;
|
||||
|
|
|
@ -530,9 +530,8 @@ static void replaceWithDefined(Symbol &Sym, SectionBase *Sec, uint64_t Value,
|
|||
uint64_t Size) {
|
||||
Symbol Old = Sym;
|
||||
|
||||
Defined New(Sym.File, Sym.getName(), Sym.Binding, Sym.StOther, Sym.Type,
|
||||
Value, Size, Sec);
|
||||
replaceSymbol(&Sym, &New);
|
||||
replaceSymbol(&Sym, Defined{Sym.File, Sym.getName(), Sym.Binding, Sym.StOther,
|
||||
Sym.Type, Value, Size, Sec});
|
||||
|
||||
Sym.PltIndex = Old.PltIndex;
|
||||
Sym.GotIndex = Old.GotIndex;
|
||||
|
|
|
@ -86,15 +86,14 @@ static uint8_t getMinVisibility(uint8_t VA, uint8_t VB) {
|
|||
return std::min(VA, VB);
|
||||
}
|
||||
|
||||
// Find an existing symbol or create and insert a new one.
|
||||
Symbol *SymbolTable::insert(const Symbol &New) {
|
||||
// Find an existing symbol or create a new one.
|
||||
Symbol *SymbolTable::insert(StringRef Name) {
|
||||
// <name>@@<version> means the symbol is the default version. In that
|
||||
// case <name>@@<version> will be used to resolve references to <name>.
|
||||
//
|
||||
// Since this is a hot path, the following string search code is
|
||||
// optimized for speed. StringRef::find(char) is much faster than
|
||||
// StringRef::find(StringRef).
|
||||
StringRef Name = New.getName();
|
||||
size_t Pos = Name.find('@');
|
||||
if (Pos != StringRef::npos && Pos + 1 < Name.size() && Name[Pos + 1] == '@')
|
||||
Name = Name.take_front(Pos);
|
||||
|
@ -110,55 +109,35 @@ Symbol *SymbolTable::insert(const Symbol &New) {
|
|||
Traced = true;
|
||||
}
|
||||
|
||||
Symbol *Old;
|
||||
if (IsNew) {
|
||||
Old = reinterpret_cast<Symbol *>(make<SymbolUnion>());
|
||||
SymVector.push_back(Old);
|
||||
if (!IsNew)
|
||||
return SymVector[SymIndex];
|
||||
|
||||
Old->SymbolKind = Symbol::PlaceholderKind;
|
||||
Old->VersionId = Config->DefaultSymbolVersion;
|
||||
Old->Visibility = STV_DEFAULT;
|
||||
Old->IsUsedInRegularObj = false;
|
||||
Old->ExportDynamic = false;
|
||||
Old->CanInline = true;
|
||||
Old->Traced = Traced;
|
||||
Old->ScriptDefined = false;
|
||||
} else {
|
||||
Old = SymVector[SymIndex];
|
||||
}
|
||||
Symbol *Sym = reinterpret_cast<Symbol *>(make<SymbolUnion>());
|
||||
SymVector.push_back(Sym);
|
||||
|
||||
Sym->SymbolKind = Symbol::PlaceholderKind;
|
||||
Sym->VersionId = Config->DefaultSymbolVersion;
|
||||
Sym->Visibility = STV_DEFAULT;
|
||||
Sym->IsUsedInRegularObj = false;
|
||||
Sym->ExportDynamic = false;
|
||||
Sym->CanInline = true;
|
||||
Sym->Traced = Traced;
|
||||
Sym->ScriptDefined = false;
|
||||
return Sym;
|
||||
}
|
||||
|
||||
Symbol *SymbolTable::addSymbol(const Symbol &New) {
|
||||
Symbol *Old = Symtab->insert(New.getName());
|
||||
resolveSymbol(Old, New);
|
||||
return Old;
|
||||
}
|
||||
|
||||
// Merge symbol properties.
|
||||
//
|
||||
// When we have many symbols of the same name, we choose one of them,
|
||||
// and that's the result of symbol resolution. However, symbols that
|
||||
// were not chosen still affect some symbol properteis.
|
||||
void SymbolTable::mergeProperties(Symbol *Old, const Symbol &New) {
|
||||
// Merge symbol properties.
|
||||
Old->ExportDynamic = Old->ExportDynamic || New.ExportDynamic;
|
||||
Old->IsUsedInRegularObj = Old->IsUsedInRegularObj || New.IsUsedInRegularObj;
|
||||
|
||||
// DSO symbols do not affect visibility in the output.
|
||||
if (!isa<SharedSymbol>(New))
|
||||
Old->Visibility = getMinVisibility(Old->Visibility, New.Visibility);
|
||||
}
|
||||
|
||||
Symbol *SymbolTable::addUndefined(const Undefined &New) {
|
||||
Symbol *Old = insert(New);
|
||||
mergeProperties(Old, New);
|
||||
|
||||
if (Old->isPlaceholder()) {
|
||||
replaceSymbol(Old, &New);
|
||||
return Old;
|
||||
}
|
||||
|
||||
static void addUndefined(Symbol *Old, const Undefined &New) {
|
||||
// An undefined symbol with non default visibility must be satisfied
|
||||
// in the same DSO.
|
||||
if (Old->isShared() && New.Visibility != STV_DEFAULT) {
|
||||
replaceSymbol(Old, &New);
|
||||
return Old;
|
||||
replaceSymbol(Old, New);
|
||||
return;
|
||||
}
|
||||
|
||||
if (Old->isShared() || Old->isLazy() ||
|
||||
|
@ -170,7 +149,7 @@ Symbol *SymbolTable::addUndefined(const Undefined &New) {
|
|||
// Symbols.h for the details.
|
||||
if (New.Binding == STB_WEAK) {
|
||||
Old->Type = New.Type;
|
||||
return Old;
|
||||
return;
|
||||
}
|
||||
|
||||
// Do extra check for --warn-backrefs.
|
||||
|
@ -225,7 +204,7 @@ Symbol *SymbolTable::addUndefined(const Undefined &New) {
|
|||
// group assignment rule simulates the traditional linker's semantics.
|
||||
bool Backref = Config->WarnBackrefs && New.File &&
|
||||
Old->File->GroupId < New.File->GroupId;
|
||||
fetchLazy(Old);
|
||||
Symtab->fetchLazy(Old);
|
||||
|
||||
// We don't report backward references to weak symbols as they can be
|
||||
// overridden later.
|
||||
|
@ -233,7 +212,6 @@ Symbol *SymbolTable::addUndefined(const Undefined &New) {
|
|||
warn("backward reference detected: " + New.getName() + " in " +
|
||||
toString(New.File) + " refers to " + toString(Old->File));
|
||||
}
|
||||
return Old;
|
||||
}
|
||||
|
||||
// Using .symver foo,foo@@VER unfortunately creates two symbols: foo and
|
||||
|
@ -300,22 +278,14 @@ static int compare(const Symbol *Old, const Symbol *New) {
|
|||
return 0;
|
||||
}
|
||||
|
||||
Symbol *SymbolTable::addCommon(const CommonSymbol &New) {
|
||||
Symbol *Old = insert(New);
|
||||
mergeProperties(Old, New);
|
||||
|
||||
if (Old->isPlaceholder()) {
|
||||
replaceSymbol(Old, &New);
|
||||
return Old;
|
||||
}
|
||||
|
||||
static void addCommon(Symbol *Old, const CommonSymbol &New) {
|
||||
int Cmp = compare(Old, &New);
|
||||
if (Cmp < 0)
|
||||
return Old;
|
||||
return;
|
||||
|
||||
if (Cmp > 0) {
|
||||
replaceSymbol(Old, &New);
|
||||
return Old;
|
||||
replaceSymbol(Old, New);
|
||||
return;
|
||||
}
|
||||
|
||||
CommonSymbol *OldSym = cast<CommonSymbol>(Old);
|
||||
|
@ -325,7 +295,6 @@ Symbol *SymbolTable::addCommon(const CommonSymbol &New) {
|
|||
OldSym->File = New.File;
|
||||
OldSym->Size = New.Size;
|
||||
}
|
||||
return OldSym;
|
||||
}
|
||||
|
||||
static void reportDuplicate(Symbol *Sym, InputFile *NewFile,
|
||||
|
@ -363,45 +332,23 @@ static void reportDuplicate(Symbol *Sym, InputFile *NewFile,
|
|||
error(Msg);
|
||||
}
|
||||
|
||||
Symbol *SymbolTable::addDefined(const Defined &New) {
|
||||
Symbol *Old = insert(New);
|
||||
mergeProperties(Old, New);
|
||||
|
||||
if (Old->isPlaceholder()) {
|
||||
replaceSymbol(Old, &New);
|
||||
return Old;
|
||||
}
|
||||
|
||||
static void addDefined(Symbol *Old, const Defined &New) {
|
||||
int Cmp = compare(Old, &New);
|
||||
if (Cmp > 0)
|
||||
replaceSymbol(Old, &New);
|
||||
replaceSymbol(Old, New);
|
||||
else if (Cmp == 0)
|
||||
reportDuplicate(Old, New.File,
|
||||
dyn_cast_or_null<InputSectionBase>(New.Section), New.Value);
|
||||
return Old;
|
||||
}
|
||||
|
||||
Symbol *SymbolTable::addShared(const SharedSymbol &New) {
|
||||
Symbol *Old = insert(New);
|
||||
mergeProperties(Old, New);
|
||||
|
||||
// Make sure we preempt DSO symbols with default visibility.
|
||||
if (New.Visibility == STV_DEFAULT)
|
||||
Old->ExportDynamic = true;
|
||||
|
||||
if (Old->isPlaceholder()) {
|
||||
replaceSymbol(Old, &New);
|
||||
return Old;
|
||||
}
|
||||
|
||||
static void addShared(Symbol *Old, const SharedSymbol &New) {
|
||||
if (Old->Visibility == STV_DEFAULT && (Old->isUndefined() || Old->isLazy())) {
|
||||
// An undefined symbol with non default visibility must be satisfied
|
||||
// in the same DSO.
|
||||
uint8_t Binding = Old->Binding;
|
||||
replaceSymbol(Old, &New);
|
||||
replaceSymbol(Old, New);
|
||||
Old->Binding = Binding;
|
||||
}
|
||||
return Old;
|
||||
}
|
||||
|
||||
Symbol *SymbolTable::find(StringRef Name) {
|
||||
|
@ -413,39 +360,30 @@ Symbol *SymbolTable::find(StringRef Name) {
|
|||
return SymVector[It->second];
|
||||
}
|
||||
|
||||
template <class LazyT> Symbol *SymbolTable::addLazy(const LazyT &New) {
|
||||
Symbol *Old = insert(New);
|
||||
mergeProperties(Old, New);
|
||||
|
||||
if (Old->isPlaceholder()) {
|
||||
replaceSymbol(Old, &New);
|
||||
return Old;
|
||||
}
|
||||
|
||||
template <class LazyT> static void addLazy(Symbol *Old, const LazyT &New) {
|
||||
if (!Old->isUndefined())
|
||||
return Old;
|
||||
return;
|
||||
|
||||
// An undefined weak will not fetch archive members. See comment on Lazy in
|
||||
// Symbols.h for the details.
|
||||
if (Old->isWeak()) {
|
||||
uint8_t Type = Old->Type;
|
||||
replaceSymbol(Old, &New);
|
||||
replaceSymbol(Old, New);
|
||||
Old->Type = Type;
|
||||
Old->Binding = STB_WEAK;
|
||||
return Old;
|
||||
return;
|
||||
}
|
||||
|
||||
if (InputFile *F = New.fetch())
|
||||
parseFile(F);
|
||||
return Old;
|
||||
}
|
||||
|
||||
Symbol *SymbolTable::addLazyArchive(const LazyArchive &New) {
|
||||
return addLazy(New);
|
||||
static void addLazyArchive(Symbol *Old, const LazyArchive &New) {
|
||||
addLazy(Old, New);
|
||||
}
|
||||
|
||||
Symbol *SymbolTable::addLazyObject(const LazyObject &New) {
|
||||
return addLazy(New);
|
||||
static void addLazyObject(Symbol *Old, const LazyObject &New) {
|
||||
addLazy(Old, New);
|
||||
}
|
||||
|
||||
void SymbolTable::fetchLazy(Symbol *Sym) {
|
||||
|
@ -621,6 +559,53 @@ void SymbolTable::scanVersionScript() {
|
|||
Sym->parseSymbolVersion();
|
||||
}
|
||||
|
||||
// Merge symbol properties.
|
||||
//
|
||||
// When we have many symbols of the same name, we choose one of them,
|
||||
// and that's the result of symbol resolution. However, symbols that
|
||||
// were not chosen still affect some symbol properties.
|
||||
void elf::mergeSymbolProperties(Symbol *Old, const Symbol &New) {
|
||||
// Merge symbol properties.
|
||||
Old->ExportDynamic = Old->ExportDynamic || New.ExportDynamic;
|
||||
Old->IsUsedInRegularObj = Old->IsUsedInRegularObj || New.IsUsedInRegularObj;
|
||||
|
||||
// DSO symbols do not affect visibility in the output.
|
||||
if (!New.isShared())
|
||||
Old->Visibility = getMinVisibility(Old->Visibility, New.Visibility);
|
||||
}
|
||||
|
||||
void elf::resolveSymbol(Symbol *Old, const Symbol &New) {
|
||||
mergeSymbolProperties(Old, New);
|
||||
|
||||
if (Old->isPlaceholder()) {
|
||||
replaceSymbol(Old, New);
|
||||
return;
|
||||
}
|
||||
|
||||
switch (New.kind()) {
|
||||
case Symbol::UndefinedKind:
|
||||
addUndefined(Old, cast<Undefined>(New));
|
||||
break;
|
||||
case Symbol::CommonKind:
|
||||
addCommon(Old, cast<CommonSymbol>(New));
|
||||
break;
|
||||
case Symbol::DefinedKind:
|
||||
addDefined(Old, cast<Defined>(New));
|
||||
break;
|
||||
case Symbol::LazyArchiveKind:
|
||||
addLazyArchive(Old, cast<LazyArchive>(New));
|
||||
break;
|
||||
case Symbol::LazyObjectKind:
|
||||
addLazyObject(Old, cast<LazyObject>(New));
|
||||
break;
|
||||
case Symbol::SharedKind:
|
||||
addShared(Old, cast<SharedSymbol>(New));
|
||||
break;
|
||||
case Symbol::PlaceholderKind:
|
||||
llvm_unreachable("bad symbol kind");
|
||||
}
|
||||
}
|
||||
|
||||
template void SymbolTable::addCombinedLTOObject<ELF32LE>();
|
||||
template void SymbolTable::addCombinedLTOObject<ELF32BE>();
|
||||
template void SymbolTable::addCombinedLTOObject<ELF64LE>();
|
||||
|
|
|
@ -45,15 +45,9 @@ public:
|
|||
|
||||
ArrayRef<Symbol *> getSymbols() const { return SymVector; }
|
||||
|
||||
Symbol *addUndefined(const Undefined &New);
|
||||
Symbol *addDefined(const Defined &New);
|
||||
Symbol *addShared(const SharedSymbol &New);
|
||||
Symbol *addLazyArchive(const LazyArchive &New);
|
||||
Symbol *addLazyObject(const LazyObject &New);
|
||||
Symbol *addCommon(const CommonSymbol &New);
|
||||
Symbol *insert(StringRef Name);
|
||||
|
||||
Symbol *insert(const Symbol &New);
|
||||
void mergeProperties(Symbol *Old, const Symbol &New);
|
||||
Symbol *addSymbol(const Symbol &New);
|
||||
|
||||
void fetchLazy(Symbol *Sym);
|
||||
|
||||
|
@ -69,8 +63,6 @@ public:
|
|||
llvm::DenseMap<StringRef, SharedFile *> SoNames;
|
||||
|
||||
private:
|
||||
template <class LazyT> Symbol *addLazy(const LazyT &New);
|
||||
|
||||
std::vector<Symbol *> findByVersion(SymbolVersion Ver);
|
||||
std::vector<Symbol *> findAllByVersion(SymbolVersion Ver);
|
||||
|
||||
|
@ -106,6 +98,10 @@ private:
|
|||
};
|
||||
|
||||
extern SymbolTable *Symtab;
|
||||
|
||||
void mergeSymbolProperties(Symbol *Old, const Symbol &New);
|
||||
void resolveSymbol(Symbol *Old, const Symbol &New);
|
||||
|
||||
} // namespace elf
|
||||
} // namespace lld
|
||||
|
||||
|
|
|
@ -172,17 +172,23 @@ public:
|
|||
uint64_t getSize() const;
|
||||
OutputSection *getOutputSection() const;
|
||||
|
||||
private:
|
||||
static bool isExportDynamic(Kind K, uint8_t Visibility) {
|
||||
if (K == SharedKind)
|
||||
return Visibility == llvm::ELF::STV_DEFAULT;
|
||||
return Config->Shared || Config->ExportDynamic;
|
||||
}
|
||||
|
||||
protected:
|
||||
Symbol(Kind K, InputFile *File, StringRefZ Name, uint8_t Binding,
|
||||
uint8_t StOther, uint8_t Type)
|
||||
: File(File), NameData(Name.Data), NameSize(Name.Size), Binding(Binding),
|
||||
Type(Type), StOther(StOther), SymbolKind(K), Visibility(StOther & 3),
|
||||
IsUsedInRegularObj(!File || File->kind() == InputFile::ObjKind),
|
||||
ExportDynamic(K != SharedKind &&
|
||||
(Config->Shared || Config->ExportDynamic)),
|
||||
CanInline(false), Traced(false), NeedsPltAddr(false), IsInIplt(false),
|
||||
GotInIgot(false), IsPreemptible(false), Used(!Config->GcSections),
|
||||
NeedsTocRestore(false), ScriptDefined(false) {}
|
||||
ExportDynamic(isExportDynamic(K, Visibility)), CanInline(false),
|
||||
Traced(false), NeedsPltAddr(false), IsInIplt(false), GotInIgot(false),
|
||||
IsPreemptible(false), Used(!Config->GcSections), NeedsTocRestore(false),
|
||||
ScriptDefined(false) {}
|
||||
|
||||
public:
|
||||
// True the symbol should point to its PLT entry.
|
||||
|
@ -395,24 +401,53 @@ struct ElfSym {
|
|||
// using the placement new.
|
||||
union SymbolUnion {
|
||||
alignas(Defined) char A[sizeof(Defined)];
|
||||
alignas(CommonSymbol) char B[sizeof(CommonSymbol)];
|
||||
alignas(Undefined) char C[sizeof(Undefined)];
|
||||
alignas(SharedSymbol) char D[sizeof(SharedSymbol)];
|
||||
alignas(LazyArchive) char E[sizeof(LazyArchive)];
|
||||
alignas(LazyObject) char F[sizeof(LazyObject)];
|
||||
};
|
||||
|
||||
void printTraceSymbol(Symbol *Sym);
|
||||
|
||||
template <typename T> void replaceSymbol(Symbol *Sym, const T *New) {
|
||||
using llvm::ELF::STT_TLS;
|
||||
|
||||
template <typename T> struct AssertSymbol {
|
||||
static_assert(std::is_trivially_destructible<T>(),
|
||||
"Symbol types must be trivially destructible");
|
||||
static_assert(sizeof(T) <= sizeof(SymbolUnion), "SymbolUnion too small");
|
||||
static_assert(alignof(T) <= alignof(SymbolUnion),
|
||||
"SymbolUnion not aligned enough");
|
||||
assert(static_cast<Symbol *>(static_cast<T *>(nullptr)) == nullptr &&
|
||||
"Not a Symbol");
|
||||
};
|
||||
|
||||
static inline void assertSymbols() {
|
||||
AssertSymbol<Defined>();
|
||||
AssertSymbol<CommonSymbol>();
|
||||
AssertSymbol<Undefined>();
|
||||
AssertSymbol<SharedSymbol>();
|
||||
AssertSymbol<LazyArchive>();
|
||||
AssertSymbol<LazyObject>();
|
||||
}
|
||||
|
||||
void printTraceSymbol(Symbol *Sym);
|
||||
|
||||
static size_t getSymbolSize(const Symbol &Sym) {
|
||||
switch (Sym.kind()) {
|
||||
case Symbol::CommonKind:
|
||||
return sizeof(CommonSymbol);
|
||||
case Symbol::DefinedKind:
|
||||
return sizeof(Defined);
|
||||
case Symbol::LazyArchiveKind:
|
||||
return sizeof(LazyArchive);
|
||||
case Symbol::LazyObjectKind:
|
||||
return sizeof(LazyObject);
|
||||
case Symbol::SharedKind:
|
||||
return sizeof(SharedSymbol);
|
||||
case Symbol::UndefinedKind:
|
||||
return sizeof(Undefined);
|
||||
case Symbol::PlaceholderKind:
|
||||
return sizeof(Symbol);
|
||||
}
|
||||
}
|
||||
|
||||
inline void replaceSymbol(Symbol *Sym, const Symbol &New) {
|
||||
using llvm::ELF::STT_TLS;
|
||||
|
||||
// Symbols representing thread-local variables must be referenced by
|
||||
// TLS-aware relocations, and non-TLS symbols must be reference by
|
||||
|
@ -420,16 +455,16 @@ template <typename T> void replaceSymbol(Symbol *Sym, const T *New) {
|
|||
// and non-TLS symbols. It is an error if the same symbol is defined
|
||||
// as a TLS symbol in one file and as a non-TLS symbol in other file.
|
||||
if (Sym->SymbolKind != Symbol::PlaceholderKind && !Sym->isLazy() &&
|
||||
!New->isLazy()) {
|
||||
bool TlsMismatch = (Sym->Type == STT_TLS && New->Type != STT_TLS) ||
|
||||
(Sym->Type != STT_TLS && New->Type == STT_TLS);
|
||||
!New.isLazy()) {
|
||||
bool TlsMismatch = (Sym->Type == STT_TLS && New.Type != STT_TLS) ||
|
||||
(Sym->Type != STT_TLS && New.Type == STT_TLS);
|
||||
if (TlsMismatch)
|
||||
error("TLS attribute mismatch: " + toString(*Sym) + "\n>>> defined in " +
|
||||
toString(New->File) + "\n>>> defined in " + toString(Sym->File));
|
||||
toString(New.File) + "\n>>> defined in " + toString(Sym->File));
|
||||
}
|
||||
|
||||
Symbol Old = *Sym;
|
||||
memcpy(Sym, New, sizeof(T));
|
||||
memcpy(Sym, &New, getSymbolSize(New));
|
||||
|
||||
Sym->VersionId = Old.VersionId;
|
||||
Sym->Visibility = Old.Visibility;
|
||||
|
|
|
@ -180,14 +180,14 @@ static Defined *addOptionalRegular(StringRef Name, SectionBase *Sec,
|
|||
if (!S || S->isDefined())
|
||||
return nullptr;
|
||||
|
||||
return cast<Defined>(Symtab->addDefined(
|
||||
return cast<Defined>(Symtab->addSymbol(
|
||||
Defined{/*File=*/nullptr, Name, Binding, StOther, STT_NOTYPE, Val,
|
||||
/*Size=*/0, Sec}));
|
||||
}
|
||||
|
||||
static Defined *addAbsolute(StringRef Name) {
|
||||
Defined New(nullptr, Name, STB_GLOBAL, STV_HIDDEN, STT_NOTYPE, 0, 0, nullptr);
|
||||
Symbol *Sym = Symtab->addDefined(New);
|
||||
Symbol *Sym = Symtab->addSymbol(Defined{nullptr, Name, STB_GLOBAL, STV_HIDDEN,
|
||||
STT_NOTYPE, 0, 0, nullptr});
|
||||
if (!Sym->isDefined())
|
||||
error("duplicate symbol: " + toString(*Sym));
|
||||
return cast<Defined>(Sym);
|
||||
|
@ -239,9 +239,9 @@ void elf::addReservedSymbols() {
|
|||
if (Config->EMachine == EM_PPC || Config->EMachine == EM_PPC64)
|
||||
GotOff = 0x8000;
|
||||
|
||||
Symtab->addDefined(Defined{/*File=*/nullptr, GotSymName, STB_GLOBAL,
|
||||
STV_HIDDEN, STT_NOTYPE, GotOff, /*Size=*/0,
|
||||
Out::ElfHeader});
|
||||
Symtab->addSymbol(Defined{/*File=*/nullptr, GotSymName, STB_GLOBAL,
|
||||
STV_HIDDEN, STT_NOTYPE, GotOff, /*Size=*/0,
|
||||
Out::ElfHeader});
|
||||
ElfSym::GlobalOffsetTable = cast<Defined>(S);
|
||||
}
|
||||
|
||||
|
@ -1592,9 +1592,9 @@ template <class ELFT> void Writer<ELFT>::finalizeSections() {
|
|||
// Even the author of gold doesn't remember why gold behaves that way.
|
||||
// https://sourceware.org/ml/binutils/2002-03/msg00360.html
|
||||
if (In.Dynamic->Parent)
|
||||
Symtab->addDefined(Defined{/*File=*/nullptr, "_DYNAMIC", STB_WEAK,
|
||||
STV_HIDDEN, STT_NOTYPE,
|
||||
/*Value=*/0, /*Size=*/0, In.Dynamic});
|
||||
Symtab->addSymbol(Defined{/*File=*/nullptr, "_DYNAMIC", STB_WEAK,
|
||||
STV_HIDDEN, STT_NOTYPE,
|
||||
/*Value=*/0, /*Size=*/0, In.Dynamic});
|
||||
|
||||
// Define __rel[a]_iplt_{start,end} symbols if needed.
|
||||
addRelIpltSymbols();
|
||||
|
|
Loading…
Reference in New Issue