diff options
-rw-r--r-- | lld/ELF/OutputSections.h | 2 | ||||
-rw-r--r-- | lld/ELF/Relocations.cpp | 46 | ||||
-rw-r--r-- | lld/ELF/SymbolTable.cpp | 16 | ||||
-rw-r--r-- | lld/ELF/Symbols.cpp | 27 | ||||
-rw-r--r-- | lld/ELF/Symbols.h | 42 | ||||
-rw-r--r-- | lld/ELF/SyntheticSections.cpp | 21 | ||||
-rw-r--r-- | lld/ELF/SyntheticSections.h | 2 | ||||
-rw-r--r-- | lld/ELF/Writer.cpp | 4 |
8 files changed, 91 insertions, 69 deletions
diff --git a/lld/ELF/OutputSections.h b/lld/ELF/OutputSections.h index a6a0c2ab199..06a03e5b65c 100644 --- a/lld/ELF/OutputSections.h +++ b/lld/ELF/OutputSections.h @@ -30,7 +30,7 @@ template <class ELFT> class MergeInputSection; class OutputSection; template <class ELFT> class ObjectFile; template <class ELFT> class SharedFile; -template <class ELFT> class SharedSymbol; +class SharedSymbol; template <class ELFT> class DefinedRegular; // This represents a section in an output file. diff --git a/lld/ELF/Relocations.cpp b/lld/ELF/Relocations.cpp index 35030888208..3d4ce39f5e2 100644 --- a/lld/ELF/Relocations.cpp +++ b/lld/ELF/Relocations.cpp @@ -387,23 +387,13 @@ static RelExpr fromPlt(RelExpr Expr) { return Expr; } -template <class ELFT> static uint32_t getAlignment(SharedSymbol<ELFT> *SS) { - typedef typename ELFT::uint uintX_t; - - uintX_t SecAlign = SS->file()->getSection(SS->Sym)->sh_addralign; - uintX_t SymValue = SS->Sym.st_value; - int TrailingZeros = - std::min(countTrailingZeros(SecAlign), countTrailingZeros(SymValue)); - return 1 << TrailingZeros; -} - -template <class ELFT> static bool isReadOnly(SharedSymbol<ELFT> *SS) { - typedef typename ELFT::uint uintX_t; +template <class ELFT> static bool isReadOnly(SharedSymbol *SS) { typedef typename ELFT::Phdr Elf_Phdr; + uint64_t Value = SS->getValue<ELFT>(); // Determine if the symbol is read-only by scanning the DSO's program headers. - uintX_t Value = SS->Sym.st_value; - for (const Elf_Phdr &Phdr : check(SS->file()->getObj().program_headers())) + auto *File = cast<SharedFile<ELFT>>(SS->File); + for (const Elf_Phdr &Phdr : check(File->getObj().program_headers())) if ((Phdr.p_type == ELF::PT_LOAD || Phdr.p_type == ELF::PT_GNU_RELRO) && !(Phdr.p_flags & ELF::PF_W) && Value >= Phdr.p_vaddr && Value < Phdr.p_vaddr + Phdr.p_memsz) @@ -417,16 +407,20 @@ template <class ELFT> static bool isReadOnly(SharedSymbol<ELFT> *SS) { // them are copied by a copy relocation, all of them need to be copied. // Otherwise, they would refer different places at runtime. template <class ELFT> -static std::vector<SharedSymbol<ELFT> *> getSymbolsAt(SharedSymbol<ELFT> *SS) { +static std::vector<SharedSymbol *> getSymbolsAt(SharedSymbol *SS) { typedef typename ELFT::Sym Elf_Sym; - std::vector<SharedSymbol<ELFT> *> Ret; - for (const Elf_Sym &S : SS->file()->getGlobalSymbols()) { - if (S.st_shndx != SS->Sym.st_shndx || S.st_value != SS->Sym.st_value) + auto *File = cast<SharedFile<ELFT>>(SS->File); + uint64_t Shndx = SS->getShndx<ELFT>(); + uint64_t Value = SS->getValue<ELFT>(); + + std::vector<SharedSymbol *> Ret; + for (const Elf_Sym &S : File->getGlobalSymbols()) { + if (S.st_shndx != Shndx || S.st_value != Value) continue; - StringRef Name = check(S.getName(SS->file()->getStringTable())); + StringRef Name = check(S.getName(File->getStringTable())); SymbolBody *Sym = Symtab<ELFT>::X->find(Name); - if (auto *Alias = dyn_cast_or_null<SharedSymbol<ELFT>>(Sym)) + if (auto *Alias = dyn_cast_or_null<SharedSymbol>(Sym)) Ret.push_back(Alias); } return Ret; @@ -474,7 +468,7 @@ static std::vector<SharedSymbol<ELFT> *> getSymbolsAt(SharedSymbol<ELFT> *SS) { // to the variable in .bss. This kind of issue is sometimes very hard to // debug. What's a solution? Instead of exporting a varaible V from a DSO, // define an accessor getV(). -template <class ELFT> static void addCopyRelSymbol(SharedSymbol<ELFT> *SS) { +template <class ELFT> static void addCopyRelSymbol(SharedSymbol *SS) { typedef typename ELFT::uint uintX_t; // Copy relocation against zero-sized symbol doesn't make sense. @@ -484,18 +478,18 @@ template <class ELFT> static void addCopyRelSymbol(SharedSymbol<ELFT> *SS) { // See if this symbol is in a read-only segment. If so, preserve the symbol's // memory protection by reserving space in the .bss.rel.ro section. - bool IsReadOnly = isReadOnly(SS); + bool IsReadOnly = isReadOnly<ELFT>(SS); OutputSection *OSec = IsReadOnly ? Out<ELFT>::BssRelRo : Out<ELFT>::Bss; // Create a SyntheticSection in Out to hold the .bss and the Copy Reloc. auto *ISec = - make<CopyRelSection<ELFT>>(IsReadOnly, getAlignment(SS), SymSize); + make<CopyRelSection<ELFT>>(IsReadOnly, SS->getAlignment<ELFT>(), SymSize); OSec->addSection(ISec); // Look through the DSO's dynamic symbol table for aliases and create a // dynamic symbol for each one. This causes the copy relocation to correctly // interpose any aliases. - for (SharedSymbol<ELFT> *Sym : getSymbolsAt(SS)) { + for (SharedSymbol *Sym : getSymbolsAt<ELFT>(SS)) { Sym->NeedsCopy = true; Sym->Section = ISec; Sym->symbol()->IsUsedInRegularObj = true; @@ -540,14 +534,14 @@ static RelExpr adjustExpr(const elf::ObjectFile<ELFT> &File, SymbolBody &Body, } if (Body.isObject()) { // Produce a copy relocation. - auto *B = cast<SharedSymbol<ELFT>>(&Body); + auto *B = cast<SharedSymbol>(&Body); if (!B->NeedsCopy) { if (Config->ZNocopyreloc) error(S.getLocation<ELFT>(RelOff) + ": unresolvable relocation " + toString(Type) + " against symbol '" + toString(*B) + "'; recompile with -fPIC or remove '-z nocopyreloc'"); - addCopyRelSymbol(B); + addCopyRelSymbol<ELFT>(B); } return Expr; } diff --git a/lld/ELF/SymbolTable.cpp b/lld/ELF/SymbolTable.cpp index 405c44a0671..3b4ecd504e1 100644 --- a/lld/ELF/SymbolTable.cpp +++ b/lld/ELF/SymbolTable.cpp @@ -262,8 +262,8 @@ Symbol *SymbolTable<ELFT>::addUndefined(StringRef Name, bool IsLocal, if (Binding != STB_WEAK) { if (S->body()->isShared() || S->body()->isLazy()) S->Binding = Binding; - if (auto *SS = dyn_cast<SharedSymbol<ELFT>>(S->body())) - SS->file()->IsUsed = true; + if (auto *SS = dyn_cast<SharedSymbol>(S->body())) + cast<SharedFile<ELFT>>(SS->File)->IsUsed = true; } if (auto *L = dyn_cast<Lazy>(S->body())) { // An undefined weak will not fetch archive members, but we have to remember @@ -413,7 +413,7 @@ Symbol *SymbolTable<ELFT>::addSynthetic(StringRef N, } template <typename ELFT> -void SymbolTable<ELFT>::addShared(SharedFile<ELFT> *F, StringRef Name, +void SymbolTable<ELFT>::addShared(SharedFile<ELFT> *File, StringRef Name, const Elf_Sym &Sym, const typename ELFT::Verdef *Verdef) { // DSO symbols do not affect visibility in the output, so we pass STV_DEFAULT @@ -421,15 +421,17 @@ void SymbolTable<ELFT>::addShared(SharedFile<ELFT> *F, StringRef Name, // unchanged. Symbol *S; bool WasInserted; - std::tie(S, WasInserted) = - insert(Name, Sym.getType(), STV_DEFAULT, /*CanOmitFromDynSym*/ true, F); + std::tie(S, WasInserted) = insert(Name, Sym.getType(), STV_DEFAULT, + /*CanOmitFromDynSym*/ true, File); // Make sure we preempt DSO symbols with default visibility. if (Sym.getVisibility() == STV_DEFAULT) S->ExportDynamic = true; + if (WasInserted || isa<Undefined>(S->body())) { - replaceBody<SharedSymbol<ELFT>>(S, F, Name, Sym, Verdef); + replaceBody<SharedSymbol>(S, File, Name, Sym.st_other, Sym.getType(), &Sym, + Verdef); if (!S->isWeak()) - F->IsUsed = true; + File->IsUsed = true; } } diff --git a/lld/ELF/Symbols.cpp b/lld/ELF/Symbols.cpp index f0572d2e3ba..d1588834886 100644 --- a/lld/ELF/Symbols.cpp +++ b/lld/ELF/Symbols.cpp @@ -78,7 +78,7 @@ static typename ELFT::uint getSymVA(const SymbolBody &Body, int64_t &Addend) { return In<ELFT>::Common->OutSec->Addr + In<ELFT>::Common->OutSecOff + cast<DefinedCommon>(Body).Offset; case SymbolBody::SharedKind: { - auto &SS = cast<SharedSymbol<ELFT>>(Body); + auto &SS = cast<SharedSymbol>(Body); if (SS.NeedsCopy) return SS.Section->OutSec->Addr + SS.Section->OutSecOff; if (SS.NeedsPltAddr) @@ -167,8 +167,8 @@ template <class ELFT> typename ELFT::uint SymbolBody::getSize() const { return C->Size; if (const auto *DR = dyn_cast<DefinedRegular<ELFT>>(this)) return DR->Size; - if (const auto *S = dyn_cast<SharedSymbol<ELFT>>(this)) - return S->Sym.st_size; + if (const auto *S = dyn_cast<SharedSymbol>(this)) + return S->getSize<ELFT>(); return 0; } @@ -237,6 +237,17 @@ DefinedCommon::DefinedCommon(StringRef Name, uint64_t Size, uint64_t Alignment, 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> uint64_t SharedSymbol::getAlignment() const { + auto *File = cast<SharedFile<ELFT>>(this->File); + uint64_t SecAlign = File->getSection(getSym<ELFT>())->sh_addralign; + uint64_t SymValue = getSym<ELFT>().st_value; + uint64_t SymAlign = uint64_t(1) << countTrailingZeros(SymValue); + return std::min(SecAlign, SymAlign); +} + InputFile *Lazy::fetch() { if (auto *S = dyn_cast<LazyArchive>(this)) return S->fetch(); @@ -348,12 +359,12 @@ 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::SharedSymbol<ELF32LE>; -template class elf::SharedSymbol<ELF32BE>; -template class elf::SharedSymbol<ELF64LE>; -template class elf::SharedSymbol<ELF64BE>; - template class elf::DefinedRegular<ELF32LE>; template class elf::DefinedRegular<ELF32BE>; template class elf::DefinedRegular<ELF64LE>; template class elf::DefinedRegular<ELF64BE>; + +template uint64_t SharedSymbol::template getAlignment<ELF32LE>() const; +template uint64_t SharedSymbol::template getAlignment<ELF32BE>() const; +template uint64_t SharedSymbol::template getAlignment<ELF64LE>() const; +template uint64_t SharedSymbol::template getAlignment<ELF64BE>() const; diff --git a/lld/ELF/Symbols.h b/lld/ELF/Symbols.h index 4fc130b15c7..e63b4531f8b 100644 --- a/lld/ELF/Symbols.h +++ b/lld/ELF/Symbols.h @@ -241,36 +241,48 @@ public: } }; -template <class ELFT> class SharedSymbol : public Defined { - typedef typename ELFT::Sym Elf_Sym; - typedef typename ELFT::Verdef Elf_Verdef; - typedef typename ELFT::uint uintX_t; - +class SharedSymbol : public Defined { public: static bool classof(const SymbolBody *S) { return S->kind() == SymbolBody::SharedKind; } - SharedSymbol(SharedFile<ELFT> *F, StringRef Name, const Elf_Sym &Sym, - const Elf_Verdef *Verdef) - : Defined(SymbolBody::SharedKind, Name, /*IsLocal=*/false, Sym.st_other, - Sym.getType()), - Sym(Sym), Verdef(Verdef) { + SharedSymbol(InputFile *File, StringRef Name, uint8_t StOther, uint8_t Type, + const void *ElfSym, const void *Verdef) + : Defined(SymbolBody::SharedKind, Name, /*IsLocal=*/false, StOther, Type), + Verdef(Verdef), ElfSym(ElfSym) { // IFuncs defined in DSOs are treated as functions by the static linker. if (isGnuIFunc()) Type = llvm::ELF::STT_FUNC; - this->File = F; + this->File = File; } - SharedFile<ELFT> *file() { return (SharedFile<ELFT> *)this->File; } + template <class ELFT> uint64_t getShndx() const { + return getSym<ELFT>().st_shndx; + } - const Elf_Sym &Sym; + template <class ELFT> uint64_t getValue() const { + return getSym<ELFT>().st_value; + } + + template <class ELFT> uint64_t getSize() const { + return getSym<ELFT>().st_size; + } + + template <class ELFT> uint64_t getAlignment() const; // This field is a pointer to the symbol's version definition. - const Elf_Verdef *Verdef; + const void *Verdef; // Section is significant only when NeedsCopy is true. InputSection *Section = nullptr; + +private: + template <class ELFT> const typename ELFT::Sym &getSym() const { + return *(const typename ELFT::Sym *)ElfSym; + } + + const void *ElfSym; }; // This class represents a symbol defined in an archive file. It is @@ -405,7 +417,7 @@ struct Symbol { // ELFT, and we verify this with the static_asserts in replaceBody. llvm::AlignedCharArrayUnion< DefinedCommon, DefinedRegular<llvm::object::ELF64LE>, DefinedSynthetic, - Undefined, SharedSymbol<llvm::object::ELF64LE>, LazyArchive, LazyObject> + Undefined, SharedSymbol, LazyArchive, LazyObject> Body; SymbolBody *body() { return reinterpret_cast<SymbolBody *>(Body.buffer); } diff --git a/lld/ELF/SyntheticSections.cpp b/lld/ELF/SyntheticSections.cpp index 8a881f8a41e..71d46fb3a30 100644 --- a/lld/ELF/SyntheticSections.cpp +++ b/lld/ELF/SyntheticSections.cpp @@ -1455,7 +1455,7 @@ SymbolTableSection<ELFT>::getOutputSection(SymbolBody *Sym) { return nullptr; return In<ELFT>::Common->OutSec; case SymbolBody::SharedKind: { - auto &SS = cast<SharedSymbol<ELFT>>(*Sym); + auto &SS = cast<SharedSymbol>(*Sym); if (SS.NeedsCopy) return SS.Section->OutSec; break; @@ -2003,24 +2003,27 @@ VersionNeedSection<ELFT>::VersionNeedSection() } template <class ELFT> -void VersionNeedSection<ELFT>::addSymbol(SharedSymbol<ELFT> *SS) { - if (!SS->Verdef) { +void VersionNeedSection<ELFT>::addSymbol(SharedSymbol *SS) { + auto *Ver = reinterpret_cast<const typename ELFT::Verdef *>(SS->Verdef); + if (!Ver) { SS->symbol()->VersionId = VER_NDX_GLOBAL; return; } - SharedFile<ELFT> *F = SS->file(); + + auto *File = cast<SharedFile<ELFT>>(SS->File); + // If we don't already know that we need an Elf_Verneed for this DSO, prepare // to create one by adding it to our needed list and creating a dynstr entry // for the soname. - if (F->VerdefMap.empty()) - Needed.push_back({F, In<ELFT>::DynStrTab->addString(F->getSoName())}); - typename SharedFile<ELFT>::NeededVer &NV = F->VerdefMap[SS->Verdef]; + if (File->VerdefMap.empty()) + Needed.push_back({File, In<ELFT>::DynStrTab->addString(File->getSoName())}); + typename SharedFile<ELFT>::NeededVer &NV = File->VerdefMap[Ver]; // If we don't already know that we need an Elf_Vernaux for this Elf_Verdef, // prepare to create one by allocating a version identifier and creating a // dynstr entry for the version name. if (NV.Index == 0) { - NV.StrTab = In<ELFT>::DynStrTab->addString( - SS->file()->getStringTable().data() + SS->Verdef->getAux()->vda_name); + NV.StrTab = In<ELFT>::DynStrTab->addString(File->getStringTable().data() + + Ver->getAux()->vda_name); NV.Index = NextIndex++; } SS->symbol()->VersionId = NV.Index; diff --git a/lld/ELF/SyntheticSections.h b/lld/ELF/SyntheticSections.h index 34a922da772..127dd9631c9 100644 --- a/lld/ELF/SyntheticSections.h +++ b/lld/ELF/SyntheticSections.h @@ -668,7 +668,7 @@ class VersionNeedSection final : public SyntheticSection<ELFT> { public: VersionNeedSection(); - void addSymbol(SharedSymbol<ELFT> *SS); + void addSymbol(SharedSymbol *SS); void finalize() override; void writeTo(uint8_t *Buf) override; size_t getSize() const override; diff --git a/lld/ELF/Writer.cpp b/lld/ELF/Writer.cpp index 445fe723934..7f0ec1f4bac 100644 --- a/lld/ELF/Writer.cpp +++ b/lld/ELF/Writer.cpp @@ -1112,8 +1112,8 @@ template <class ELFT> void Writer<ELFT>::finalizeSections() { if (In<ELFT>::DynSymTab && S->includeInDynsym()) { In<ELFT>::DynSymTab->addGlobal(Body); - if (auto *SS = dyn_cast<SharedSymbol<ELFT>>(Body)) - if (SS->file()->isNeeded()) + if (auto *SS = dyn_cast<SharedSymbol>(Body)) + if (cast<SharedFile<ELFT>>(SS->File)->isNeeded()) In<ELFT>::VerNeed->addSymbol(SS); } } |