summaryrefslogtreecommitdiff
path: root/ELF/Symbols.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'ELF/Symbols.cpp')
-rw-r--r--ELF/Symbols.cpp253
1 files changed, 71 insertions, 182 deletions
diff --git a/ELF/Symbols.cpp b/ELF/Symbols.cpp
index c69007e781a68..ab42fcd51a81b 100644
--- a/ELF/Symbols.cpp
+++ b/ELF/Symbols.cpp
@@ -8,15 +8,15 @@
//===----------------------------------------------------------------------===//
#include "Symbols.h"
-#include "Error.h"
#include "InputFiles.h"
#include "InputSection.h"
#include "OutputSections.h"
-#include "Strings.h"
#include "SyntheticSections.h"
#include "Target.h"
#include "Writer.h"
+#include "lld/Common/ErrorHandler.h"
+#include "lld/Common/Strings.h"
#include "llvm/ADT/STLExtras.h"
#include "llvm/Support/Path.h"
#include <cstring>
@@ -28,25 +28,23 @@ using namespace llvm::ELF;
using namespace lld;
using namespace lld::elf;
-DefinedRegular *ElfSym::Bss;
-DefinedRegular *ElfSym::Etext1;
-DefinedRegular *ElfSym::Etext2;
-DefinedRegular *ElfSym::Edata1;
-DefinedRegular *ElfSym::Edata2;
-DefinedRegular *ElfSym::End1;
-DefinedRegular *ElfSym::End2;
-DefinedRegular *ElfSym::GlobalOffsetTable;
-DefinedRegular *ElfSym::MipsGp;
-DefinedRegular *ElfSym::MipsGpDisp;
-DefinedRegular *ElfSym::MipsLocalGp;
-
-static uint64_t getSymVA(const SymbolBody &Body, int64_t &Addend) {
- switch (Body.kind()) {
- case SymbolBody::DefinedRegularKind: {
- auto &D = cast<DefinedRegular>(Body);
+Defined *ElfSym::Bss;
+Defined *ElfSym::Etext1;
+Defined *ElfSym::Etext2;
+Defined *ElfSym::Edata1;
+Defined *ElfSym::Edata2;
+Defined *ElfSym::End1;
+Defined *ElfSym::End2;
+Defined *ElfSym::GlobalOffsetTable;
+Defined *ElfSym::MipsGp;
+Defined *ElfSym::MipsGpDisp;
+Defined *ElfSym::MipsLocalGp;
+
+static uint64_t getSymVA(const Symbol &Sym, int64_t &Addend) {
+ switch (Sym.kind()) {
+ case Symbol::DefinedKind: {
+ auto &D = cast<Defined>(Sym);
SectionBase *IS = D.Section;
- if (auto *ISB = dyn_cast_or_null<InputSectionBase>(IS))
- IS = ISB->Repl;
// According to the ELF spec reference to a local symbol from outside
// the group are not allowed. Unfortunately .eh_frame breaks that rule
@@ -59,6 +57,7 @@ static uint64_t getSymVA(const SymbolBody &Body, int64_t &Addend) {
if (!IS)
return D.Value;
+ IS = IS->Repl;
uint64_t Offset = D.Value;
// An object in an SHF_MERGE section might be referenced via a
@@ -99,139 +98,85 @@ static uint64_t getSymVA(const SymbolBody &Body, int64_t &Addend) {
}
return VA;
}
- case SymbolBody::DefinedCommonKind:
- if (!Config->DefineCommon)
- return 0;
- return InX::Common->getParent()->Addr + InX::Common->OutSecOff +
- cast<DefinedCommon>(Body).Offset;
- case SymbolBody::SharedKind: {
- auto &SS = cast<SharedSymbol>(Body);
- if (SS.NeedsCopy)
- return SS.CopyRelSec->getParent()->Addr + SS.CopyRelSec->OutSecOff +
- SS.CopyRelSecOff;
+ case Symbol::SharedKind: {
+ auto &SS = cast<SharedSymbol>(Sym);
+ if (SS.CopyRelSec)
+ return SS.CopyRelSec->getParent()->Addr + SS.CopyRelSec->OutSecOff;
if (SS.NeedsPltAddr)
- return Body.getPltVA();
+ return Sym.getPltVA();
return 0;
}
- case SymbolBody::UndefinedKind:
+ case Symbol::UndefinedKind:
return 0;
- case SymbolBody::LazyArchiveKind:
- case SymbolBody::LazyObjectKind:
- assert(Body.symbol()->IsUsedInRegularObj && "lazy symbol reached writer");
+ case Symbol::LazyArchiveKind:
+ case Symbol::LazyObjectKind:
+ assert(Sym.IsUsedInRegularObj && "lazy symbol reached writer");
return 0;
}
llvm_unreachable("invalid symbol kind");
}
-SymbolBody::SymbolBody(Kind K, StringRefZ Name, bool IsLocal, uint8_t StOther,
- uint8_t Type)
- : SymbolKind(K), NeedsCopy(false), NeedsPltAddr(false), IsLocal(IsLocal),
- IsInGlobalMipsGot(false), Is32BitMipsGot(false), IsInIplt(false),
- IsInIgot(false), Type(Type), StOther(StOther), Name(Name) {}
-
-// Returns true if a symbol can be replaced at load-time by a symbol
-// with the same name defined in other ELF executable or DSO.
-bool SymbolBody::isPreemptible() const {
- if (isLocal())
- return false;
-
- // Shared symbols resolve to the definition in the DSO. The exceptions are
- // symbols with copy relocations (which resolve to .bss) or preempt plt
- // entries (which resolve to that plt entry).
- if (isShared())
- return !NeedsCopy && !NeedsPltAddr;
-
- // That's all that can be preempted in a non-DSO.
- if (!Config->Shared)
- return false;
-
- // Only symbols that appear in dynsym can be preempted.
- if (!symbol()->includeInDynsym())
- return false;
-
- // Only default visibility symbols can be preempted.
- if (symbol()->Visibility != STV_DEFAULT)
- return false;
-
- // -Bsymbolic means that definitions are not preempted.
- if (Config->Bsymbolic || (Config->BsymbolicFunctions && isFunc()))
- return !isDefined();
- return true;
-}
-
-// 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::copy(SymbolBody *Other) {
- memcpy(symbol()->Body.buffer, Other->symbol()->Body.buffer,
- sizeof(Symbol::Body));
+// Returns true if this is a weak undefined symbol.
+bool Symbol::isUndefWeak() const {
+ // See comment on Lazy in Symbols.h for the details.
+ return isWeak() && (isUndefined() || isLazy());
}
-uint64_t SymbolBody::getVA(int64_t Addend) const {
+uint64_t Symbol::getVA(int64_t Addend) const {
uint64_t OutVA = getSymVA(*this, Addend);
return OutVA + Addend;
}
-uint64_t SymbolBody::getGotVA() const {
- return InX::Got->getVA() + getGotOffset();
-}
+uint64_t Symbol::getGotVA() const { return InX::Got->getVA() + getGotOffset(); }
-uint64_t SymbolBody::getGotOffset() const {
+uint64_t Symbol::getGotOffset() const {
return GotIndex * Target->GotEntrySize;
}
-uint64_t SymbolBody::getGotPltVA() const {
+uint64_t Symbol::getGotPltVA() const {
if (this->IsInIgot)
return InX::IgotPlt->getVA() + getGotPltOffset();
return InX::GotPlt->getVA() + getGotPltOffset();
}
-uint64_t SymbolBody::getGotPltOffset() const {
+uint64_t Symbol::getGotPltOffset() const {
return GotPltIndex * Target->GotPltEntrySize;
}
-uint64_t SymbolBody::getPltVA() const {
+uint64_t Symbol::getPltVA() const {
if (this->IsInIplt)
return InX::Iplt->getVA() + PltIndex * Target->PltEntrySize;
return InX::Plt->getVA() + Target->PltHeaderSize +
PltIndex * Target->PltEntrySize;
}
-template <class ELFT> typename ELFT::uint SymbolBody::getSize() const {
- if (const auto *C = dyn_cast<DefinedCommon>(this))
- return C->Size;
- if (const auto *DR = dyn_cast<DefinedRegular>(this))
+uint64_t Symbol::getSize() const {
+ if (const auto *DR = dyn_cast<Defined>(this))
return DR->Size;
if (const auto *S = dyn_cast<SharedSymbol>(this))
- return S->getSize<ELFT>();
+ return S->Size;
return 0;
}
-OutputSection *SymbolBody::getOutputSection() const {
- if (auto *S = dyn_cast<DefinedRegular>(this)) {
- if (S->Section)
- return S->Section->getOutputSection();
+OutputSection *Symbol::getOutputSection() const {
+ if (auto *S = dyn_cast<Defined>(this)) {
+ if (auto *Sec = S->Section)
+ return Sec->Repl->getOutputSection();
return nullptr;
}
if (auto *S = dyn_cast<SharedSymbol>(this)) {
- if (S->NeedsCopy)
+ if (S->CopyRelSec)
return S->CopyRelSec->getParent();
return nullptr;
}
- if (isa<DefinedCommon>(this)) {
- if (Config->DefineCommon)
- return InX::Common->getParent();
- return nullptr;
- }
-
return nullptr;
}
// If a symbol name contains '@', the characters after that is
// a symbol version name. This function parses that.
-void SymbolBody::parseSymbolVersion() {
+void Symbol::parseSymbolVersion() {
StringRef S = getName();
size_t Pos = S.find('@');
if (Pos == 0 || Pos == StringRef::npos)
@@ -244,7 +189,7 @@ void SymbolBody::parseSymbolVersion() {
Name = {S.data(), Pos};
// If this is not in this DSO, it is not a definition.
- if (!isInCurrentDSO())
+ if (!isDefined())
return;
// '@@' in a symbol name means the default version.
@@ -258,9 +203,9 @@ void SymbolBody::parseSymbolVersion() {
continue;
if (IsDefault)
- symbol()->VersionId = Ver.Id;
+ VersionId = Ver.Id;
else
- symbol()->VersionId = Ver.Id | VERSYM_HIDDEN;
+ VersionId = Ver.Id | VERSYM_HIDDEN;
return;
}
@@ -273,81 +218,34 @@ void SymbolBody::parseSymbolVersion() {
Verstr);
}
-Defined::Defined(Kind K, StringRefZ Name, bool IsLocal, uint8_t StOther,
- uint8_t Type)
- : SymbolBody(K, Name, IsLocal, StOther, Type) {}
-
-template <class ELFT> bool DefinedRegular::isMipsPIC() const {
- typedef typename ELFT::Ehdr Elf_Ehdr;
- if (!Section || !isFunc())
- return false;
-
- auto *Sec = cast<InputSectionBase>(Section);
- const Elf_Ehdr *Hdr = Sec->template getFile<ELFT>()->getObj().getHeader();
- return (this->StOther & STO_MIPS_MIPS16) == STO_MIPS_PIC ||
- (Hdr->e_flags & EF_MIPS_PIC);
-}
-
-Undefined::Undefined(StringRefZ Name, bool IsLocal, uint8_t StOther,
- uint8_t Type, InputFile *File)
- : SymbolBody(SymbolBody::UndefinedKind, Name, IsLocal, StOther, Type) {
- this->File = File;
-}
-
-DefinedCommon::DefinedCommon(StringRef Name, uint64_t Size, uint32_t Alignment,
- uint8_t StOther, uint8_t Type, InputFile *File)
- : Defined(SymbolBody::DefinedCommonKind, Name, /*IsLocal=*/false, StOther,
- Type),
- Alignment(Alignment), Size(Size) {
- this->File = File;
-}
-
-// If a shared symbol is referred via a copy relocation, its alignment
-// becomes part of the ABI. This function returns a symbol alignment.
-// Because symbols don't have alignment attributes, we need to infer that.
-template <class ELFT> uint32_t SharedSymbol::getAlignment() const {
- auto *File = cast<SharedFile<ELFT>>(this->File);
- uint32_t SecAlign = File->getSection(getSym<ELFT>())->sh_addralign;
- uint64_t SymValue = getSym<ELFT>().st_value;
- uint32_t SymAlign = uint32_t(1) << countTrailingZeros(SymValue);
- return std::min(SecAlign, SymAlign);
-}
-
InputFile *Lazy::fetch() {
if (auto *S = dyn_cast<LazyArchive>(this))
return S->fetch();
return cast<LazyObject>(this)->fetch();
}
-LazyArchive::LazyArchive(ArchiveFile &File,
- const llvm::object::Archive::Symbol S, uint8_t Type)
- : Lazy(LazyArchiveKind, S.getName(), Type), Sym(S) {
- this->File = &File;
-}
-
-LazyObject::LazyObject(StringRef Name, LazyObjectFile &File, uint8_t Type)
- : Lazy(LazyObjectKind, Name, Type) {
- this->File = &File;
-}
+ArchiveFile *LazyArchive::getFile() { return cast<ArchiveFile>(File); }
InputFile *LazyArchive::fetch() {
- std::pair<MemoryBufferRef, uint64_t> MBInfo = file()->getMember(&Sym);
+ std::pair<MemoryBufferRef, uint64_t> MBInfo = getFile()->getMember(&Sym);
// getMember returns an empty buffer if the member was already
// read from the library.
if (MBInfo.first.getBuffer().empty())
return nullptr;
- return createObjectFile(MBInfo.first, file()->getName(), MBInfo.second);
+ return createObjectFile(MBInfo.first, getFile()->getName(), MBInfo.second);
}
-InputFile *LazyObject::fetch() { return file()->fetch(); }
+LazyObjFile *LazyObject::getFile() { return cast<LazyObjFile>(File); }
+
+InputFile *LazyObject::fetch() { return getFile()->fetch(); }
uint8_t Symbol::computeBinding() const {
if (Config->Relocatable)
return Binding;
if (Visibility != STV_DEFAULT && Visibility != STV_PROTECTED)
return STB_LOCAL;
- if (VersionId == VER_NDX_LOCAL && body()->isInCurrentDSO())
+ if (VersionId == VER_NDX_LOCAL && isDefined())
return STB_LOCAL;
if (Config->NoGnuUnique && Binding == STB_GNU_UNIQUE)
return STB_GLOBAL;
@@ -355,45 +253,36 @@ uint8_t Symbol::computeBinding() const {
}
bool Symbol::includeInDynsym() const {
+ if (!Config->HasDynSymTab)
+ return false;
if (computeBinding() == STB_LOCAL)
return false;
- return ExportDynamic || body()->isShared() ||
- (body()->isUndefined() && Config->Shared);
+ if (!isDefined())
+ return true;
+ return ExportDynamic;
}
// Print out a log message for --trace-symbol.
void elf::printTraceSymbol(Symbol *Sym) {
- SymbolBody *B = Sym->body();
std::string S;
- if (B->isUndefined())
+ if (Sym->isUndefined())
S = ": reference to ";
- else if (B->isCommon())
+ else if (Sym->isLazy())
+ S = ": lazy definition of ";
+ else if (Sym->isShared())
+ S = ": shared definition of ";
+ else if (dyn_cast_or_null<BssSection>(cast<Defined>(Sym)->Section))
S = ": common definition of ";
else
S = ": definition of ";
- message(toString(B->File) + S + B->getName());
+ message(toString(Sym->File) + S + Sym->getName());
}
// Returns a symbol for an error message.
-std::string lld::toString(const SymbolBody &B) {
+std::string lld::toString(const Symbol &B) {
if (Config->Demangle)
- if (Optional<std::string> S = demangle(B.getName()))
+ if (Optional<std::string> S = demangleItanium(B.getName()))
return *S;
return B.getName();
}
-
-template uint32_t SymbolBody::template getSize<ELF32LE>() const;
-template uint32_t SymbolBody::template getSize<ELF32BE>() const;
-template uint64_t SymbolBody::template getSize<ELF64LE>() const;
-template uint64_t SymbolBody::template getSize<ELF64BE>() const;
-
-template bool DefinedRegular::template isMipsPIC<ELF32LE>() const;
-template bool DefinedRegular::template isMipsPIC<ELF32BE>() const;
-template bool DefinedRegular::template isMipsPIC<ELF64LE>() const;
-template bool DefinedRegular::template isMipsPIC<ELF64BE>() const;
-
-template uint32_t SharedSymbol::template getAlignment<ELF32LE>() const;
-template uint32_t SharedSymbol::template getAlignment<ELF32BE>() const;
-template uint32_t SharedSymbol::template getAlignment<ELF64LE>() const;
-template uint32_t SharedSymbol::template getAlignment<ELF64BE>() const;