Skip to content

Commit 11479da

Browse files
committed
lld: add experimental support for SHT_RELR sections.
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
1 parent 7139dea commit 11479da

File tree

Image for: File tree

9 files changed

Image for: 9 files changed
+462
-124
lines changed

9 files changed

Image for: 9 files changed
+462
-124
lines changed

‎lld/ELF/Config.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -153,6 +153,7 @@ struct Configuration {
153153
bool PrintGcSections;
154154
bool PrintIcfSections;
155155
bool Relocatable;
156+
bool RelrPackDynRelocs = false;
156157
bool SaveTemps;
157158
bool SingleRoRx;
158159
bool Shared;
@@ -163,6 +164,7 @@ struct Configuration {
163164
bool ThinLTOEmitImportsFiles;
164165
bool ThinLTOIndexOnly;
165166
bool UndefinedVersion;
167+
bool UseAndroidRelrTags = false;
166168
bool WarnBackrefs;
167169
bool WarnCommon;
168170
bool WarnMissingEntry;

‎lld/ELF/Driver.cpp

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -794,6 +794,8 @@ void LinkerDriver::readConfigs(opt::InputArgList &Args) {
794794
Config->Undefined = args::getStrings(Args, OPT_undefined);
795795
Config->UndefinedVersion =
796796
Args.hasFlag(OPT_undefined_version, OPT_no_undefined_version, true);
797+
Config->UseAndroidRelrTags = Args.hasFlag(
798+
OPT_use_android_relr_tags, OPT_no_use_android_relr_tags, false);
797799
Config->UnresolvedSymbols = getUnresolvedSymbolPolicy(Args);
798800
Config->WarnBackrefs =
799801
Args.hasFlag(OPT_warn_backrefs, OPT_no_warn_backrefs, false);
@@ -873,10 +875,16 @@ void LinkerDriver::readConfigs(opt::InputArgList &Args) {
873875

874876
if (auto *Arg = Args.getLastArg(OPT_pack_dyn_relocs)) {
875877
StringRef S = Arg->getValue();
876-
if (S == "android")
878+
if (S == "android") {
877879
Config->AndroidPackDynRelocs = true;
878-
else if (S != "none")
880+
} else if (S == "relr") {
881+
Config->RelrPackDynRelocs = true;
882+
} else if (S == "android+relr") {
883+
Config->AndroidPackDynRelocs = true;
884+
Config->RelrPackDynRelocs = true;
885+
} else if (S != "none") {
879886
error("unknown -pack-dyn-relocs format: " + S);
887+
}
880888
}
881889

882890
if (auto *Arg = Args.getLastArg(OPT_symbol_ordering_file))

‎lld/ELF/LinkerScript.cpp

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -414,7 +414,8 @@ LinkerScript::computeInputSections(const InputSectionDescription *Cmd) {
414414
void LinkerScript::discard(ArrayRef<InputSection *> V) {
415415
for (InputSection *S : V) {
416416
if (S == InX::ShStrTab || S == InX::Dynamic || S == InX::DynSymTab ||
417-
S == InX::DynStrTab || S == InX::RelaPlt || S == InX::RelaDyn)
417+
S == InX::DynStrTab || S == InX::RelaPlt || S == InX::RelaDyn ||
418+
S == InX::RelrDyn)
418419
error("discarding " + S->Name + " section is not allowed");
419420

420421
// You can discard .hash and .gnu.hash sections by linker scripts. Since

‎lld/ELF/Options.td

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -233,7 +233,11 @@ defm orphan_handling:
233233

234234
defm pack_dyn_relocs:
235235
Eq<"pack-dyn-relocs", "Pack dynamic relocations in the given format">,
236-
MetaVarName<"[none,android]">;
236+
MetaVarName<"[none,android,relr,android+relr]">;
237+
238+
defm use_android_relr_tags: B<"use-android-relr-tags",
239+
"use SHT_ANDROID_RELR / DT_ANDROID_RELR* tags instead of SHT_RELR / DT_RELR*",
240+
"use SHT_RELR / DT_RELR* tags (default)">;
237241

238242
defm pie: B<"pie",
239243
"Create a position independent executable",

‎lld/ELF/Relocations.cpp

Lines changed: 25 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -717,6 +717,24 @@ class OffsetGetter {
717717
};
718718
} // namespace
719719

720+
static void addRelativeReloc(InputSectionBase *IS, uint64_t OffsetInSec,
721+
Symbol *Sym, int64_t Addend, RelExpr Expr,
722+
RelType Type) {
723+
// Add a relative relocation. If RelrDyn section is enabled, and the
724+
// relocation offset is guaranteed to be even, add the relocation to
725+
// the RelrDyn section, otherwise add it to the RelaDyn section.
726+
// RelrDyn sections don't support odd offsets. Also, RelrDyn sections
727+
// don't store the addend values, so we must write it to the relocated
728+
// address.
729+
if (InX::RelrDyn && IS->Alignment >= 2 && OffsetInSec % 2 == 0) {
730+
IS->Relocations.push_back({Expr, Type, OffsetInSec, Addend, Sym});
731+
InX::RelrDyn->Relocs.push_back({IS, OffsetInSec});
732+
return;
733+
}
734+
InX::RelaDyn->addReloc(Target->RelativeRel, IS, OffsetInSec, Sym, Addend,
735+
Expr, Type);
736+
}
737+
720738
template <class ELFT, class GotPltSection>
721739
static void addPltEntry(PltSection *Plt, GotPltSection *GotPlt,
722740
RelocationBaseSection *Rel, RelType Type, Symbol &Sym) {
@@ -748,14 +766,12 @@ template <class ELFT> static void addGotEntry(Symbol &Sym) {
748766

749767
// Otherwise, we emit a dynamic relocation to .rel[a].dyn so that
750768
// the GOT slot will be fixed at load-time.
751-
RelType Type;
752-
if (Sym.isTls())
753-
Type = Target->TlsGotRel;
754-
else if (!Sym.IsPreemptible && Config->Pic && !isAbsolute(Sym))
755-
Type = Target->RelativeRel;
756-
else
757-
Type = Target->GotRel;
758-
InX::RelaDyn->addReloc(Type, InX::Got, Off, &Sym, 0,
769+
if (!Sym.isTls() && !Sym.IsPreemptible && Config->Pic && !isAbsolute(Sym)) {
770+
addRelativeReloc(InX::Got, Off, &Sym, 0, R_ABS, Target->GotRel);
771+
return;
772+
}
773+
InX::RelaDyn->addReloc(Sym.isTls() ? Target->TlsGotRel : Target->GotRel,
774+
InX::Got, Off, &Sym, 0,
759775
Sym.IsPreemptible ? R_ADDEND : R_ABS, Target->GotRel);
760776
}
761777

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

808824
if (!IsPreemptibleValue) {
809-
InX::RelaDyn->addReloc(Target->RelativeRel, &Sec, Offset, &Sym, Addend,
810-
Expr, Type);
825+
addRelativeReloc(&Sec, Offset, &Sym, Addend, Expr, Type);
811826
return;
812827
} else if (RelType Rel = Target->getDynRel(Type)) {
813828
InX::RelaDyn->addReloc(Rel, &Sec, Offset, &Sym, Addend, R_ADDEND, Type);

‎lld/ELF/SyntheticSections.cpp

Lines changed: 110 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1294,6 +1294,14 @@ template <class ELFT> void DynamicSection<ELFT>::finalizeContents() {
12941294
addInt(IsRela ? DT_RELACOUNT : DT_RELCOUNT, NumRelativeRels);
12951295
}
12961296
}
1297+
if (InX::RelrDyn && !InX::RelrDyn->Relocs.empty()) {
1298+
addInSec(Config->UseAndroidRelrTags ? DT_ANDROID_RELR : DT_RELR,
1299+
InX::RelrDyn);
1300+
addSize(Config->UseAndroidRelrTags ? DT_ANDROID_RELRSZ : DT_RELRSZ,
1301+
InX::RelrDyn->getParent());
1302+
addInt(Config->UseAndroidRelrTags ? DT_ANDROID_RELRENT : DT_RELRENT,
1303+
sizeof(Elf_Relr));
1304+
}
12971305
// .rel[a].plt section usually consists of two parts, containing plt and
12981306
// iplt relocations. It is possible to have only iplt relocations in the
12991307
// output. In that case RelaPlt is empty and have zero offset, the same offset
@@ -1466,6 +1474,11 @@ void RelocationBaseSection::finalizeContents() {
14661474
getParent()->Link = Link;
14671475
}
14681476

1477+
RelrBaseSection::RelrBaseSection()
1478+
: SyntheticSection(SHF_ALLOC,
1479+
Config->UseAndroidRelrTags ? SHT_ANDROID_RELR : SHT_RELR,
1480+
Config->Wordsize, ".relr.dyn") {}
1481+
14691482
template <class ELFT>
14701483
static void encodeDynamicReloc(typename ELFT::Rela *P,
14711484
const DynamicReloc &Rel) {
@@ -1694,6 +1707,97 @@ bool AndroidPackedRelocationSection<ELFT>::updateAllocSize() {
16941707
return RelocData.size() != OldSize;
16951708
}
16961709

1710+
template <class ELFT> RelrSection<ELFT>::RelrSection() {
1711+
this->Entsize = Config->Wordsize;
1712+
}
1713+
1714+
template <class ELFT> bool RelrSection<ELFT>::updateAllocSize() {
1715+
// This function computes the contents of an SHT_RELR packed relocation
1716+
// section.
1717+
//
1718+
// Proposal for adding SHT_RELR sections to generic-abi is here:
1719+
// https://groups.google.com/forum/#!topic/generic-abi/bX460iggiKg
1720+
//
1721+
// The encoded sequence of Elf64_Relr entries in a SHT_RELR section looks
1722+
// like [ AAAAAAAA BBBBBBB1 BBBBBBB1 ... AAAAAAAA BBBBBB1 ... ]
1723+
//
1724+
// i.e. start with an address, followed by any number of bitmaps. The address
1725+
// entry encodes 1 relocation. The subsequent bitmap entries encode up to 63
1726+
// relocations each, at subsequent offsets following the last address entry.
1727+
//
1728+
// The bitmap entries must have 1 in the least significant bit. The assumption
1729+
// here is that an address cannot have 1 in lsb. Odd addresses are not
1730+
// supported.
1731+
//
1732+
// Excluding the least significant bit in the bitmap, each non-zero bit in
1733+
// the bitmap represents a relocation to be applied to a corresponding machine
1734+
// word that follows the base address word. The second least significant bit
1735+
// represents the machine word immediately following the initial address, and
1736+
// each bit that follows represents the next word, in linear order. As such,
1737+
// a single bitmap can encode up to 31 relocations in a 32-bit object, and
1738+
// 63 relocations in a 64-bit object.
1739+
//
1740+
// This encoding has a couple of interesting properties:
1741+
// 1. Looking at any entry, it is clear whether it's an address or a bitmap:
1742+
// even means address, odd means bitmap.
1743+
// 2. Just a simple list of addresses is a valid encoding.
1744+
1745+
size_t OldSize = RelrRelocs.size();
1746+
RelrRelocs.clear();
1747+
1748+
// Number of bits to use for the relocation offsets bitmap.
1749+
// These many relative relocations can be encoded in a single entry.
1750+
const size_t NBits = 8 * Config->Wordsize - 1;
1751+
1752+
// Get offsets for all relative relocations and sort them.
1753+
std::vector<uint64_t> Offsets;
1754+
for (const RelativeReloc &Rel : Relocs) {
1755+
Offsets.push_back(Rel.getOffset());
1756+
}
1757+
std::sort(Offsets.begin(), Offsets.end());
1758+
1759+
uint64_t Base = 0;
1760+
typename std::vector<uint64_t>::iterator Curr = Offsets.begin();
1761+
while (Curr != Offsets.end()) {
1762+
uint64_t Current = *Curr;
1763+
assert(Current % 2 == 0);
1764+
1765+
uint64_t Bits = 0;
1766+
typename std::vector<uint64_t>::iterator Next = Curr;
1767+
if (Base > 0 && Base <= Current) {
1768+
while (Next != Offsets.end()) {
1769+
uint64_t Delta = *Next - Base;
1770+
// If Next is too far out, it cannot be folded into Curr.
1771+
if (Delta >= NBits * Config->Wordsize)
1772+
break;
1773+
// If Next is not a multiple of wordsize away, it cannot
1774+
// be folded into Curr.
1775+
if (Delta % Config->Wordsize != 0)
1776+
break;
1777+
// Next can be folded into Curr, add it to the bitmap.
1778+
Bits |= 1ULL << (Delta / Config->Wordsize);
1779+
++Next;
1780+
}
1781+
}
1782+
1783+
if (Bits == 0) {
1784+
RelrRelocs.push_back(Elf_Relr(Current));
1785+
// This is not a continuation entry, only one offset was
1786+
// consumed. Set base offset for subsequent bitmap entries.
1787+
Base = Current + Config->Wordsize;
1788+
++Curr;
1789+
} else {
1790+
RelrRelocs.push_back(Elf_Relr((Bits << 1) | 1));
1791+
// This is a continuation entry encoding multiple offsets
1792+
// in a bitmap. Advance base offset by NBits words.
1793+
Base += NBits * Config->Wordsize;
1794+
Curr = Next;
1795+
}
1796+
}
1797+
1798+
return RelrRelocs.size() != OldSize;
1799+
}
1800+
16971801
SymbolTableBaseSection::SymbolTableBaseSection(StringTableSection &StrTabSec)
16981802
: SyntheticSection(StrTabSec.isDynamic() ? (uint64_t)SHF_ALLOC : 0,
16991803
StrTabSec.isDynamic() ? SHT_DYNSYM : SHT_SYMTAB,
@@ -2893,6 +2997,7 @@ MipsRldMapSection *InX::MipsRldMap;
28932997
PltSection *InX::Plt;
28942998
PltSection *InX::Iplt;
28952999
RelocationBaseSection *InX::RelaDyn;
3000+
RelrBaseSection *InX::RelrDyn;
28963001
RelocationBaseSection *InX::RelaPlt;
28973002
RelocationBaseSection *InX::RelaIplt;
28983003
StringTableSection *InX::ShStrTab;
@@ -2954,6 +3059,11 @@ template class elf::AndroidPackedRelocationSection<ELF32BE>;
29543059
template class elf::AndroidPackedRelocationSection<ELF64LE>;
29553060
template class elf::AndroidPackedRelocationSection<ELF64BE>;
29563061

3062+
template class elf::RelrSection<ELF32LE>;
3063+
template class elf::RelrSection<ELF32BE>;
3064+
template class elf::RelrSection<ELF64LE>;
3065+
template class elf::RelrSection<ELF64BE>;
3066+
29573067
template class elf::SymbolTableSection<ELF32LE>;
29583068
template class elf::SymbolTableSection<ELF32BE>;
29593069
template class elf::SymbolTableSection<ELF64LE>;

‎lld/ELF/SyntheticSections.h

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -438,6 +438,7 @@ template <class ELFT> class DynamicSection final : public SyntheticSection {
438438
typedef typename ELFT::Dyn Elf_Dyn;
439439
typedef typename ELFT::Rel Elf_Rel;
440440
typedef typename ELFT::Rela Elf_Rela;
441+
typedef typename ELFT::Relr Elf_Relr;
441442
typedef typename ELFT::Shdr Elf_Shdr;
442443
typedef typename ELFT::Sym Elf_Sym;
443444

@@ -517,6 +518,39 @@ class AndroidPackedRelocationSection final : public RelocationBaseSection {
517518
SmallVector<char, 0> RelocData;
518519
};
519520

521+
struct RelativeReloc {
522+
uint64_t getOffset() const { return InputSec->getVA(OffsetInSec); }
523+
524+
const InputSectionBase *InputSec;
525+
uint64_t OffsetInSec;
526+
};
527+
528+
class RelrBaseSection : public SyntheticSection {
529+
public:
530+
RelrBaseSection();
531+
std::vector<RelativeReloc> Relocs;
532+
};
533+
534+
// RelrSection is used to encode offsets for relative relocations.
535+
// Proposal for adding SHT_RELR sections to generic-abi is here:
536+
// https://groups.google.com/forum/#!topic/generic-abi/bX460iggiKg
537+
// For more details, see the comment in RelrSection::updateAllocSize().
538+
template <class ELFT> class RelrSection final : public RelrBaseSection {
539+
typedef typename ELFT::Relr Elf_Relr;
540+
541+
public:
542+
RelrSection();
543+
544+
bool updateAllocSize() override;
545+
size_t getSize() const override { return RelrRelocs.size() * this->Entsize; }
546+
void writeTo(uint8_t *Buf) override {
547+
memcpy(Buf, RelrRelocs.data(), getSize());
548+
}
549+
550+
private:
551+
std::vector<Elf_Relr> RelrRelocs;
552+
};
553+
520554
struct SymbolTableEntry {
521555
Symbol *Sym;
522556
size_t StrTabOffset;
@@ -958,6 +992,7 @@ struct InX {
958992
static PltSection *Plt;
959993
static PltSection *Iplt;
960994
static RelocationBaseSection *RelaDyn;
995+
static RelrBaseSection *RelrDyn;
961996
static RelocationBaseSection *RelaPlt;
962997
static RelocationBaseSection *RelaIplt;
963998
static StringTableSection *ShStrTab;

‎lld/ELF/Writer.cpp

Lines changed: 15 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -349,6 +349,11 @@ template <class ELFT> static void createSyntheticSections() {
349349
Add(InX::RelaDyn);
350350
}
351351

352+
if (Config->RelrPackDynRelocs) {
353+
InX::RelrDyn = make<RelrSection<ELFT>>();
354+
Add(InX::RelrDyn);
355+
}
356+
352357
// Add .got. MIPS' .got is so different from the other archs,
353358
// it has its own class.
354359
if (Config->EMachine == EM_MIPS) {
@@ -1646,12 +1651,12 @@ template <class ELFT> void Writer<ELFT>::finalizeSections() {
16461651
// Dynamic section must be the last one in this list and dynamic
16471652
// symbol table section (DynSymTab) must be the first one.
16481653
applySynthetic(
1649-
{InX::DynSymTab, InX::Bss, InX::BssRelRo, InX::GnuHashTab,
1650-
InX::HashTab, InX::SymTab, InX::ShStrTab, InX::StrTab,
1651-
In<ELFT>::VerDef, InX::DynStrTab, InX::Got, InX::MipsGot,
1652-
InX::IgotPlt, InX::GotPlt, InX::RelaDyn, InX::RelaIplt,
1653-
InX::RelaPlt, InX::Plt, InX::Iplt, InX::EhFrameHdr,
1654-
In<ELFT>::VerSym, In<ELFT>::VerNeed, InX::Dynamic},
1654+
{InX::DynSymTab, InX::Bss, InX::BssRelRo, InX::GnuHashTab,
1655+
InX::HashTab, InX::SymTab, InX::ShStrTab, InX::StrTab,
1656+
In<ELFT>::VerDef, InX::DynStrTab, InX::Got, InX::MipsGot,
1657+
InX::IgotPlt, InX::GotPlt, InX::RelaDyn, InX::RelrDyn,
1658+
InX::RelaIplt, InX::RelaPlt, InX::Plt, InX::Iplt,
1659+
InX::EhFrameHdr, In<ELFT>::VerSym, In<ELFT>::VerNeed, InX::Dynamic},
16551660
[](SyntheticSection *SS) { SS->finalizeContents(); });
16561661

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

0 commit comments

Image for: 0 commit comments
Comments
 (0)