Skip to content

Commit

Permalink
lld: add experimental support for SHT_RELR sections.
Browse files Browse the repository at this point in the history
Patch by Rahul Chaudhry!

This change adds experimental support for SHT_RELR sections, proposed
here: https://groups.google.com/forum/#!topic/generic-abi/bX460iggiKg

Pass '--pack-dyn-relocs=relr' to enable generation of SHT_RELR section
and DT_RELR, DT_RELRSZ, and DT_RELRENT dynamic tags.

Definitions for the new ELF section type and dynamic array tags, as well
as the encoding used in the new section are all under discussion and are
subject to change. Use with caution!

Pass '--use-android-relr-tags' with '--pack-dyn-relocs=relr' to use
SHT_ANDROID_RELR section type instead of SHT_RELR, as well as
DT_ANDROID_RELR* dynamic tags instead of DT_RELR*. The generated
section contents are identical.

'--pack-dyn-relocs=android+relr --use-android-relr-tags' enables both
'--pack-dyn-relocs=android' and '--pack-dyn-relocs=relr': lld will
encode the relative relocations in a SHT_ANDROID_RELR section, and pack
the rest of the dynamic relocations in a SHT_ANDROID_REL(A) section.

Differential Revision: https://reviews.llvm.org/D48247

llvm-svn: 336594
  • Loading branch information
