SymbolBody and Symbol were separated classes due to a historical reason.
Symbol used to be a pointer to a SymbolBody, and the relationship
between Symbol and SymbolBody was n:1.
r2681780 changed that. Since that patch, SymbolBody and Symbol are
allocated next to each other to improve memory locality, and they have
1:1 relationship now. So, the separation of Symbol and SymbolBody no
longer makes sense.
This patch merges them into one class. In order to avoid updating too
many places, I chose SymbolBody as a unified name. I'll rename it Symbol
in a follow-up patch.
Differential Revision: https://reviews.llvm.org/D39406
llvm-svn: 317006
namespace elf {
class InputFile;
-struct Symbol;
enum ELFKind {
ELFNoneKind,
DenseSet<StringRef> Libs = getExcludeLibs(Args);
bool All = Libs.count("ALL");
- for (InputFile *File : Files) {
+ for (InputFile *File : Files)
if (Optional<StringRef> Archive = getArchiveName(File))
if (All || Libs.count(path::filename(*Archive)))
- for (SymbolBody *SymBody : File->getSymbols())
- if (!SymBody->isLocal())
- SymBody->symbol()->VersionId = VER_NDX_LOCAL;
- }
+ for (SymbolBody *Sym : File->getSymbols())
+ if (!Sym->isLocal())
+ Sym->VersionId = VER_NDX_LOCAL;
}
// Do actual linking. Note that when this function is called,
switch (Sym->st_shndx) {
case SHN_UNDEF:
- return Symtab
- ->addUndefined<ELFT>(Name, /*IsLocal=*/false, Binding, StOther, Type,
- /*CanOmitFromDynSym=*/false, this)
- ->body();
+ return Symtab->addUndefined<ELFT>(Name, /*IsLocal=*/false, Binding, StOther,
+ Type,
+ /*CanOmitFromDynSym=*/false, this);
case SHN_COMMON:
if (Value == 0 || Value >= UINT32_MAX)
fatal(toString(this) + ": common symbol '" + Name +
"' has invalid alignment: " + Twine(Value));
- return Symtab->addCommon(Name, Size, Value, Binding, StOther, Type, this)
- ->body();
+ return Symtab->addCommon(Name, Size, Value, Binding, StOther, Type, this);
}
switch (Binding) {
case STB_WEAK:
case STB_GNU_UNIQUE:
if (Sec == &InputSection::Discarded)
- return Symtab
- ->addUndefined<ELFT>(Name, /*IsLocal=*/false, Binding, StOther, Type,
- /*CanOmitFromDynSym=*/false, this)
- ->body();
- return Symtab
- ->addRegular<ELFT>(Name, StOther, Type, Value, Size, Binding, Sec, this)
- ->body();
+ return Symtab->addUndefined<ELFT>(Name, /*IsLocal=*/false, Binding,
+ StOther, Type,
+ /*CanOmitFromDynSym=*/false, this);
+ return Symtab->addRegular<ELFT>(Name, StOther, Type, Value, Size, Binding,
+ Sec, this);
}
}
template <class ELFT> void ArchiveFile::parse() {
Symbols.reserve(File->getNumberOfSymbols());
for (const Archive::Symbol &Sym : File->symbols())
- Symbols.push_back(
- Symtab->addLazyArchive<ELFT>(Sym.getName(), this, Sym)->body());
+ Symbols.push_back(Symtab->addLazyArchive<ELFT>(Sym.getName(), this, Sym));
}
// Returns a buffer pointing to a member file containing a given symbol.
}
template <class ELFT>
-static Symbol *createBitcodeSymbol(const std::vector<bool> &KeptComdats,
- const lto::InputFile::Symbol &ObjSym,
- BitcodeFile *F) {
+static SymbolBody *createBitcodeSymbol(const std::vector<bool> &KeptComdats,
+ const lto::InputFile::Symbol &ObjSym,
+ BitcodeFile *F) {
StringRef NameRef = Saver.save(ObjSym.getName());
uint32_t Binding = ObjSym.isWeak() ? STB_WEAK : STB_GLOBAL;
KeptComdats.push_back(ComdatGroups.insert(CachedHashStringRef(S)).second);
for (const lto::InputFile::Symbol &ObjSym : Obj->symbols())
- Symbols.push_back(
- createBitcodeSymbol<ELFT>(KeptComdats, ObjSym, this)->body());
+ Symbols.push_back(createBitcodeSymbol<ELFT>(KeptComdats, ObjSym, this));
}
static ELFKind getELFKind(MemoryBufferRef MB) {
}
BitcodeCompiler::BitcodeCompiler() : LTOObj(createLTO()) {
- for (Symbol *Sym : Symtab->getSymbols()) {
- StringRef Name = Sym->body()->getName();
+ for (SymbolBody *Sym : Symtab->getSymbols()) {
+ StringRef Name = Sym->getName();
for (StringRef Prefix : {"__start_", "__stop_"})
if (Name.startswith(Prefix))
UsedStartStop.insert(Name.substr(Prefix.size()));
BitcodeCompiler::~BitcodeCompiler() = default;
-static void undefine(Symbol *S) {
- replaceBody<Undefined>(S, nullptr, S->body()->getName(), /*IsLocal=*/false,
- STV_DEFAULT, S->body()->Type);
+static void undefine(SymbolBody *S) {
+ replaceBody<Undefined>(S, nullptr, S->getName(), /*IsLocal=*/false,
+ STV_DEFAULT, S->Type);
}
void BitcodeCompiler::add(BitcodeFile &F) {
// Provide a resolution to the LTO API for each symbol.
for (const lto::InputFile::Symbol &ObjSym : Obj.symbols()) {
- SymbolBody *B = Syms[SymNum];
- Symbol *Sym = B->symbol();
+ SymbolBody *Sym = Syms[SymNum];
lto::SymbolResolution &R = Resols[SymNum];
++SymNum;
// flags an undefined in IR with a definition in ASM as prevailing.
// Once IRObjectFile is fixed to report only one symbol this hack can
// be removed.
- R.Prevailing = !ObjSym.isUndefined() && B->getFile() == &F;
+ R.Prevailing = !ObjSym.isUndefined() && Sym->getFile() == &F;
// We ask LTO to preserve following global symbols:
// 1) All symbols when doing relocatable link, so that them can be used
// still not final:
// 1) Aliased (with --defsym) or wrapped (with --wrap) symbols.
// 2) Symbols redefined in linker script.
- R.LinkerRedefined = !Sym->CanInline || ScriptSymbols.count(B->getName());
+ R.LinkerRedefined = !Sym->CanInline || ScriptSymbols.count(Sym->getName());
}
checkError(LTOObj->add(std::move(F.Obj), Resols));
}
return;
// Define a symbol.
- Symbol *Sym;
+ SymbolBody *Sym;
uint8_t Visibility = Cmd->Hidden ? STV_HIDDEN : STV_DEFAULT;
std::tie(Sym, std::ignore) = Symtab->insert(Cmd->Name, /*Type*/ 0, Visibility,
/*CanOmitFromDynSym*/ false,
replaceBody<DefinedRegular>(Sym, nullptr, Cmd->Name, /*IsLocal=*/false,
Visibility, STT_NOTYPE, SymValue, 0, Sec);
- Cmd->Sym = cast<DefinedRegular>(Sym->body());
+ Cmd->Sym = cast<DefinedRegular>(Sym);
}
// This function is called from assignAddresses, while we are
// Preserve externally-visible symbols if the symbols defined by this
// file can interrupt other ELF file's symbols at runtime.
- for (Symbol *S : Symtab->getSymbols())
+ for (SymbolBody *S : Symtab->getSymbols())
if (S->includeInDynsym())
- MarkSymbol(S->body());
+ MarkSymbol(S);
// Preserve special sections and those which are specified in linker
// script KEEP command.
for (SharedSymbol *Sym : getSymbolsAt<ELFT>(SS)) {
Sym->CopyRelSec = Sec;
Sym->IsPreemptible = false;
- Sym->symbol()->IsUsedInRegularObj = true;
+ Sym->IsUsedInRegularObj = true;
}
In<ELFT>::RelaDyn->addReloc({Target->CopyRel, Sec, 0, false, SS, 0});
if (Config->UnresolvedSymbols == UnresolvedPolicy::IgnoreAll)
return false;
- if (Sym.isLocal() || !Sym.isUndefined() || Sym.symbol()->isWeak())
+ if (Sym.isLocal() || !Sym.isUndefined() || Sym.isWeak())
return false;
- bool CanBeExternal = Sym.symbol()->computeBinding() != STB_LOCAL &&
- Sym.getVisibility() == STV_DEFAULT;
+ bool CanBeExternal =
+ Sym.computeBinding() != STB_LOCAL && Sym.getVisibility() == STV_DEFAULT;
if (Config->UnresolvedSymbols == UnresolvedPolicy::Ignore && CanBeExternal)
return false;
template <class ELFT>
DefinedRegular *SymbolTable::addAbsolute(StringRef Name, uint8_t Visibility,
uint8_t Binding) {
- Symbol *Sym = addRegular<ELFT>(Name, Visibility, STT_NOTYPE, 0, 0, Binding,
- nullptr, nullptr);
- return cast<DefinedRegular>(Sym->body());
+ SymbolBody *Sym = addRegular<ELFT>(Name, Visibility, STT_NOTYPE, 0, 0,
+ Binding, nullptr, nullptr);
+ return cast<DefinedRegular>(Sym);
}
// Set a flag for --trace-symbol so that we can print out a log message
// Rename SYM as __wrap_SYM. The original symbol is preserved as __real_SYM.
// Used to implement --wrap.
template <class ELFT> void SymbolTable::addSymbolWrap(StringRef Name) {
- SymbolBody *B = find(Name);
- if (!B)
+ SymbolBody *Sym = find(Name);
+ if (!Sym)
return;
- Symbol *Sym = B->symbol();
- Symbol *Real = addUndefined<ELFT>(Saver.save("__real_" + Name));
- Symbol *Wrap = addUndefined<ELFT>(Saver.save("__wrap_" + Name));
+ SymbolBody *Real = addUndefined<ELFT>(Saver.save("__real_" + Name));
+ SymbolBody *Wrap = addUndefined<ELFT>(Saver.save("__wrap_" + Name));
defsym(Real, Sym);
defsym(Sym, Wrap);
return;
}
- defsym(addUndefined<ELFT>(Alias), B->symbol());
+ defsym(addUndefined<ELFT>(Alias), B);
}
// Apply symbol renames created by -wrap and -defsym. The renames are created
// __wrap_foo point to, we just want have __real_foo in the symbol table.
// First make a copy of __real_foo
- std::vector<Symbol> Origs;
+ std::vector<SymbolUnion> Origs;
for (const auto &P : WrapSymbols)
- Origs.push_back(*P.second);
+ Origs.emplace_back(*(SymbolUnion *)P.second);
// Replace __real_foo with foo and foo with __wrap_foo
for (SymbolRenaming &S : Defsyms) {
- S.Dst->body()->copyFrom(S.Src->body());
+ S.Dst->copyFrom(S.Src);
S.Dst->File = S.Src->File;
S.Dst->Binding = S.Binding;
}
// __real_foo into it.
for (unsigned I = 0, N = WrapSymbols.size(); I < N; ++I) {
// We now have two copies of __wrap_foo. Drop one.
- Symbol *Wrap = WrapSymbols[I].first;
+ SymbolBody *Wrap = WrapSymbols[I].first;
Wrap->IsUsedInRegularObj = false;
- Symbol *Real = &Origs[I];
+ auto *Real = (SymbolBody *)&Origs[I];
// If __real_foo was undefined, we don't want it in the symbol table.
- if (!Real->body()->isInCurrentOutput())
+ if (!Real->isInCurrentOutput())
continue;
- auto *NewSym = make<Symbol>();
- memcpy(NewSym, Real, sizeof(Symbol));
+ auto *NewSym = (SymbolBody *)make<SymbolUnion>();
+ memcpy(NewSym, Real, sizeof(SymbolUnion));
SymVector.push_back(NewSym);
}
}
}
// Find an existing symbol or create and insert a new one.
-std::pair<Symbol *, bool> SymbolTable::insert(StringRef Name) {
+std::pair<SymbolBody *, bool> 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>.
//
V = SymIndex((int)SymVector.size(), true);
}
- Symbol *Sym;
+ SymbolBody *Sym;
if (IsNew) {
- Sym = make<Symbol>();
+ Sym = (SymbolBody *)make<SymbolUnion>();
Sym->InVersionScript = false;
Sym->Binding = STB_WEAK;
Sym->Visibility = STV_DEFAULT;
// Find an existing symbol or create and insert a new one, then apply the given
// attributes.
-std::pair<Symbol *, bool> SymbolTable::insert(StringRef Name, uint8_t Type,
- uint8_t Visibility,
- bool CanOmitFromDynSym,
- InputFile *File) {
- Symbol *S;
+std::pair<SymbolBody *, bool> SymbolTable::insert(StringRef Name, uint8_t Type,
+ uint8_t Visibility,
+ bool CanOmitFromDynSym,
+ InputFile *File) {
+ SymbolBody *S;
bool WasInserted;
std::tie(S, WasInserted) = insert(Name);
if (!File || File->kind() == InputFile::ObjKind)
S->IsUsedInRegularObj = true;
- if (!WasInserted && S->body()->Type != SymbolBody::UnknownType &&
- ((Type == STT_TLS) != S->body()->isTls())) {
- error("TLS attribute mismatch: " + toString(*S->body()) +
- "\n>>> defined in " + toString(S->File) + "\n>>> defined in " +
- toString(File));
+ if (!WasInserted && S->Type != SymbolBody::UnknownType &&
+ ((Type == STT_TLS) != S->isTls())) {
+ error("TLS attribute mismatch: " + toString(*S) + "\n>>> defined in " +
+ toString(S->File) + "\n>>> defined in " + toString(File));
}
return {S, WasInserted};
}
-template <class ELFT> Symbol *SymbolTable::addUndefined(StringRef Name) {
+template <class ELFT> SymbolBody *SymbolTable::addUndefined(StringRef Name) {
return addUndefined<ELFT>(Name, /*IsLocal=*/false, STB_GLOBAL, STV_DEFAULT,
/*Type*/ 0,
/*CanOmitFromDynSym*/ false, /*File*/ nullptr);
static uint8_t getVisibility(uint8_t StOther) { return StOther & 3; }
template <class ELFT>
-Symbol *SymbolTable::addUndefined(StringRef Name, bool IsLocal, uint8_t Binding,
- uint8_t StOther, uint8_t Type,
- bool CanOmitFromDynSym, InputFile *File) {
- Symbol *S;
+SymbolBody *SymbolTable::addUndefined(StringRef Name, bool IsLocal,
+ uint8_t Binding, uint8_t StOther,
+ uint8_t Type, bool CanOmitFromDynSym,
+ InputFile *File) {
+ SymbolBody *S;
bool WasInserted;
uint8_t Visibility = getVisibility(StOther);
std::tie(S, WasInserted) =
insert(Name, Type, Visibility, CanOmitFromDynSym, File);
// An undefined symbol with non default visibility must be satisfied
// in the same DSO.
- if (WasInserted ||
- (isa<SharedSymbol>(S->body()) && Visibility != STV_DEFAULT)) {
+ if (WasInserted || (isa<SharedSymbol>(S) && Visibility != STV_DEFAULT)) {
S->Binding = Binding;
replaceBody<Undefined>(S, File, Name, IsLocal, StOther, Type);
return S;
}
if (Binding != STB_WEAK) {
- SymbolBody *B = S->body();
- if (!B->isInCurrentOutput())
+ if (!S->isInCurrentOutput())
S->Binding = Binding;
- if (auto *SS = dyn_cast<SharedSymbol>(B))
+ if (auto *SS = dyn_cast<SharedSymbol>(S))
SS->getFile<ELFT>()->IsUsed = true;
}
- if (auto *L = dyn_cast<Lazy>(S->body())) {
+ if (auto *L = dyn_cast<Lazy>(S)) {
// An undefined weak will not fetch archive members. See comment on Lazy in
// Symbols.h for the details.
if (S->isWeak())
// FIXME: If users can transition to using
// .symver foo,foo@@@VER
// we can delete this hack.
-static int compareVersion(Symbol *S, StringRef Name) {
+static int compareVersion(SymbolBody *S, StringRef Name) {
bool A = Name.contains("@@");
- bool B = S->body()->getName().contains("@@");
+ bool B = S->getName().contains("@@");
if (A && !B)
return 1;
if (!A && B)
// We have a new defined symbol with the specified binding. Return 1 if the new
// symbol should win, -1 if the new symbol should lose, or 0 if both symbols are
// strong defined symbols.
-static int compareDefined(Symbol *S, bool WasInserted, uint8_t Binding,
+static int compareDefined(SymbolBody *S, bool WasInserted, uint8_t Binding,
StringRef Name) {
if (WasInserted)
return 1;
- SymbolBody *Body = S->body();
- if (!Body->isInCurrentOutput())
+ if (!S->isInCurrentOutput())
return 1;
-
if (int R = compareVersion(S, Name))
return R;
-
if (Binding == STB_WEAK)
return -1;
if (S->isWeak())
// We have a new non-common defined symbol with the specified binding. Return 1
// if the new symbol should win, -1 if the new symbol should lose, or 0 if there
// is a conflict. If the new symbol wins, also update the binding.
-static int compareDefinedNonCommon(Symbol *S, bool WasInserted, uint8_t Binding,
- bool IsAbsolute, uint64_t Value,
- StringRef Name) {
+static int compareDefinedNonCommon(SymbolBody *S, bool WasInserted,
+ uint8_t Binding, bool IsAbsolute,
+ uint64_t Value, StringRef Name) {
if (int Cmp = compareDefined(S, WasInserted, Binding, Name)) {
if (Cmp > 0)
S->Binding = Binding;
return Cmp;
}
- SymbolBody *B = S->body();
- if (isa<DefinedCommon>(B)) {
+ if (isa<DefinedCommon>(S)) {
// Non-common symbols take precedence over common symbols.
if (Config->WarnCommon)
- warn("common " + S->body()->getName() + " is overridden");
+ warn("common " + S->getName() + " is overridden");
return 1;
- } else if (auto *R = dyn_cast<DefinedRegular>(B)) {
+ }
+ if (auto *R = dyn_cast<DefinedRegular>(S)) {
if (R->Section == nullptr && Binding == STB_GLOBAL && IsAbsolute &&
R->Value == Value)
return -1;
return 0;
}
-Symbol *SymbolTable::addCommon(StringRef N, uint64_t Size, uint32_t Alignment,
- uint8_t Binding, uint8_t StOther, uint8_t Type,
- InputFile *File) {
- Symbol *S;
+SymbolBody *SymbolTable::addCommon(StringRef N, uint64_t Size,
+ uint32_t Alignment, uint8_t Binding,
+ uint8_t StOther, uint8_t Type,
+ InputFile *File) {
+ SymbolBody *S;
bool WasInserted;
std::tie(S, WasInserted) = insert(N, Type, getVisibility(StOther),
/*CanOmitFromDynSym*/ false, File);
S->Binding = Binding;
replaceBody<DefinedCommon>(S, File, N, Size, Alignment, StOther, Type);
} else if (Cmp == 0) {
- auto *C = dyn_cast<DefinedCommon>(S->body());
+ auto *C = dyn_cast<DefinedCommon>(S);
if (!C) {
// Non-common symbols take precedence over common symbols.
if (Config->WarnCommon)
- warn("common " + S->body()->getName() + " is overridden");
+ warn("common " + S->getName() + " is overridden");
return S;
}
if (Config->WarnCommon)
- warn("multiple common of " + S->body()->getName());
+ warn("multiple common of " + S->getName());
Alignment = C->Alignment = std::max(C->Alignment, Alignment);
if (Size > C->Size)
}
template <typename ELFT>
-Symbol *SymbolTable::addRegular(StringRef Name, uint8_t StOther, uint8_t Type,
- uint64_t Value, uint64_t Size, uint8_t Binding,
- SectionBase *Section, InputFile *File) {
- Symbol *S;
+SymbolBody *SymbolTable::addRegular(StringRef Name, uint8_t StOther,
+ uint8_t Type, uint64_t Value, uint64_t Size,
+ uint8_t Binding, SectionBase *Section,
+ InputFile *File) {
+ SymbolBody *S;
bool WasInserted;
std::tie(S, WasInserted) = insert(Name, Type, getVisibility(StOther),
/*CanOmitFromDynSym*/ false, File);
replaceBody<DefinedRegular>(S, File, Name, /*IsLocal=*/false, StOther, Type,
Value, Size, Section);
else if (Cmp == 0)
- reportDuplicate<ELFT>(S->body(),
- dyn_cast_or_null<InputSectionBase>(Section), Value);
+ reportDuplicate<ELFT>(S, dyn_cast_or_null<InputSectionBase>(Section),
+ Value);
return S;
}
// DSO symbols do not affect visibility in the output, so we pass STV_DEFAULT
// as the visibility, which will leave the visibility in the symbol table
// unchanged.
- Symbol *S;
+ SymbolBody *S;
bool WasInserted;
std::tie(S, WasInserted) = insert(Name, Sym.getType(), STV_DEFAULT,
/*CanOmitFromDynSym*/ true, File);
if (Sym.getVisibility() == STV_DEFAULT)
S->ExportDynamic = true;
- SymbolBody *Body = S->body();
// An undefined symbol with non default visibility must be satisfied
// in the same DSO.
- if (WasInserted || ((Body->isUndefined() || Body->isLazy()) &&
- Body->getVisibility() == STV_DEFAULT)) {
+ if (WasInserted || ((S->isUndefined() || S->isLazy()) &&
+ S->getVisibility() == STV_DEFAULT)) {
replaceBody<SharedSymbol>(S, File, Name, Sym.st_other, Sym.getType(),
Sym.st_value, Sym.st_size, Alignment, Verdef);
if (!S->isWeak())
}
}
-Symbol *SymbolTable::addBitcode(StringRef Name, uint8_t Binding,
- uint8_t StOther, uint8_t Type,
- bool CanOmitFromDynSym, BitcodeFile *F) {
- Symbol *S;
+SymbolBody *SymbolTable::addBitcode(StringRef Name, uint8_t Binding,
+ uint8_t StOther, uint8_t Type,
+ bool CanOmitFromDynSym, BitcodeFile *F) {
+ SymbolBody *S;
bool WasInserted;
std::tie(S, WasInserted) =
insert(Name, Type, getVisibility(StOther), CanOmitFromDynSym, F);
replaceBody<DefinedRegular>(S, F, Name, /*IsLocal=*/false, StOther, Type, 0,
0, nullptr);
else if (Cmp == 0)
- reportDuplicate(S->body(), F);
+ reportDuplicate(S, F);
return S;
}
SymIndex V = It->second;
if (V.Idx == -1)
return nullptr;
- return SymVector[V.Idx]->body();
+ return SymVector[V.Idx];
}
-void SymbolTable::defsym(Symbol *Dst, Symbol *Src) {
+void SymbolTable::defsym(SymbolBody *Dst, SymbolBody *Src) {
// We want to tell LTO not to inline Dst symbol because LTO doesn't
// know the final symbol contents after renaming.
Dst->CanInline = false;
}
template <class ELFT>
-Symbol *SymbolTable::addLazyArchive(StringRef Name, ArchiveFile *F,
- const object::Archive::Symbol Sym) {
- Symbol *S;
+SymbolBody *SymbolTable::addLazyArchive(StringRef Name, ArchiveFile *F,
+ const object::Archive::Symbol Sym) {
+ SymbolBody *S;
bool WasInserted;
std::tie(S, WasInserted) = insert(Name);
if (WasInserted) {
replaceBody<LazyArchive>(S, F, Sym, SymbolBody::UnknownType);
return S;
}
- if (!S->body()->isUndefined())
+ if (!S->isUndefined())
return S;
// An undefined weak will not fetch archive members. See comment on Lazy in
// Symbols.h for the details.
if (S->isWeak()) {
- replaceBody<LazyArchive>(S, F, Sym, S->body()->Type);
+ replaceBody<LazyArchive>(S, F, Sym, S->Type);
return S;
}
std::pair<MemoryBufferRef, uint64_t> MBInfo = F->getMember(&Sym);
template <class ELFT>
void SymbolTable::addLazyObject(StringRef Name, LazyObjFile &Obj) {
- Symbol *S;
+ SymbolBody *S;
bool WasInserted;
std::tie(S, WasInserted) = insert(Name);
if (WasInserted) {
replaceBody<LazyObject>(S, &Obj, Name, SymbolBody::UnknownType);
return;
}
- if (!S->body()->isUndefined())
+ if (!S->isUndefined())
return;
// See comment for addLazyArchive above.
if (S->isWeak())
- replaceBody<LazyObject>(S, &Obj, Name, S->body()->Type);
+ replaceBody<LazyObject>(S, &Obj, Name, S->Type);
else if (InputFile *F = Obj.fetch())
addFile<ELFT>(F);
}
if (SymbolBody *B = find(Name)) {
// Mark the symbol not to be eliminated by LTO
// even if it is a bitcode symbol.
- B->symbol()->IsUsedInRegularObj = true;
+ B->IsUsedInRegularObj = true;
if (auto *L = dyn_cast_or_null<Lazy>(B))
if (InputFile *File = L->fetch())
addFile<ELFT>(File);
SymbolBody *Sym = find(U);
if (!Sym || !Sym->isDefined())
continue;
- Sym->symbol()->ExportDynamic = true;
+ Sym->ExportDynamic = true;
// If -dynamic-list is given, the default version is set to
// VER_NDX_LOCAL, which prevents a symbol to be exported via .dynsym.
// Set to VER_NDX_GLOBAL so the symbol will be handled as if it were
// specified by -dynamic-list.
- Sym->symbol()->VersionId = VER_NDX_GLOBAL;
+ Sym->VersionId = VER_NDX_GLOBAL;
}
}
}
StringMap<std::vector<SymbolBody *>> &SymbolTable::getDemangledSyms() {
if (!DemangledSyms) {
DemangledSyms.emplace();
- for (Symbol *Sym : SymVector) {
- SymbolBody *B = Sym->body();
- if (!B->isInCurrentOutput())
+ for (SymbolBody *Sym : SymVector) {
+ if (!Sym->isInCurrentOutput())
continue;
- if (Optional<std::string> S = demangle(B->getName()))
- (*DemangledSyms)[*S].push_back(B);
+ if (Optional<std::string> S = demangle(Sym->getName()))
+ (*DemangledSyms)[*S].push_back(Sym);
else
- (*DemangledSyms)[B->getName()].push_back(B);
+ (*DemangledSyms)[Sym->getName()].push_back(Sym);
}
}
return *DemangledSyms;
return Res;
}
- for (Symbol *Sym : SymVector) {
- SymbolBody *B = Sym->body();
- if (B->isInCurrentOutput() && M.match(B->getName()))
- Res.push_back(B);
- }
+ for (SymbolBody *Sym : SymVector)
+ if (Sym->isInCurrentOutput() && M.match(Sym->getName()))
+ Res.push_back(Sym);
return Res;
}
for (SymbolBody *B : Syms) {
if (!Config->Shared)
- B->symbol()->ExportDynamic = true;
- else if (B->symbol()->includeInDynsym())
+ B->ExportDynamic = true;
+ else if (B->includeInDynsym())
B->IsPreemptible = true;
}
}
}
// Assign the version.
- for (SymbolBody *B : Syms) {
+ for (SymbolBody *Sym : Syms) {
// Skip symbols containing version info because symbol versions
// specified by symbol names take precedence over version scripts.
// See parseSymbolVersion().
- if (B->getName().contains('@'))
+ if (Sym->getName().contains('@'))
continue;
- Symbol *Sym = B->symbol();
if (Sym->InVersionScript)
warn("duplicate symbol '" + Ver.Name + "' in version script");
Sym->VersionId = VersionId;
// so we set a version to a symbol only if no version has been assigned
// to the symbol. This behavior is compatible with GNU.
for (SymbolBody *B : findAllByVersion(Ver))
- if (B->symbol()->VersionId == Config->DefaultSymbolVersion)
- B->symbol()->VersionId = VersionId;
+ if (B->VersionId == Config->DefaultSymbolVersion)
+ B->VersionId = VersionId;
}
// This function processes version scripts by updating VersionId
// Symbol themselves might know their versions because symbols
// can contain versions in the form of <name>@<version>.
// Let them parse and update their names to exclude version suffix.
- for (Symbol *Sym : SymVector)
- Sym->body()->parseSymbolVersion();
+ for (SymbolBody *Sym : SymVector)
+ Sym->parseSymbolVersion();
}
template void SymbolTable::addSymbolWrap<ELF32LE>(StringRef);
template void SymbolTable::addSymbolWrap<ELF64LE>(StringRef);
template void SymbolTable::addSymbolWrap<ELF64BE>(StringRef);
-template Symbol *SymbolTable::addUndefined<ELF32LE>(StringRef);
-template Symbol *SymbolTable::addUndefined<ELF32BE>(StringRef);
-template Symbol *SymbolTable::addUndefined<ELF64LE>(StringRef);
-template Symbol *SymbolTable::addUndefined<ELF64BE>(StringRef);
-
-template Symbol *SymbolTable::addUndefined<ELF32LE>(StringRef, bool, uint8_t,
- uint8_t, uint8_t, bool,
- InputFile *);
-template Symbol *SymbolTable::addUndefined<ELF32BE>(StringRef, bool, uint8_t,
- uint8_t, uint8_t, bool,
- InputFile *);
-template Symbol *SymbolTable::addUndefined<ELF64LE>(StringRef, bool, uint8_t,
- uint8_t, uint8_t, bool,
- InputFile *);
-template Symbol *SymbolTable::addUndefined<ELF64BE>(StringRef, bool, uint8_t,
- uint8_t, uint8_t, bool,
- InputFile *);
+template SymbolBody *SymbolTable::addUndefined<ELF32LE>(StringRef);
+template SymbolBody *SymbolTable::addUndefined<ELF32BE>(StringRef);
+template SymbolBody *SymbolTable::addUndefined<ELF64LE>(StringRef);
+template SymbolBody *SymbolTable::addUndefined<ELF64BE>(StringRef);
+
+template SymbolBody *SymbolTable::addUndefined<ELF32LE>(StringRef, bool,
+ uint8_t, uint8_t,
+ uint8_t, bool,
+ InputFile *);
+template SymbolBody *SymbolTable::addUndefined<ELF32BE>(StringRef, bool,
+ uint8_t, uint8_t,
+ uint8_t, bool,
+ InputFile *);
+template SymbolBody *SymbolTable::addUndefined<ELF64LE>(StringRef, bool,
+ uint8_t, uint8_t,
+ uint8_t, bool,
+ InputFile *);
+template SymbolBody *SymbolTable::addUndefined<ELF64BE>(StringRef, bool,
+ uint8_t, uint8_t,
+ uint8_t, bool,
+ InputFile *);
template void SymbolTable::addSymbolAlias<ELF32LE>(StringRef, StringRef);
template void SymbolTable::addSymbolAlias<ELF32BE>(StringRef, StringRef);
template void SymbolTable::addCombinedLTOObject<ELF64LE>();
template void SymbolTable::addCombinedLTOObject<ELF64BE>();
-template Symbol *SymbolTable::addRegular<ELF32LE>(StringRef, uint8_t, uint8_t,
- uint64_t, uint64_t, uint8_t,
- SectionBase *, InputFile *);
-template Symbol *SymbolTable::addRegular<ELF32BE>(StringRef, uint8_t, uint8_t,
- uint64_t, uint64_t, uint8_t,
- SectionBase *, InputFile *);
-template Symbol *SymbolTable::addRegular<ELF64LE>(StringRef, uint8_t, uint8_t,
- uint64_t, uint64_t, uint8_t,
- SectionBase *, InputFile *);
-template Symbol *SymbolTable::addRegular<ELF64BE>(StringRef, uint8_t, uint8_t,
- uint64_t, uint64_t, uint8_t,
- SectionBase *, InputFile *);
+template SymbolBody *
+SymbolTable::addRegular<ELF32LE>(StringRef, uint8_t, uint8_t, uint64_t,
+ uint64_t, uint8_t, SectionBase *, InputFile *);
+template SymbolBody *
+SymbolTable::addRegular<ELF32BE>(StringRef, uint8_t, uint8_t, uint64_t,
+ uint64_t, uint8_t, SectionBase *, InputFile *);
+template SymbolBody *
+SymbolTable::addRegular<ELF64LE>(StringRef, uint8_t, uint8_t, uint64_t,
+ uint64_t, uint8_t, SectionBase *, InputFile *);
+template SymbolBody *
+SymbolTable::addRegular<ELF64BE>(StringRef, uint8_t, uint8_t, uint64_t,
+ uint64_t, uint8_t, SectionBase *, InputFile *);
template DefinedRegular *SymbolTable::addAbsolute<ELF32LE>(StringRef, uint8_t,
uint8_t);
template DefinedRegular *SymbolTable::addAbsolute<ELF64BE>(StringRef, uint8_t,
uint8_t);
-template Symbol *
+template SymbolBody *
SymbolTable::addLazyArchive<ELF32LE>(StringRef, ArchiveFile *,
const object::Archive::Symbol);
-template Symbol *
+template SymbolBody *
SymbolTable::addLazyArchive<ELF32BE>(StringRef, ArchiveFile *,
const object::Archive::Symbol);
-template Symbol *
+template SymbolBody *
SymbolTable::addLazyArchive<ELF64LE>(StringRef, ArchiveFile *,
const object::Archive::Symbol);
-template Symbol *
+template SymbolBody *
SymbolTable::addLazyArchive<ELF64BE>(StringRef, ArchiveFile *,
const object::Archive::Symbol);
namespace lld {
namespace elf {
-struct Symbol;
-
// SymbolTable is a bucket of all known symbols, including defined,
// undefined, or lazy symbols (the last one is symbols in archive
// files whose archive members are not yet loaded).
template <class ELFT> void addSymbolWrap(StringRef Name);
void applySymbolRenames();
- ArrayRef<Symbol *> getSymbols() const { return SymVector; }
+ ArrayRef<SymbolBody *> getSymbols() const { return SymVector; }
template <class ELFT>
DefinedRegular *addAbsolute(StringRef Name,
uint8_t Visibility = llvm::ELF::STV_HIDDEN,
uint8_t Binding = llvm::ELF::STB_GLOBAL);
- template <class ELFT> Symbol *addUndefined(StringRef Name);
+ template <class ELFT> SymbolBody *addUndefined(StringRef Name);
template <class ELFT>
- Symbol *addUndefined(StringRef Name, bool IsLocal, uint8_t Binding,
- uint8_t StOther, uint8_t Type, bool CanOmitFromDynSym,
- InputFile *File);
+ SymbolBody *addUndefined(StringRef Name, bool IsLocal, uint8_t Binding,
+ uint8_t StOther, uint8_t Type,
+ bool CanOmitFromDynSym, InputFile *File);
template <class ELFT>
- Symbol *addRegular(StringRef Name, uint8_t StOther, uint8_t Type,
- uint64_t Value, uint64_t Size, uint8_t Binding,
- SectionBase *Section, InputFile *File);
+ SymbolBody *addRegular(StringRef Name, uint8_t StOther, uint8_t Type,
+ uint64_t Value, uint64_t Size, uint8_t Binding,
+ SectionBase *Section, InputFile *File);
template <class ELFT>
void addShared(StringRef Name, SharedFile<ELFT> *F,
const typename ELFT::Verdef *Verdef);
template <class ELFT>
- Symbol *addLazyArchive(StringRef Name, ArchiveFile *F,
- const llvm::object::Archive::Symbol S);
+ SymbolBody *addLazyArchive(StringRef Name, ArchiveFile *F,
+ const llvm::object::Archive::Symbol S);
template <class ELFT> void addLazyObject(StringRef Name, LazyObjFile &Obj);
- Symbol *addBitcode(StringRef Name, uint8_t Binding, uint8_t StOther,
- uint8_t Type, bool CanOmitFromDynSym, BitcodeFile *File);
+ SymbolBody *addBitcode(StringRef Name, uint8_t Binding, uint8_t StOther,
+ uint8_t Type, bool CanOmitFromDynSym,
+ BitcodeFile *File);
- Symbol *addCommon(StringRef Name, uint64_t Size, uint32_t Alignment,
- uint8_t Binding, uint8_t StOther, uint8_t Type,
- InputFile *File);
+ SymbolBody *addCommon(StringRef Name, uint64_t Size, uint32_t Alignment,
+ uint8_t Binding, uint8_t StOther, uint8_t Type,
+ InputFile *File);
- std::pair<Symbol *, bool> insert(StringRef Name);
- std::pair<Symbol *, bool> insert(StringRef Name, uint8_t Type,
- uint8_t Visibility, bool CanOmitFromDynSym,
- InputFile *File);
+ std::pair<SymbolBody *, bool> insert(StringRef Name);
+ std::pair<SymbolBody *, bool> insert(StringRef Name, uint8_t Type,
+ uint8_t Visibility,
+ bool CanOmitFromDynSym, InputFile *File);
template <class ELFT> void fetchIfLazy(StringRef Name);
template <class ELFT> void scanShlibUndefined();
private:
std::vector<SymbolBody *> findByVersion(SymbolVersion Ver);
std::vector<SymbolBody *> findAllByVersion(SymbolVersion Ver);
- void defsym(Symbol *Dst, Symbol *Src);
+ void defsym(SymbolBody *Dst, SymbolBody *Src);
llvm::StringMap<std::vector<SymbolBody *>> &getDemangledSyms();
void handleAnonymousVersion();
// FIXME: Experiment with passing in a custom hashing or sorting the symbols
// once symbol resolution is finished.
llvm::DenseMap<llvm::CachedHashStringRef, SymIndex> Symtab;
- std::vector<Symbol *> SymVector;
+ std::vector<SymbolBody *> SymVector;
// Comdat groups define "link once" sections. If two comdat groups have the
// same name, only one of them is linked, and the other is ignored. This set
llvm::Optional<llvm::StringMap<std::vector<SymbolBody *>>> DemangledSyms;
struct SymbolRenaming {
- Symbol *Dst;
- Symbol *Src;
+ SymbolBody *Dst;
+ SymbolBody *Src;
uint8_t Binding;
};
std::vector<SymbolRenaming> Defsyms;
// For -wrap.
- std::vector<std::pair<Symbol *, Symbol *>> WrapSymbols;
+ std::vector<std::pair<SymbolBody *, SymbolBody *>> WrapSymbols;
// For LTO.
std::unique_ptr<BitcodeCompiler> LTO;
return 0;
case SymbolBody::LazyArchiveKind:
case SymbolBody::LazyObjectKind:
- assert(Body.symbol()->IsUsedInRegularObj && "lazy symbol reached writer");
+ assert(Body.IsUsedInRegularObj && "lazy symbol reached writer");
return 0;
}
llvm_unreachable("invalid symbol kind");
// Returns true if this is a weak undefined symbol.
bool SymbolBody::isUndefWeak() const {
// See comment on Lazy in Symbols.h for the details.
- return !isLocal() && symbol()->isWeak() && (isUndefined() || isLazy());
+ return !isLocal() && isWeak() && (isUndefined() || isLazy());
}
InputFile *SymbolBody::getFile() const {
// SymbolBody, or having a special absolute section if needed.
return Sec ? cast<InputSectionBase>(Sec)->File : nullptr;
}
- return symbol()->File;
+ return File;
}
// Overwrites all attributes with Other's so that this symbol becomes
// an alias to Other. This is useful for handling some options such as
// --wrap.
void SymbolBody::copyFrom(SymbolBody *Other) {
- memcpy(symbol()->Body.buffer, Other->symbol()->Body.buffer,
- sizeof(Symbol::Body));
+ SymbolBody Sym = *this;
+ memcpy(this, Other, sizeof(SymbolUnion));
+
+ Binding = Sym.Binding;
+ VersionId = Sym.VersionId;
+ Visibility = Sym.Visibility;
+ IsUsedInRegularObj = Sym.IsUsedInRegularObj;
+ ExportDynamic = Sym.ExportDynamic;
+ CanInline = Sym.CanInline;
+ Traced = Sym.Traced;
+ InVersionScript = Sym.InVersionScript;
}
uint64_t SymbolBody::getVA(int64_t Addend) const {
continue;
if (IsDefault)
- symbol()->VersionId = Ver.Id;
+ VersionId = Ver.Id;
else
- symbol()->VersionId = Ver.Id | VERSYM_HIDDEN;
+ VersionId = Ver.Id | VERSYM_HIDDEN;
return;
}
InputFile *LazyObject::fetch() { return getFile()->fetch(); }
-uint8_t Symbol::computeBinding() const {
+uint8_t SymbolBody::computeBinding() const {
if (Config->Relocatable)
return Binding;
if (Visibility != STV_DEFAULT && Visibility != STV_PROTECTED)
return STB_LOCAL;
- if (VersionId == VER_NDX_LOCAL && body()->isInCurrentOutput())
+ if (VersionId == VER_NDX_LOCAL && isInCurrentOutput())
return STB_LOCAL;
if (Config->NoGnuUnique && Binding == STB_GNU_UNIQUE)
return STB_GLOBAL;
return Binding;
}
-bool Symbol::includeInDynsym() const {
+bool SymbolBody::includeInDynsym() const {
if (!Config->HasDynSymTab)
return false;
if (computeBinding() == STB_LOCAL)
return false;
- if (!body()->isInCurrentOutput())
+ if (!isInCurrentOutput())
return true;
return ExportDynamic;
}
// Print out a log message for --trace-symbol.
-void elf::printTraceSymbol(Symbol *Sym) {
- SymbolBody *B = Sym->body();
+void elf::printTraceSymbol(SymbolBody *Sym) {
std::string S;
- if (B->isUndefined())
+ if (Sym->isUndefined())
S = ": reference to ";
- else if (B->isCommon())
+ else if (Sym->isCommon())
S = ": common definition of ";
- else if (B->isLazy())
+ else if (Sym->isLazy())
S = ": lazy definition of ";
- else if (B->isShared())
+ else if (Sym->isShared())
S = ": shared definition of ";
else
S = ": definition of ";
- message(toString(Sym->File) + S + B->getName());
+ message(toString(Sym->File) + S + Sym->getName());
}
// Returns a symbol for an error message.
class OutputSection;
template <class ELFT> class SharedFile;
-struct Symbol;
-
// The base class for real symbol classes.
class SymbolBody {
public:
};
SymbolBody(Kind K) : SymbolKind(K) {}
+ Kind kind() const { return static_cast<Kind>(SymbolKind); }
- Symbol *symbol();
- const Symbol *symbol() const {
- return const_cast<SymbolBody *>(this)->symbol();
- }
+ // Symbol binding. This is not overwritten by replaceSymbol to track
+ // changes during resolution. In particular:
+ // - An undefined weak is still weak when it resolves to a shared library.
+ // - An undefined weak will not fetch archive members, but we have to
+ // remember it is weak.
+ uint8_t Binding;
- Kind kind() const { return static_cast<Kind>(SymbolKind); }
+ // Version definition index.
+ uint16_t VersionId;
+
+ // Symbol visibility. This is the computed minimum visibility of all
+ // observed non-DSO symbols.
+ unsigned Visibility : 2;
+
+ // True if the symbol was used for linking and thus need to be added to the
+ // output file's symbol table. This is true for all symbols except for
+ // unreferenced DSO symbols and bitcode symbols that are unreferenced except
+ // by other bitcode objects.
+ unsigned IsUsedInRegularObj : 1;
+
+ // If this flag is true and the symbol has protected or default visibility, it
+ // will appear in .dynsym. This flag is set by interposable DSO symbols in
+ // executables, by most symbols in DSOs and executables built with
+ // --export-dynamic, and by dynamic lists.
+ unsigned ExportDynamic : 1;
+
+ // False if LTO shouldn't inline whatever this symbol points to. If a symbol
+ // is overwritten after LTO, LTO shouldn't inline the symbol because it
+ // doesn't know the final contents of the symbol.
+ unsigned CanInline : 1;
+
+ // True if this symbol is specified by --trace-symbol option.
+ unsigned Traced : 1;
+
+ // This symbol version was found in a version script.
+ unsigned InVersionScript : 1;
+
+ // The file from which this symbol was created.
+ InputFile *File = nullptr;
+
+ bool includeInDynsym() const;
+ uint8_t computeBinding() const;
+ bool isWeak() const { return Binding == llvm::ELF::STB_WEAK; }
bool isUndefined() const { return SymbolKind == UndefinedKind; }
bool isDefined() const { return SymbolKind <= DefinedLast; }
static DefinedRegular *MipsLocalGp;
};
-// A real symbol object, SymbolBody, is usually stored within a Symbol. There's
-// always one Symbol for each symbol name. The resolver updates the SymbolBody
-// stored in the Body field of this object as it resolves symbols. Symbol also
-// holds computed properties of symbol names.
-struct Symbol {
- // Symbol binding. This is on the Symbol to track changes during resolution.
- // In particular:
- // An undefined weak is still weak when it resolves to a shared library.
- // An undefined weak will not fetch archive members, but we have to remember
- // it is weak.
- uint8_t Binding;
-
- // Version definition index.
- uint16_t VersionId;
-
- // Symbol visibility. This is the computed minimum visibility of all
- // observed non-DSO symbols.
- unsigned Visibility : 2;
-
- // True if the symbol was used for linking and thus need to be added to the
- // output file's symbol table. This is true for all symbols except for
- // unreferenced DSO symbols and bitcode symbols that are unreferenced except
- // by other bitcode objects.
- unsigned IsUsedInRegularObj : 1;
-
- // If this flag is true and the symbol has protected or default visibility, it
- // will appear in .dynsym. This flag is set by interposable DSO symbols in
- // executables, by most symbols in DSOs and executables built with
- // --export-dynamic, and by dynamic lists.
- unsigned ExportDynamic : 1;
-
- // False if LTO shouldn't inline whatever this symbol points to. If a symbol
- // is overwritten after LTO, LTO shouldn't inline the symbol because it
- // doesn't know the final contents of the symbol.
- unsigned CanInline : 1;
-
- // True if this symbol is specified by --trace-symbol option.
- unsigned Traced : 1;
-
- // This symbol version was found in a version script.
- unsigned InVersionScript : 1;
-
- // The file from which this symbol was created.
- InputFile *File = nullptr;
-
- bool includeInDynsym() const;
- uint8_t computeBinding() const;
- bool isWeak() const { return Binding == llvm::ELF::STB_WEAK; }
-
- // This field is used to store the Symbol's SymbolBody. This instantiation of
- // AlignedCharArrayUnion gives us a struct with a char array field that is
- // large and aligned enough to store any derived class of SymbolBody.
- llvm::AlignedCharArrayUnion<DefinedCommon, DefinedRegular, Undefined,
- SharedSymbol, LazyArchive, LazyObject>
- Body;
-
- SymbolBody *body() { return reinterpret_cast<SymbolBody *>(Body.buffer); }
- const SymbolBody *body() const { return const_cast<Symbol *>(this)->body(); }
+// A buffer class that is large enough to hold any SymbolBody-derived
+// object. We allocate memory using this class and instantiate a symbol
+// using the placement new.
+union SymbolUnion {
+ alignas(DefinedRegular) char A[sizeof(DefinedRegular)];
+ alignas(DefinedCommon) char B[sizeof(DefinedCommon)];
+ 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);
+void printTraceSymbol(SymbolBody *Sym);
template <typename T, typename... ArgT>
-void replaceBody(Symbol *S, InputFile *File, ArgT &&... Arg) {
- static_assert(sizeof(T) <= sizeof(S->Body), "Body too small");
- static_assert(alignof(T) <= alignof(decltype(S->Body)),
- "Body not aligned enough");
+void replaceBody(SymbolBody *S, InputFile *File, ArgT &&... Arg) {
+ static_assert(sizeof(T) <= sizeof(SymbolUnion), "SymbolUnion too small");
+ static_assert(alignof(T) <= alignof(SymbolUnion),
+ "SymbolUnion not aligned enough");
assert(static_cast<SymbolBody *>(static_cast<T *>(nullptr)) == nullptr &&
"Not a SymbolBody");
+
+ SymbolBody Sym = *S;
+
+ new (S) T(std::forward<ArgT>(Arg)...);
S->File = File;
- new (S->Body.buffer) T(std::forward<ArgT>(Arg)...);
+
+ S->Binding = Sym.Binding;
+ S->VersionId = Sym.VersionId;
+ S->Visibility = Sym.Visibility;
+ S->IsUsedInRegularObj = Sym.IsUsedInRegularObj;
+ S->ExportDynamic = Sym.ExportDynamic;
+ S->CanInline = Sym.CanInline;
+ S->Traced = Sym.Traced;
+ S->InVersionScript = Sym.InVersionScript;
// Print out a log message if --trace-symbol was specified.
// This is for debugging.
if (S->Traced)
printTraceSymbol(S);
}
-
-inline Symbol *SymbolBody::symbol() {
- assert(!isLocal());
- return reinterpret_cast<Symbol *>(reinterpret_cast<char *>(this) -
- offsetof(Symbol, Body));
-}
} // namespace elf
std::string toString(const elf::SymbolBody &B);
// Create a .bss section for each common symbol and replace the common symbol
// with a DefinedRegular symbol.
template <class ELFT> void elf::createCommonSections() {
- for (Symbol *S : Symtab->getSymbols()) {
- auto *Sym = dyn_cast<DefinedCommon>(S->body());
+ for (SymbolBody *S : Symtab->getSymbols()) {
+ auto *Sym = dyn_cast<DefinedCommon>(S);
if (!Sym)
continue;
// move all local symbols before global symbols.
auto It = std::stable_partition(
Symbols.begin(), Symbols.end(), [](const SymbolTableEntry &S) {
- return S.Symbol->isLocal() ||
- S.Symbol->symbol()->computeBinding() == STB_LOCAL;
+ return S.Symbol->isLocal() || S.Symbol->computeBinding() == STB_LOCAL;
});
size_t NumLocals = It - Symbols.begin();
getParent()->Info = NumLocals + 1;
if (Body->isLocal()) {
ESym->setBindingAndType(STB_LOCAL, Body->Type);
} else {
- ESym->setBindingAndType(Body->symbol()->computeBinding(), Body->Type);
- ESym->setVisibility(Body->symbol()->Visibility);
+ ESym->setBindingAndType(Body->computeBinding(), Body->Type);
+ ESym->setVisibility(Body->Visibility);
}
ESym->st_name = Ent.StrTabOffset;
template <class ELFT> void VersionTableSection<ELFT>::writeTo(uint8_t *Buf) {
auto *OutVersym = reinterpret_cast<Elf_Versym *>(Buf) + 1;
for (const SymbolTableEntry &S : InX::DynSymTab->getSymbols()) {
- OutVersym->vs_index = S.Symbol->symbol()->VersionId;
+ OutVersym->vs_index = S.Symbol->VersionId;
++OutVersym;
}
}
void VersionNeedSection<ELFT>::addSymbol(SharedSymbol *SS) {
auto *Ver = reinterpret_cast<const typename ELFT::Verdef *>(SS->Verdef);
if (!Ver) {
- SS->symbol()->VersionId = VER_NDX_GLOBAL;
+ SS->VersionId = VER_NDX_GLOBAL;
return;
}
Ver->getAux()->vda_name);
NV.Index = NextIndex++;
}
- SS->symbol()->VersionId = NV.Index;
+ SS->VersionId = NV.Index;
}
template <class ELFT> void VersionNeedSection<ELFT>::writeTo(uint8_t *Buf) {
}
static bool includeInSymtab(const SymbolBody &B) {
- if (!B.isLocal() && !B.symbol()->IsUsedInRegularObj)
+ if (!B.isLocal() && !B.IsUsedInRegularObj)
return false;
if (auto *D = dyn_cast<DefinedRegular>(&B)) {
SymbolBody *S = Symtab->find(Name);
if (!S || S->isInCurrentOutput())
return nullptr;
- Symbol *Sym = Symtab->addRegular<ELFT>(Name, StOther, STT_NOTYPE, Val,
- /*Size=*/0, Binding, Sec,
- /*File=*/nullptr);
- return cast<DefinedRegular>(Sym->body());
+ SymbolBody *Sym = Symtab->addRegular<ELFT>(Name, StOther, STT_NOTYPE, Val,
+ /*Size=*/0, Binding, Sec,
+ /*File=*/nullptr);
+ return cast<DefinedRegular>(Sym);
}
// The beginning and the ending of .rel[a].plt section are marked
static bool computeIsPreemptible(const SymbolBody &B) {
assert(!B.isLocal());
// Only symbols that appear in dynsym can be preempted.
- if (!B.symbol()->includeInDynsym())
+ if (!B.includeInDynsym())
return false;
// Only default visibility symbols can be preempted.
- if (B.symbol()->Visibility != STV_DEFAULT)
+ if (B.Visibility != STV_DEFAULT)
return false;
// At this point copy relocations have not been created yet, so any
applySynthetic({InX::EhFrame},
[](SyntheticSection *SS) { SS->finalizeContents(); });
- for (Symbol *S : Symtab->getSymbols())
- S->body()->IsPreemptible |= computeIsPreemptible(*S->body());
+ for (SymbolBody *S : Symtab->getSymbols())
+ S->IsPreemptible |= computeIsPreemptible(*S);
// Scan relocations. This must be done after every symbol is declared so that
// we can correctly decide if a dynamic relocation is needed.
// Now that we have defined all possible global symbols including linker-
// synthesized ones. Visit all symbols to give the finishing touches.
- for (Symbol *S : Symtab->getSymbols()) {
- SymbolBody *Body = S->body();
-
- if (!includeInSymtab(*Body))
+ for (SymbolBody *Sym : Symtab->getSymbols()) {
+ if (!includeInSymtab(*Sym))
continue;
if (InX::SymTab)
- InX::SymTab->addSymbol(Body);
+ InX::SymTab->addSymbol(Sym);
- if (InX::DynSymTab && S->includeInDynsym()) {
- InX::DynSymTab->addSymbol(Body);
- if (auto *SS = dyn_cast<SharedSymbol>(Body))
- if (cast<SharedFile<ELFT>>(S->File)->isNeeded())
+ 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);
}
}
The linker can be understood as the interactions between them.
Once you understand their functions, the code of the linker should look obvious to you.
-* SymbolBody
+* Symbol
- SymbolBody is a class to represent symbols.
+ This class represents a symbol.
They are created for symbols in object files or archive files.
The linker creates linker-defined symbols as well.
- There are basically three types of SymbolBodies: Defined, Undefined, or Lazy.
+ There are basically three types of Symbols: Defined, Undefined, or Lazy.
- Defined symbols are for all symbols that are considered as "resolved",
including real defined symbols, COMDAT symbols, common symbols,
- Lazy symbols represent symbols we found in archive file headers
which can turn into Defined if we read archieve members.
-* Symbol
+ There's only one Symbol instance for each unique symbol name. This uniqueness
+ is guaranteed by the symbol table. As the resolver reads symbols from input
+ files, it replaces an existing Symbol with the "best" Symbol for its symbol
+ name using the placement new.
- A Symbol is a container for a SymbolBody. There's only one Symbol for each
- unique symbol name (this uniqueness is guaranteed by the symbol table).
- Each global symbol has only one SymbolBody at any one time, which is
- the SymbolBody stored within a memory region of the Symbol large enough
- to store any SymbolBody.
-
- As the resolver reads symbols from input files, it replaces the Symbol's
- SymbolBody with the "best" SymbolBody for its symbol name by constructing
- the new SymbolBody in place on top of the existing SymbolBody. For example,
- if the resolver is given a defined symbol, and the SymbolBody with its name
- is undefined, it will construct a Defined SymbolBody over the Undefined
- SymbolBody.
-
- This means that each SymbolBody pointer always points to the best SymbolBody,
- and it is possible to get from a SymbolBody to a Symbol, or vice versa,
- by adding or subtracting a fixed offset. This memory layout helps reduce
- the cache miss rate through high locality and a small number of required
- pointer indirections.
+ The above mechanism allows you to use pointers to Symbols as a very cheap way
+ to access name resolution results. Assume for example that you have a pointer
+ to an undefined symbol before name resolution. If the symbol is resolved to a
+ defined symbol by the resolver, the pointer will "automatically" point to the
+ defined symbol, because the undefined symbol the pointer pointed to will have
+ been replaced by the defined symbol in-place.
* SymbolTable
InputFile is a superclass of file readers.
We have a different subclass for each input file type,
such as regular object file, archive file, etc.
- They are responsible for creating and owning SymbolBodies and
- InputSections/Chunks.
+ They are responsible for creating and owning Symbols and InputSections/Chunks.
* Writer