Skip to content

Commit

Permalink
[ELF] ifunc implementation using synthetic sections
Browse files Browse the repository at this point in the history
This change introduces new synthetic sections IpltSection, IgotPltSection
that represent the ifunc entries that would previously have been put in
the PltSection and the GotPltSection. The separation makes sure that
the R_*_IRELATIVE relocations are placed after the non R_*_IRELATIVE
relocations, which permits ifunc resolvers to know that the .got.plt
slots will be initialized prior to the resolver being called.

A secondary benefit is that for ARM we can move the IgotPltSection and its
dynamic relocations to the .got and .rel.dyn as the ARM glibc expects all
the R_*_IRELATIVE relocations to be in the .rel.dyn

Differential revision: https://reviews.llvm.org/D27406

llvm-svn: 289045
  • Loading branch information
smithp35 committed Dec 8, 2016
1 parent 0f77869 commit baffdb8
Show file tree
Hide file tree
Showing 16 changed files with 621 additions and 162 deletions.
24 changes: 13 additions & 11 deletions lld/ELF/Relocations.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -719,18 +719,20 @@ static void scanRelocs(InputSectionBase<ELFT> &C, ArrayRef<RelTy> Rels) {
if (needsPlt(Expr)) {
if (Body.isInPlt())
continue;
In<ELFT>::Plt->addEntry(Body);

uint32_t Rel;
if (Body.isGnuIFunc() && !Preemptible)
Rel = Target->IRelativeRel;
else
Rel = Target->PltRel;

In<ELFT>::GotPlt->addEntry(Body);
In<ELFT>::RelaPlt->addReloc({Rel, In<ELFT>::GotPlt,
Body.getGotPltOffset<ELFT>(), !Preemptible,
&Body, 0});
if (Body.isGnuIFunc() && !Preemptible) {
In<ELFT>::Iplt->addEntry(Body);
In<ELFT>::IgotPlt->addEntry(Body);
In<ELFT>::RelaIplt->addReloc({Target->IRelativeRel, In<ELFT>::IgotPlt,
Body.getGotPltOffset<ELFT>(),
!Preemptible, &Body, 0});
} else {
In<ELFT>::Plt->addEntry(Body);
In<ELFT>::GotPlt->addEntry(Body);
In<ELFT>::RelaPlt->addReloc({Target->PltRel, In<ELFT>::GotPlt,
Body.getGotPltOffset<ELFT>(), !Preemptible,
&Body, 0});
}
continue;
}

Expand Down
8 changes: 6 additions & 2 deletions lld/ELF/Symbols.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -95,8 +95,8 @@ static typename ELFT::uint getSymVA(const SymbolBody &Body,
SymbolBody::SymbolBody(Kind K, StringRefZ Name, bool IsLocal, uint8_t StOther,
uint8_t Type)
: SymbolKind(K), NeedsCopyOrPltAddr(false), IsLocal(IsLocal),
IsInGlobalMipsGot(false), Is32BitMipsGot(false), Type(Type),
StOther(StOther), Name(Name) {}
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.
Expand Down Expand Up @@ -151,6 +151,8 @@ template <class ELFT> typename ELFT::uint SymbolBody::getGotOffset() const {
}

template <class ELFT> typename ELFT::uint SymbolBody::getGotPltVA() const {
if (this->IsInIgot)
return In<ELFT>::IgotPlt->getVA() + getGotPltOffset<ELFT>();
return In<ELFT>::GotPlt->getVA() + getGotPltOffset<ELFT>();
}

Expand All @@ -159,6 +161,8 @@ template <class ELFT> typename ELFT::uint SymbolBody::getGotPltOffset() const {
}

template <class ELFT> typename ELFT::uint SymbolBody::getPltVA() const {
if (this->IsInIplt)
return In<ELFT>::Iplt->getVA() + PltIndex * Target->PltEntrySize;
return In<ELFT>::Plt->getVA() + Target->PltHeaderSize +
PltIndex * Target->PltEntrySize;
}
Expand Down
6 changes: 6 additions & 0 deletions lld/ELF/Symbols.h
Original file line number Diff line number Diff line change
Expand Up @@ -117,6 +117,12 @@ class SymbolBody {
// True if this symbol is referenced by 32-bit GOT relocations.
unsigned Is32BitMipsGot : 1;

// True if this symbol is in the Iplt sub-section of the Plt.
unsigned IsInIplt : 1;

// True if this symbol is in the Igot sub-section of the .got.plt or .got.
unsigned IsInIgot : 1;

// The following fields have the same meaning as the ELF symbol attributes.
uint8_t Type; // symbol type
uint8_t StOther; // st_other field value
Expand Down
79 changes: 74 additions & 5 deletions lld/ELF/SyntheticSections.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -707,6 +707,36 @@ template <class ELFT> void GotPltSection<ELFT>::writeTo(uint8_t *Buf) {
}
}

// On ARM the IgotPltSection is part of the GotSection, on other Targets it is
// part of the .got.plt
template <class ELFT>
IgotPltSection<ELFT>::IgotPltSection()
: SyntheticSection<ELFT>(SHF_ALLOC | SHF_WRITE, SHT_PROGBITS,
Target->GotPltEntrySize,
Config->EMachine == EM_ARM ? ".got" : ".got.plt") {
}

template <class ELFT> void IgotPltSection<ELFT>::addEntry(SymbolBody &Sym) {
Sym.IsInIgot = true;
Sym.GotPltIndex = Entries.size();
Entries.push_back(&Sym);
}

template <class ELFT> size_t IgotPltSection<ELFT>::getSize() const {
return Entries.size() * Target->GotPltEntrySize;
}

template <class ELFT> void IgotPltSection<ELFT>::writeTo(uint8_t *Buf) {
for (const SymbolBody *B : Entries) {
if (Config->EMachine == EM_ARM)
// On ARM we are actually part of the Got and not GotPlt.
write32le(Buf, B->getVA<ELFT>());
else
Target->writeGotPlt(Buf, *B);
Buf += sizeof(uintX_t);
}
}

template <class ELFT>
StringTableSection<ELFT>::StringTableSection(StringRef Name, bool Dynamic)
: SyntheticSection<ELFT>(Dynamic ? (uintX_t)SHF_ALLOC : 0, SHT_STRTAB, 1,
Expand Down Expand Up @@ -805,11 +835,10 @@ template <class ELFT> void DynamicSection<ELFT>::finalize() {
return; // Already finalized.

this->Link = In<ELFT>::DynStrTab->OutSec->SectionIndex;

if (!In<ELFT>::RelaDyn->empty()) {
if (In<ELFT>::RelaDyn->OutSec->Size > 0) {
bool IsRela = Config->Rela;
add({IsRela ? DT_RELA : DT_REL, In<ELFT>::RelaDyn});
add({IsRela ? DT_RELASZ : DT_RELSZ, In<ELFT>::RelaDyn->getSize()});
add({IsRela ? DT_RELASZ : DT_RELSZ, In<ELFT>::RelaDyn->OutSec->Size});
add({IsRela ? DT_RELAENT : DT_RELENT,
uintX_t(IsRela ? sizeof(Elf_Rela) : sizeof(Elf_Rel))});

Expand All @@ -822,9 +851,9 @@ template <class ELFT> void DynamicSection<ELFT>::finalize() {
add({IsRela ? DT_RELACOUNT : DT_RELCOUNT, NumRelativeRels});
}
}
if (!In<ELFT>::RelaPlt->empty()) {
if (In<ELFT>::RelaPlt->OutSec->Size > 0) {
add({DT_JMPREL, In<ELFT>::RelaPlt});
add({DT_PLTRELSZ, In<ELFT>::RelaPlt->getSize()});
add({DT_PLTRELSZ, In<ELFT>::RelaPlt->OutSec->Size});
add({Config->EMachine == EM_MIPS ? DT_MIPS_PLTGOT : DT_PLTGOT,
In<ELFT>::GotPlt});
add({DT_PLTREL, uint64_t(Config->Rela ? DT_RELA : DT_REL)});
Expand Down Expand Up @@ -1400,6 +1429,36 @@ template <class ELFT> size_t PltSection<ELFT>::getSize() const {
return Target->PltHeaderSize + Entries.size() * Target->PltEntrySize;
}

template <class ELFT>
IpltSection<ELFT>::IpltSection()
: SyntheticSection<ELFT>(SHF_ALLOC | SHF_EXECINSTR, SHT_PROGBITS, 16,
".plt") {}

template <class ELFT> void IpltSection<ELFT>::writeTo(uint8_t *Buf) {
// The IRelative relocations do not support lazy binding so no header is
// needed
size_t Off = 0;
for (auto &I : Entries) {
const SymbolBody *B = I.first;
unsigned RelOff = I.second + In<ELFT>::Plt->getSize();
uint64_t Got = B->getGotPltVA<ELFT>();
uint64_t Plt = this->getVA() + Off;
Target->writePlt(Buf + Off, Got, Plt, B->PltIndex, RelOff);
Off += Target->PltEntrySize;
}
}

template <class ELFT> void IpltSection<ELFT>::addEntry(SymbolBody &Sym) {
Sym.PltIndex = Entries.size();
Sym.IsInIplt = true;
unsigned RelOff = In<ELFT>::RelaIplt->getRelocOffset();
Entries.push_back(std::make_pair(&Sym, RelOff));
}

template <class ELFT> size_t IpltSection<ELFT>::getSize() const {
return Entries.size() * Target->PltEntrySize;
}

template <class ELFT>
GdbIndexSection<ELFT>::GdbIndexSection()
: SyntheticSection<ELFT>(0, SHT_PROGBITS, 1, ".gdb_index") {}
Expand Down Expand Up @@ -1750,6 +1809,11 @@ template class elf::GotPltSection<ELF32BE>;
template class elf::GotPltSection<ELF64LE>;
template class elf::GotPltSection<ELF64BE>;

template class elf::IgotPltSection<ELF32LE>;
template class elf::IgotPltSection<ELF32BE>;
template class elf::IgotPltSection<ELF64LE>;
template class elf::IgotPltSection<ELF64BE>;

template class elf::StringTableSection<ELF32LE>;
template class elf::StringTableSection<ELF32BE>;
template class elf::StringTableSection<ELF64LE>;
Expand Down Expand Up @@ -1785,6 +1849,11 @@ template class elf::PltSection<ELF32BE>;
template class elf::PltSection<ELF64LE>;
template class elf::PltSection<ELF64BE>;

template class elf::IpltSection<ELF32LE>;
template class elf::IpltSection<ELF32BE>;
template class elf::IpltSection<ELF64LE>;
template class elf::IpltSection<ELF64BE>;

template class elf::GdbIndexSection<ELF32LE>;
template class elf::GdbIndexSection<ELF32BE>;
template class elf::GdbIndexSection<ELF64LE>;
Expand Down
40 changes: 40 additions & 0 deletions lld/ELF/SyntheticSections.h
Original file line number Diff line number Diff line change
Expand Up @@ -206,6 +206,25 @@ class GotPltSection final : public SyntheticSection<ELFT> {
std::vector<const SymbolBody *> Entries;
};

// The IgotPltSection is a Got associated with the IpltSection for GNU Ifunc
// Symbols that will be relocated by Target->IRelativeRel.
// On most Targets the IgotPltSection will immediately follow the GotPltSection
// on ARM the IgotPltSection will immediately follow the GotSection.
template <class ELFT>
class IgotPltSection final : public SyntheticSection<ELFT> {
typedef typename ELFT::uint uintX_t;

public:
IgotPltSection();
void addEntry(SymbolBody &Sym);
size_t getSize() const override;
void writeTo(uint8_t *Buf) override;
bool empty() const override { return Entries.empty(); }

private:
std::vector<const SymbolBody *> Entries;
};

template <class ELFT>
class StringTableSection final : public SyntheticSection<ELFT> {
public:
Expand Down Expand Up @@ -431,6 +450,21 @@ template <class ELFT> class PltSection final : public SyntheticSection<ELFT> {
std::vector<std::pair<const SymbolBody *, unsigned>> Entries;
};

// The IpltSection is a variant of Plt for recording entries for GNU Ifunc
// symbols that will be subject to a Target->IRelativeRel
// The IpltSection immediately follows the Plt section in the Output Section
template <class ELFT> class IpltSection final : public SyntheticSection<ELFT> {
public:
IpltSection();
void writeTo(uint8_t *Buf) override;
size_t getSize() const override;
void addEntry(SymbolBody &Sym);
bool empty() const override { return Entries.empty(); }

private:
std::vector<std::pair<const SymbolBody *, unsigned>> Entries;
};

template <class ELFT>
class GdbIndexSection final : public SyntheticSection<ELFT> {
typedef typename ELFT::uint uintX_t;
Expand Down Expand Up @@ -644,12 +678,15 @@ template <class ELFT> struct In {
static GotSection<ELFT> *Got;
static MipsGotSection<ELFT> *MipsGot;
static GotPltSection<ELFT> *GotPlt;
static IgotPltSection<ELFT> *IgotPlt;
static HashTableSection<ELFT> *HashTab;
static InputSection<ELFT> *Interp;
static MipsRldMapSection<ELFT> *MipsRldMap;
static PltSection<ELFT> *Plt;
static IpltSection<ELFT> *Iplt;
static RelocationSection<ELFT> *RelaDyn;
static RelocationSection<ELFT> *RelaPlt;
static RelocationSection<ELFT> *RelaIplt;
static StringTableSection<ELFT> *ShStrTab;
static StringTableSection<ELFT> *StrTab;
static SymbolTableSection<ELFT> *SymTab;
Expand All @@ -669,12 +706,15 @@ template <class ELFT> GnuHashTableSection<ELFT> *In<ELFT>::GnuHashTab;
template <class ELFT> GotSection<ELFT> *In<ELFT>::Got;
template <class ELFT> MipsGotSection<ELFT> *In<ELFT>::MipsGot;
template <class ELFT> GotPltSection<ELFT> *In<ELFT>::GotPlt;
template <class ELFT> IgotPltSection<ELFT> *In<ELFT>::IgotPlt;
template <class ELFT> HashTableSection<ELFT> *In<ELFT>::HashTab;
template <class ELFT> InputSection<ELFT> *In<ELFT>::Interp;
template <class ELFT> MipsRldMapSection<ELFT> *In<ELFT>::MipsRldMap;
template <class ELFT> PltSection<ELFT> *In<ELFT>::Plt;
template <class ELFT> IpltSection<ELFT> *In<ELFT>::Iplt;
template <class ELFT> RelocationSection<ELFT> *In<ELFT>::RelaDyn;
template <class ELFT> RelocationSection<ELFT> *In<ELFT>::RelaPlt;
template <class ELFT> RelocationSection<ELFT> *In<ELFT>::RelaIplt;
template <class ELFT> StringTableSection<ELFT> *In<ELFT>::ShStrTab;
template <class ELFT> StringTableSection<ELFT> *In<ELFT>::StrTab;
template <class ELFT> SymbolTableSection<ELFT> *In<ELFT>::SymTab;
Expand Down
27 changes: 20 additions & 7 deletions lld/ELF/Writer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -356,6 +356,8 @@ template <class ELFT> void Writer<ELFT>::createSyntheticSections() {

In<ELFT>::GotPlt = make<GotPltSection<ELFT>>();
Symtab<ELFT>::X->Sections.push_back(In<ELFT>::GotPlt);
In<ELFT>::IgotPlt = make<IgotPltSection<ELFT>>();
Symtab<ELFT>::X->Sections.push_back(In<ELFT>::IgotPlt);

if (Config->GdbIndex) {
In<ELFT>::GdbIndex = make<GdbIndexSection<ELFT>>();
Expand All @@ -368,8 +370,17 @@ template <class ELFT> void Writer<ELFT>::createSyntheticSections() {
Config->Rela ? ".rela.plt" : ".rel.plt", false /*Sort*/);
Symtab<ELFT>::X->Sections.push_back(In<ELFT>::RelaPlt);

// The RelaIplt immediately follows .rel.plt (.rel.dyn for ARM) to ensure
// that the IRelative relocations are processed last by the dynamic loader
In<ELFT>::RelaIplt = make<RelocationSection<ELFT>>(
(Config->EMachine == EM_ARM) ? ".rel.dyn" : In<ELFT>::RelaPlt->Name,
false /*Sort*/);
Symtab<ELFT>::X->Sections.push_back(In<ELFT>::RelaIplt);

In<ELFT>::Plt = make<PltSection<ELFT>>();
Symtab<ELFT>::X->Sections.push_back(In<ELFT>::Plt);
In<ELFT>::Iplt = make<IpltSection<ELFT>>();
Symtab<ELFT>::X->Sections.push_back(In<ELFT>::Iplt);

if (Config->EhFrameHdr) {
In<ELFT>::EhFrameHdr = make<EhFrameHeader<ELFT>>();
Expand Down Expand Up @@ -651,10 +662,10 @@ template <class ELFT> void Writer<ELFT>::addRelIpltSymbols() {
if (In<ELFT>::DynSymTab)
return;
StringRef S = Config->Rela ? "__rela_iplt_start" : "__rel_iplt_start";
addOptionalRegular<ELFT>(S, In<ELFT>::RelaPlt, 0);
addOptionalRegular<ELFT>(S, In<ELFT>::RelaIplt, 0);

S = Config->Rela ? "__rela_iplt_end" : "__rel_iplt_end";
addOptionalRegular<ELFT>(S, In<ELFT>::RelaPlt, -1);
addOptionalRegular<ELFT>(S, In<ELFT>::RelaIplt, -1);
}

// The linker is expected to define some symbols depending on
Expand Down Expand Up @@ -1036,11 +1047,13 @@ template <class ELFT> void Writer<ELFT>::finalizeSections() {
// symbol table section (DynSymTab) must be the first one.
finalizeSynthetic<ELFT>(
{In<ELFT>::DynSymTab, In<ELFT>::GnuHashTab, In<ELFT>::HashTab,
In<ELFT>::SymTab, In<ELFT>::ShStrTab, In<ELFT>::StrTab, In<ELFT>::VerDef,
In<ELFT>::DynStrTab, In<ELFT>::GdbIndex, In<ELFT>::Got,
In<ELFT>::MipsGot, In<ELFT>::GotPlt, In<ELFT>::RelaDyn,
In<ELFT>::RelaPlt, In<ELFT>::Plt, In<ELFT>::EhFrameHdr, In<ELFT>::VerSym,
In<ELFT>::VerNeed, In<ELFT>::Dynamic});
In<ELFT>::SymTab, In<ELFT>::ShStrTab, In<ELFT>::StrTab,
In<ELFT>::VerDef, In<ELFT>::DynStrTab, In<ELFT>::GdbIndex,
In<ELFT>::Got, In<ELFT>::MipsGot, In<ELFT>::IgotPlt,
In<ELFT>::GotPlt, In<ELFT>::RelaDyn, In<ELFT>::RelaIplt,
In<ELFT>::RelaPlt, In<ELFT>::Plt, In<ELFT>::Iplt,
In<ELFT>::Plt, In<ELFT>::EhFrameHdr, In<ELFT>::VerSym,
In<ELFT>::VerNeed, In<ELFT>::Dynamic});
}

template <class ELFT> void Writer<ELFT>::addPredefinedSections() {
Expand Down
8 changes: 8 additions & 0 deletions lld/test/ELF/Inputs/arm-shared.s
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
.syntax unified
.global bar2
.type bar2, %function
bar2:

.global zed2
.type zed2, %function
zed2:
9 changes: 9 additions & 0 deletions lld/test/ELF/Inputs/shared2-x86-64.s
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
.global bar2
.type bar2, @function
bar2:
ret

.global zed2
.type zed2, @function
zed2:
ret

0 comments on commit baffdb8

Please sign in to comment.