rui314 committed Jul 9, 2018
1 parent 7139dea commit 11479da
Show file tree
Hide file tree
Showing 9 changed files with 462 additions and 124 deletions.
2 changes: 2 additions & 0 deletions lld/ELF/Config.h
Original file line number Diff line number Diff line change
Expand Up @@ -153,6 +153,7 @@ struct Configuration {
bool PrintGcSections;
bool PrintIcfSections;
bool Relocatable;
bool RelrPackDynRelocs = false;
bool SaveTemps;
bool SingleRoRx;
bool Shared;
Expand All @@ -163,6 +164,7 @@ struct Configuration {
bool ThinLTOEmitImportsFiles;
bool ThinLTOIndexOnly;
bool UndefinedVersion;
bool UseAndroidRelrTags = false;
bool WarnBackrefs;
bool WarnCommon;
bool WarnMissingEntry;
Expand Down
12 changes: 10 additions & 2 deletions lld/ELF/Driver.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -794,6 +794,8 @@ void LinkerDriver::readConfigs(opt::InputArgList &Args) {
Config->Undefined = args::getStrings(Args, OPT_undefined);
Config->UndefinedVersion =
Args.hasFlag(OPT_undefined_version, OPT_no_undefined_version, true);
Config->UseAndroidRelrTags = Args.hasFlag(
OPT_use_android_relr_tags, OPT_no_use_android_relr_tags, false);
Config->UnresolvedSymbols = getUnresolvedSymbolPolicy(Args);
Config->WarnBackrefs =
Args.hasFlag(OPT_warn_backrefs, OPT_no_warn_backrefs, false);
Expand Down Expand Up @@ -873,10 +875,16 @@ void LinkerDriver::readConfigs(opt::InputArgList &Args) {

if (auto *Arg = Args.getLastArg(OPT_pack_dyn_relocs)) {
StringRef S = Arg->getValue();
if (S == "android")
if (S == "android") {
Config->AndroidPackDynRelocs = true;
else if (S != "none")
} else if (S == "relr") {
Config->RelrPackDynRelocs = true;
} else if (S == "android+relr") {
Config->AndroidPackDynRelocs = true;
Config->RelrPackDynRelocs = true;
} else if (S != "none") {
error("unknown -pack-dyn-relocs format: " + S);
}
}

if (auto *Arg = Args.getLastArg(OPT_symbol_ordering_file))
Expand Down
3 changes: 2 additions & 1 deletion lld/ELF/LinkerScript.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -414,7 +414,8 @@ LinkerScript::computeInputSections(const InputSectionDescription *Cmd) {
void LinkerScript::discard(ArrayRef<InputSection *> V) {
for (InputSection *S : V) {
if (S == InX::ShStrTab || S == InX::Dynamic || S == InX::DynSymTab ||
S == InX::DynStrTab || S == InX::RelaPlt || S == InX::RelaDyn)
S == InX::DynStrTab || S == InX::RelaPlt || S == InX::RelaDyn ||
S == InX::RelrDyn)
error("discarding " + S->Name + " section is not allowed");

// You can discard .hash and .gnu.hash sections by linker scripts. Since
Expand Down
6 changes: 5 additions & 1 deletion lld/ELF/Options.td
Original file line number Diff line number Diff line change
Expand Up @@ -233,7 +233,11 @@ defm orphan_handling:

defm pack_dyn_relocs:
Eq<"pack-dyn-relocs", "Pack dynamic relocations in the given format">,
MetaVarName<"[none,android]">;
MetaVarName<"[none,android,relr,android+relr]">;

defm use_android_relr_tags: B<"use-android-relr-tags",
"use SHT_ANDROID_RELR / DT_ANDROID_RELR* tags instead of SHT_RELR / DT_RELR*",
"use SHT_RELR / DT_RELR* tags (default)">;

defm pie: B<"pie",
"Create a position independent executable",
Expand Down
35 changes: 25 additions & 10 deletions lld/ELF/Relocations.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -717,6 +717,24 @@ class OffsetGetter {
};
} // namespace

static void addRelativeReloc(InputSectionBase *IS, uint64_t OffsetInSec,
Symbol *Sym, int64_t Addend, RelExpr Expr,
RelType Type) {
// Add a relative relocation. If RelrDyn section is enabled, and the
// relocation offset is guaranteed to be even, add the relocation to
// the RelrDyn section, otherwise add it to the RelaDyn section.
// RelrDyn sections don't support odd offsets. Also, RelrDyn sections
// don't store the addend values, so we must write it to the relocated
// address.
if (InX::RelrDyn && IS->Alignment >= 2 && OffsetInSec % 2 == 0) {
IS->Relocations.push_back({Expr, Type, OffsetInSec, Addend, Sym});
InX::RelrDyn->Relocs.push_back({IS, OffsetInSec});
return;
}
InX::RelaDyn->addReloc(Target->RelativeRel, IS, OffsetInSec, Sym, Addend,
Expr, Type);
}

template <class ELFT, class GotPltSection>
static void addPltEntry(PltSection *Plt, GotPltSection *GotPlt,
RelocationBaseSection *Rel, RelType Type, Symbol &Sym) {
Expand Down Expand Up @@ -748,14 +766,12 @@ template <class ELFT> static void addGotEntry(Symbol &Sym) {

// Otherwise, we emit a dynamic relocation to .rel[a].dyn so that
// the GOT slot will be fixed at load-time.
RelType Type;
if (Sym.isTls())
Type = Target->TlsGotRel;
else if (!Sym.IsPreemptible && Config->Pic && !isAbsolute(Sym))
Type = Target->RelativeRel;
else
Type = Target->GotRel;
InX::RelaDyn->addReloc(Type, InX::Got, Off, &Sym, 0,
if (!Sym.isTls() && !Sym.IsPreemptible && Config->Pic && !isAbsolute(Sym)) {
addRelativeReloc(InX::Got, Off, &Sym, 0, R_ABS, Target->GotRel);
return;
}
InX::RelaDyn->addReloc(Sym.isTls() ? Target->TlsGotRel : Target->GotRel,
InX::Got, Off, &Sym, 0,
Sym.IsPreemptible ? R_ADDEND : R_ABS, Target->GotRel);
}

Expand Down Expand Up @@ -806,8 +822,7 @@ static void processRelocAux(InputSectionBase &Sec, RelExpr Expr, RelType Type,
bool IsPreemptibleValue = Sym.IsPreemptible && Expr != R_GOT;

if (!IsPreemptibleValue) {
InX::RelaDyn->addReloc(Target->RelativeRel, &Sec, Offset, &Sym, Addend,
Expr, Type);
addRelativeReloc(&Sec, Offset, &Sym, Addend, Expr, Type);
return;
} else if (RelType Rel = Target->getDynRel(Type)) {
InX::RelaDyn->addReloc(Rel, &Sec, Offset, &Sym, Addend, R_ADDEND, Type);
Expand Down
110 changes: 110 additions & 0 deletions lld/ELF/SyntheticSections.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1294,6 +1294,14 @@ template <class ELFT> void DynamicSection<ELFT>::finalizeContents() {
addInt(IsRela ? DT_RELACOUNT : DT_RELCOUNT, NumRelativeRels);
}
}
if (InX::RelrDyn && !InX::RelrDyn->Relocs.empty()) {
addInSec(Config->UseAndroidRelrTags ? DT_ANDROID_RELR : DT_RELR,
InX::RelrDyn);
addSize(Config->UseAndroidRelrTags ? DT_ANDROID_RELRSZ : DT_RELRSZ,
InX::RelrDyn->getParent());
addInt(Config->UseAndroidRelrTags ? DT_ANDROID_RELRENT : DT_RELRENT,
sizeof(Elf_Relr));
}
// .rel[a].plt section usually consists of two parts, containing plt and
// iplt relocations. It is possible to have only iplt relocations in the
// output. In that case RelaPlt is empty and have zero offset, the same offset
Expand Down Expand Up @@ -1466,6 +1474,11 @@ void RelocationBaseSection::finalizeContents() {
getParent()->Link = Link;
}

RelrBaseSection::RelrBaseSection()
: SyntheticSection(SHF_ALLOC,
Config->UseAndroidRelrTags ? SHT_ANDROID_RELR : SHT_RELR,
Config->Wordsize, ".relr.dyn") {}

template <class ELFT>
static void encodeDynamicReloc(typename ELFT::Rela *P,
const DynamicReloc &Rel) {
Expand Down Expand Up @@ -1694,6 +1707,97 @@ bool AndroidPackedRelocationSection<ELFT>::updateAllocSize() {
return RelocData.size() != OldSize;
}

template <class ELFT> RelrSection<ELFT>::RelrSection() {
this->Entsize = Config->Wordsize;
}

template <class ELFT> bool RelrSection<ELFT>::updateAllocSize() {
// This function computes the contents of an SHT_RELR packed relocation
// section.
//
// Proposal for adding SHT_RELR sections to generic-abi is here:
// https://groups.google.com/forum/#!topic/generic-abi/bX460iggiKg
//
// The encoded sequence of Elf64_Relr entries in a SHT_RELR section looks
// like [ AAAAAAAA BBBBBBB1 BBBBBBB1 ... AAAAAAAA BBBBBB1 ... ]
//
// i.e. start with an address, followed by any number of bitmaps. The address
// entry encodes 1 relocation. The subsequent bitmap entries encode up to 63
// relocations each, at subsequent offsets following the last address entry.
//
// The bitmap entries must have 1 in the least significant bit. The assumption
// here is that an address cannot have 1 in lsb. Odd addresses are not
// supported.
//
// Excluding the least significant bit in the bitmap, each non-zero bit in
// the bitmap represents a relocation to be applied to a corresponding machine
// word that follows the base address word. The second least significant bit
// represents the machine word immediately following the initial address, and
// each bit that follows represents the next word, in linear order. As such,
// a single bitmap can encode up to 31 relocations in a 32-bit object, and
// 63 relocations in a 64-bit object.
//
// This encoding has a couple of interesting properties:
// 1. Looking at any entry, it is clear whether it's an address or a bitmap:
// even means address, odd means bitmap.
// 2. Just a simple list of addresses is a valid encoding.

size_t OldSize = RelrRelocs.size();
RelrRelocs.clear();

// Number of bits to use for the relocation offsets bitmap.
// These many relative relocations can be encoded in a single entry.
const size_t NBits = 8 * Config->Wordsize - 1;

// Get offsets for all relative relocations and sort them.
std::vector<uint64_t> Offsets;
for (const RelativeReloc &Rel : Relocs) {
Offsets.push_back(Rel.getOffset());
}
std::sort(Offsets.begin(), Offsets.end());

uint64_t Base = 0;
typename std::vector<uint64_t>::iterator Curr = Offsets.begin();
while (Curr != Offsets.end()) {
uint64_t Current = *Curr;
assert(Current % 2 == 0);

uint64_t Bits = 0;
typename std::vector<uint64_t>::iterator Next = Curr;
if (Base > 0 && Base <= Current) {
while (Next != Offsets.end()) {
uint64_t Delta = *Next - Base;
// If Next is too far out, it cannot be folded into Curr.
if (Delta >= NBits * Config->Wordsize)
break;
// If Next is not a multiple of wordsize away, it cannot
// be folded into Curr.
if (Delta % Config->Wordsize != 0)
break;
// Next can be folded into Curr, add it to the bitmap.
Bits |= 1ULL << (Delta / Config->Wordsize);
++Next;
}
}

if (Bits == 0) {
RelrRelocs.push_back(Elf_Relr(Current));
// This is not a continuation entry, only one offset was
// consumed. Set base offset for subsequent bitmap entries.
Base = Current + Config->Wordsize;
++Curr;
} else {
RelrRelocs.push_back(Elf_Relr((Bits << 1) | 1));
// This is a continuation entry encoding multiple offsets
// in a bitmap. Advance base offset by NBits words.
Base += NBits * Config->Wordsize;
Curr = Next;
}
}

return RelrRelocs.size() != OldSize;
}

SymbolTableBaseSection::SymbolTableBaseSection(StringTableSection &StrTabSec)
: SyntheticSection(StrTabSec.isDynamic() ? (uint64_t)SHF_ALLOC : 0,
StrTabSec.isDynamic() ? SHT_DYNSYM : SHT_SYMTAB,
Expand Down Expand Up @@ -2893,6 +2997,7 @@ MipsRldMapSection *InX::MipsRldMap;
PltSection *InX::Plt;
PltSection *InX::Iplt;
RelocationBaseSection *InX::RelaDyn;
RelrBaseSection *InX::RelrDyn;
RelocationBaseSection *InX::RelaPlt;
RelocationBaseSection *InX::RelaIplt;
StringTableSection *InX::ShStrTab;
Expand Down Expand Up @@ -2954,6 +3059,11 @@ template class elf::AndroidPackedRelocationSection<ELF32BE>;
template class elf::AndroidPackedRelocationSection<ELF64LE>;
template class elf::AndroidPackedRelocationSection<ELF64BE>;

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

template class elf::SymbolTableSection<ELF32LE>;
template class elf::SymbolTableSection<ELF32BE>;
template class elf::SymbolTableSection<ELF64LE>;
Expand Down
35 changes: 35 additions & 0 deletions lld/ELF/SyntheticSections.h
Original file line number Diff line number Diff line change
Expand Up @@ -438,6 +438,7 @@ template <class ELFT> class DynamicSection final : public SyntheticSection {
typedef typename ELFT::Dyn Elf_Dyn;
typedef typename ELFT::Rel Elf_Rel;
typedef typename ELFT::Rela Elf_Rela;
typedef typename ELFT::Relr Elf_Relr;
typedef typename ELFT::Shdr Elf_Shdr;
typedef typename ELFT::Sym Elf_Sym;

Expand Down Expand Up @@ -517,6 +518,39 @@ class AndroidPackedRelocationSection final : public RelocationBaseSection {
SmallVector<char, 0> RelocData;
};

struct RelativeReloc {
uint64_t getOffset() const { return InputSec->getVA(OffsetInSec); }

const InputSectionBase *InputSec;
uint64_t OffsetInSec;
};

class RelrBaseSection : public SyntheticSection {
public:
RelrBaseSection();
std::vector<RelativeReloc> Relocs;
};

// RelrSection is used to encode offsets for relative relocations.
// Proposal for adding SHT_RELR sections to generic-abi is here:
// https://groups.google.com/forum/#!topic/generic-abi/bX460iggiKg
// For more details, see the comment in RelrSection::updateAllocSize().
template <class ELFT> class RelrSection final : public RelrBaseSection {
typedef typename ELFT::Relr Elf_Relr;

public:
RelrSection();

bool updateAllocSize() override;
size_t getSize() const override { return RelrRelocs.size() * this->Entsize; }
void writeTo(uint8_t *Buf) override {
memcpy(Buf, RelrRelocs.data(), getSize());
}

private:
std::vector<Elf_Relr> RelrRelocs;
};

struct SymbolTableEntry {
Symbol *Sym;
size_t StrTabOffset;
Expand Down Expand Up @@ -958,6 +992,7 @@ struct InX {
static PltSection *Plt;
static PltSection *Iplt;
static RelocationBaseSection *RelaDyn;
static RelrBaseSection *RelrDyn;
static RelocationBaseSection *RelaPlt;
static RelocationBaseSection *RelaIplt;
static StringTableSection *ShStrTab;
Expand Down
22 changes: 15 additions & 7 deletions lld/ELF/Writer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -349,6 +349,11 @@ template <class ELFT> static void createSyntheticSections() {
Add(InX::RelaDyn);
}

if (Config->RelrPackDynRelocs) {
InX::RelrDyn = make<RelrSection<ELFT>>();
Add(InX::RelrDyn);
}

// Add .got. MIPS' .got is so different from the other archs,
// it has its own class.
if (Config->EMachine == EM_MIPS) {
Expand Down Expand Up @@ -1646,12 +1651,12 @@ template <class ELFT> void Writer<ELFT>::finalizeSections() {
// Dynamic section must be the last one in this list and dynamic
// symbol table section (DynSymTab) must be the first one.
applySynthetic(
{InX::DynSymTab, InX::Bss, InX::BssRelRo, InX::GnuHashTab,
InX::HashTab, InX::SymTab, InX::ShStrTab, InX::StrTab,
In<ELFT>::VerDef, InX::DynStrTab, InX::Got, InX::MipsGot,
InX::IgotPlt, InX::GotPlt, InX::RelaDyn, InX::RelaIplt,
InX::RelaPlt, InX::Plt, InX::Iplt, InX::EhFrameHdr,
In<ELFT>::VerSym, In<ELFT>::VerNeed, InX::Dynamic},
{InX::DynSymTab, InX::Bss, InX::BssRelRo, InX::GnuHashTab,
InX::HashTab, InX::SymTab, InX::ShStrTab, InX::StrTab,
In<ELFT>::VerDef, InX::DynStrTab, InX::Got, InX::MipsGot,
InX::IgotPlt, InX::GotPlt, InX::RelaDyn, InX::RelrDyn,
InX::RelaIplt, InX::RelaPlt, InX::Plt, InX::Iplt,
InX::EhFrameHdr, In<ELFT>::VerSym, In<ELFT>::VerNeed, InX::Dynamic},
[](SyntheticSection *SS) { SS->finalizeContents(); });

if (!Script->HasSectionsCommand && !Config->Relocatable)
Expand All @@ -1666,7 +1671,8 @@ template <class ELFT> void Writer<ELFT>::finalizeSections() {
// for jump instructions that is the linker's responsibility for creating
// range extension thunks for. As the generation of the content may also
// alter InputSection addresses we must converge to a fixed point.
if (Target->NeedsThunks || Config->AndroidPackDynRelocs) {
if (Target->NeedsThunks || Config->AndroidPackDynRelocs ||
Config->RelrPackDynRelocs) {
ThunkCreator TC;
AArch64Err843419Patcher A64P;
bool Changed;
Expand All @@ -1683,6 +1689,8 @@ template <class ELFT> void Writer<ELFT>::finalizeSections() {
if (InX::MipsGot)
InX::MipsGot->updateAllocSize();
Changed |= InX::RelaDyn->updateAllocSize();
if (InX::RelrDyn)
Changed |= InX::RelrDyn->updateAllocSize();
} while (Changed);
}

Expand Down
Loading

0 comments on commit 11479da

Please sign in to comment.