summaryrefslogtreecommitdiff
path: root/ELF/Symbols.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'ELF/Symbols.cpp')
-rw-r--r--ELF/Symbols.cpp176
1 files changed, 100 insertions, 76 deletions
diff --git a/ELF/Symbols.cpp b/ELF/Symbols.cpp
index d6a605d111834..a2133f411c205 100644
--- a/ELF/Symbols.cpp
+++ b/ELF/Symbols.cpp
@@ -12,9 +12,14 @@
#include "InputFiles.h"
#include "InputSection.h"
#include "OutputSections.h"
+#include "Strings.h"
+#include "SyntheticSections.h"
#include "Target.h"
+#include "Writer.h"
#include "llvm/ADT/STLExtras.h"
+#include "llvm/Support/Path.h"
+#include <cstring>
using namespace llvm;
using namespace llvm::object;
@@ -30,27 +35,27 @@ static typename ELFT::uint getSymVA(const SymbolBody &Body,
switch (Body.kind()) {
case SymbolBody::DefinedSyntheticKind: {
- auto &D = cast<DefinedSynthetic<ELFT>>(Body);
- const OutputSectionBase<ELFT> *Sec = D.Section;
+ auto &D = cast<DefinedSynthetic>(Body);
+ const OutputSectionBase *Sec = D.Section;
if (!Sec)
return D.Value;
- if (D.Value == DefinedSynthetic<ELFT>::SectionEnd)
- return Sec->getVA() + Sec->getSize();
- return Sec->getVA() + D.Value;
+ if (D.Value == uintX_t(-1))
+ return Sec->Addr + Sec->Size;
+ return Sec->Addr + D.Value;
}
case SymbolBody::DefinedRegularKind: {
auto &D = cast<DefinedRegular<ELFT>>(Body);
- InputSectionBase<ELFT> *SC = D.Section;
+ InputSectionBase<ELFT> *IS = D.Section;
// According to the ELF spec reference to a local symbol from outside
// the group are not allowed. Unfortunately .eh_frame breaks that rule
// and must be treated specially. For now we just replace the symbol with
// 0.
- if (SC == &InputSection<ELFT>::Discarded)
+ if (IS == &InputSection<ELFT>::Discarded)
return 0;
// This is an absolute symbol.
- if (!SC)
+ if (!IS)
return D.Value;
uintX_t Offset = D.Value;
@@ -58,20 +63,25 @@ static typename ELFT::uint getSymVA(const SymbolBody &Body,
Offset += Addend;
Addend = 0;
}
- uintX_t VA = SC->OutSec->getVA() + SC->getOffset(Offset);
- if (D.isTls())
+ uintX_t VA = (IS->OutSec ? IS->OutSec->Addr : 0) + IS->getOffset(Offset);
+ if (D.isTls() && !Config->Relocatable) {
+ if (!Out<ELFT>::TlsPhdr)
+ fatal(toString(D.File) +
+ " has a STT_TLS symbol but doesn't have a PT_TLS section");
return VA - Out<ELFT>::TlsPhdr->p_vaddr;
+ }
return VA;
}
case SymbolBody::DefinedCommonKind:
- return Out<ELFT>::Bss->getVA() + cast<DefinedCommon>(Body).OffsetInBss;
+ return In<ELFT>::Common->OutSec->Addr + In<ELFT>::Common->OutSecOff +
+ cast<DefinedCommon>(Body).Offset;
case SymbolBody::SharedKind: {
auto &SS = cast<SharedSymbol<ELFT>>(Body);
if (!SS.NeedsCopyOrPltAddr)
return 0;
if (SS.isFunc())
return Body.getPltVA<ELFT>();
- return Out<ELFT>::Bss->getVA() + SS.OffsetInBss;
+ return Out<ELFT>::Bss->Addr + SS.OffsetInBss;
}
case SymbolBody::UndefinedKind:
return 0;
@@ -79,32 +89,15 @@ static typename ELFT::uint getSymVA(const SymbolBody &Body,
case SymbolBody::LazyObjectKind:
assert(Body.symbol()->IsUsedInRegularObj && "lazy symbol reached writer");
return 0;
- case SymbolBody::DefinedBitcodeKind:
- llvm_unreachable("should have been replaced");
}
llvm_unreachable("invalid symbol kind");
}
-SymbolBody::SymbolBody(Kind K, uint32_t NameOffset, uint8_t StOther,
+SymbolBody::SymbolBody(Kind K, StringRefZ Name, bool IsLocal, uint8_t StOther,
uint8_t Type)
- : SymbolKind(K), NeedsCopyOrPltAddr(false), IsLocal(true),
- IsInGlobalMipsGot(false), Type(Type), StOther(StOther),
- NameOffset(NameOffset) {}
-
-SymbolBody::SymbolBody(Kind K, StringRef Name, uint8_t StOther, uint8_t Type)
- : SymbolKind(K), NeedsCopyOrPltAddr(false), IsLocal(false),
- IsInGlobalMipsGot(false), Type(Type), StOther(StOther),
- Name({Name.data(), Name.size()}) {}
-
-StringRef SymbolBody::getName() const {
- assert(!isLocal());
- return StringRef(Name.S, Name.Len);
-}
-
-void SymbolBody::setName(StringRef S) {
- Name.S = S.data();
- Name.Len = S.size();
-}
+ : SymbolKind(K), NeedsCopyOrPltAddr(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.
@@ -151,7 +144,7 @@ typename ELFT::uint SymbolBody::getVA(typename ELFT::uint Addend) const {
}
template <class ELFT> typename ELFT::uint SymbolBody::getGotVA() const {
- return Out<ELFT>::Got->getVA() + getGotOffset<ELFT>();
+ return In<ELFT>::Got->getVA() + getGotOffset<ELFT>();
}
template <class ELFT> typename ELFT::uint SymbolBody::getGotOffset() const {
@@ -159,7 +152,9 @@ template <class ELFT> typename ELFT::uint SymbolBody::getGotOffset() const {
}
template <class ELFT> typename ELFT::uint SymbolBody::getGotPltVA() const {
- return Out<ELFT>::GotPlt->getVA() + getGotPltOffset<ELFT>();
+ if (this->IsInIgot)
+ return In<ELFT>::IgotPlt->getVA() + getGotPltOffset<ELFT>();
+ return In<ELFT>::GotPlt->getVA() + getGotPltOffset<ELFT>();
}
template <class ELFT> typename ELFT::uint SymbolBody::getGotPltOffset() const {
@@ -167,7 +162,9 @@ template <class ELFT> typename ELFT::uint SymbolBody::getGotPltOffset() const {
}
template <class ELFT> typename ELFT::uint SymbolBody::getPltVA() const {
- return Out<ELFT>::Plt->getVA() + Target->PltHeaderSize +
+ if (this->IsInIplt)
+ return In<ELFT>::Iplt->getVA() + PltIndex * Target->PltEntrySize;
+ return In<ELFT>::Plt->getVA() + Target->PltHeaderSize +
PltIndex * Target->PltEntrySize;
}
@@ -189,48 +186,67 @@ template <class ELFT> typename ELFT::uint SymbolBody::getSize() const {
return 0;
}
-Defined::Defined(Kind K, StringRef Name, uint8_t StOther, uint8_t Type)
- : SymbolBody(K, Name, StOther, Type) {}
-
-Defined::Defined(Kind K, uint32_t NameOffset, uint8_t StOther, uint8_t Type)
- : SymbolBody(K, NameOffset, StOther, Type) {}
+// If a symbol name contains '@', the characters after that is
+// a symbol version name. This function parses that.
+void SymbolBody::parseSymbolVersion() {
+ StringRef S = getName();
+ size_t Pos = S.find('@');
+ if (Pos == 0 || Pos == StringRef::npos)
+ return;
+ StringRef Verstr = S.substr(Pos + 1);
+ if (Verstr.empty())
+ return;
+
+ // Truncate the symbol name so that it doesn't include the version string.
+ Name = {S.data(), Pos};
+
+ // '@@' in a symbol name means the default version.
+ // It is usually the most recent one.
+ bool IsDefault = (Verstr[0] == '@');
+ if (IsDefault)
+ Verstr = Verstr.substr(1);
+
+ for (VersionDefinition &Ver : Config->VersionDefinitions) {
+ if (Ver.Name != Verstr)
+ continue;
+
+ if (IsDefault)
+ symbol()->VersionId = Ver.Id;
+ else
+ symbol()->VersionId = Ver.Id | VERSYM_HIDDEN;
+ return;
+ }
-DefinedBitcode::DefinedBitcode(StringRef Name, uint8_t StOther, uint8_t Type,
- BitcodeFile *F)
- : Defined(DefinedBitcodeKind, Name, StOther, Type) {
- this->File = F;
+ // It is an error if the specified version is not defined.
+ error(toString(File) + ": symbol " + S + " has undefined version " + Verstr);
}
-bool DefinedBitcode::classof(const SymbolBody *S) {
- return S->kind() == DefinedBitcodeKind;
-}
+Defined::Defined(Kind K, StringRefZ Name, bool IsLocal, uint8_t StOther,
+ uint8_t Type)
+ : SymbolBody(K, Name, IsLocal, StOther, Type) {}
-Undefined::Undefined(StringRef Name, uint8_t StOther, uint8_t Type,
- InputFile *File)
- : SymbolBody(SymbolBody::UndefinedKind, Name, StOther, Type) {
- this->File = File;
+template <class ELFT> bool DefinedRegular<ELFT>::isMipsPIC() const {
+ if (!Section || !isFunc())
+ return false;
+ return (this->StOther & STO_MIPS_MIPS16) == STO_MIPS_PIC ||
+ (Section->getFile()->getObj().getHeader()->e_flags & EF_MIPS_PIC);
}
-Undefined::Undefined(uint32_t NameOffset, uint8_t StOther, uint8_t Type,
- InputFile *File)
- : SymbolBody(SymbolBody::UndefinedKind, NameOffset, StOther, Type) {
+Undefined::Undefined(StringRefZ Name, bool IsLocal, uint8_t StOther,
+ uint8_t Type, InputFile *File)
+ : SymbolBody(SymbolBody::UndefinedKind, Name, IsLocal, StOther, Type) {
this->File = File;
}
-template <typename ELFT>
-DefinedSynthetic<ELFT>::DefinedSynthetic(StringRef N, uintX_t Value,
- OutputSectionBase<ELFT> *Section)
- : Defined(SymbolBody::DefinedSyntheticKind, N, STV_HIDDEN, 0 /* Type */),
- Value(Value), Section(Section) {}
-
-DefinedCommon::DefinedCommon(StringRef N, uint64_t Size, uint64_t Alignment,
+DefinedCommon::DefinedCommon(StringRef Name, uint64_t Size, uint64_t Alignment,
uint8_t StOther, uint8_t Type, InputFile *File)
- : Defined(SymbolBody::DefinedCommonKind, N, StOther, Type),
+ : Defined(SymbolBody::DefinedCommonKind, Name, /*IsLocal=*/false, StOther,
+ Type),
Alignment(Alignment), Size(Size) {
this->File = File;
}
-std::unique_ptr<InputFile> Lazy::fetch() {
+InputFile *Lazy::fetch() {
if (auto *S = dyn_cast<LazyArchive>(this))
return S->fetch();
return cast<LazyObject>(this)->fetch();
@@ -247,20 +263,20 @@ LazyObject::LazyObject(StringRef Name, LazyObjectFile &File, uint8_t Type)
this->File = &File;
}
-std::unique_ptr<InputFile> LazyArchive::fetch() {
- MemoryBufferRef MBRef = file()->getMember(&Sym);
+InputFile *LazyArchive::fetch() {
+ std::pair<MemoryBufferRef, uint64_t> MBInfo = file()->getMember(&Sym);
// getMember returns an empty buffer if the member was already
// read from the library.
- if (MBRef.getBuffer().empty())
- return std::unique_ptr<InputFile>(nullptr);
- return createObjectFile(MBRef, file()->getName());
+ if (MBInfo.first.getBuffer().empty())
+ return nullptr;
+ return createObjectFile(MBInfo.first, file()->getName(), MBInfo.second);
}
-std::unique_ptr<InputFile> LazyObject::fetch() {
+InputFile *LazyObject::fetch() {
MemoryBufferRef MBRef = file()->getBuffer();
if (MBRef.getBuffer().empty())
- return std::unique_ptr<InputFile>(nullptr);
+ return nullptr;
return createObjectFile(MBRef);
}
@@ -274,7 +290,7 @@ bool Symbol::includeInDynsym() const {
// Print out a log message for --trace-symbol.
void elf::printTraceSymbol(Symbol *Sym) {
SymbolBody *B = Sym->body();
- outs() << getFilename(B->File);
+ outs() << toString(B->File);
if (B->isUndefined())
outs() << ": reference to ";
@@ -285,6 +301,14 @@ void elf::printTraceSymbol(Symbol *Sym) {
outs() << B->getName() << "\n";
}
+// Returns a symbol for an error message.
+std::string elf::toString(const SymbolBody &B) {
+ if (Config->Demangle)
+ if (Optional<std::string> S = demangle(B.getName()))
+ return *S;
+ return B.getName();
+}
+
template bool SymbolBody::hasThunk<ELF32LE>() const;
template bool SymbolBody::hasThunk<ELF32BE>() const;
template bool SymbolBody::hasThunk<ELF64LE>() const;
@@ -330,7 +354,7 @@ 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 class elf::DefinedSynthetic<ELF32LE>;
-template class elf::DefinedSynthetic<ELF32BE>;
-template class elf::DefinedSynthetic<ELF64LE>;
-template class elf::DefinedSynthetic<ELF64BE>;
+template class elf::DefinedRegular<ELF32LE>;
+template class elf::DefinedRegular<ELF32BE>;
+template class elf::DefinedRegular<ELF64LE>;
+template class elf::DefinedRegular<ELF64BE>;