forked from OSchip/llvm-project
De-template SharedSymbol.
Differential Revision: https://reviews.llvm.org/D30351 llvm-svn: 296303
This commit is contained in:
parent
4d5f70ddea
commit
4076fa1e21
|
@ -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.
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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); }
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue