diff options
Diffstat (limited to 'ELF/Symbols.cpp')
-rw-r--r-- | ELF/Symbols.cpp | 176 |
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>; |