Index: ELF/Config.h =================================================================== --- ELF/Config.h +++ ELF/Config.h @@ -114,6 +114,8 @@ CallGraphProfile; bool AllowMultipleDefinition; bool AndroidPackDynRelocs = false; + bool RelrPackDynRelocs = false; + bool AndroidRelrPackDynRelocs = false; bool ARMHasBlx = false; bool ARMHasMovtMovw = false; bool ARMJ1J2BranchEncoding = false; Index: ELF/Driver.cpp =================================================================== --- ELF/Driver.cpp +++ ELF/Driver.cpp @@ -854,6 +854,12 @@ StringRef S = Arg->getValue(); if (S == "android") Config->AndroidPackDynRelocs = true; + else if (S == "relr") + Config->RelrPackDynRelocs = true; + else if (S == "android-relr") { + Config->RelrPackDynRelocs = true; + Config->AndroidRelrPackDynRelocs = true; + } else if (S != "none") error("unknown -pack-dyn-relocs format: " + S); } @@ -942,9 +948,11 @@ // if --apply-dynamic-relocs is used. // We default to not writing the addends when using RELA relocations since // any standard conforming tool can find it in r_addend. + // When using RELR relocations, we need to write the addends since RELR + // relocations decode to offsets only. Config->WriteAddends = Args.hasFlag(OPT_apply_dynamic_relocs, OPT_no_apply_dynamic_relocs, false) || - !Config->IsRela; + !Config->IsRela || Config->RelrPackDynRelocs; } // Returns a value of "-format" option. Index: ELF/LinkerScript.cpp =================================================================== --- ELF/LinkerScript.cpp +++ ELF/LinkerScript.cpp @@ -412,7 +412,8 @@ void LinkerScript::discard(ArrayRef 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 Index: ELF/Options.td =================================================================== --- ELF/Options.td +++ ELF/Options.td @@ -233,7 +233,7 @@ 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 pie: B<"pie", "Create a position independent executable", Index: ELF/SyntheticSections.h =================================================================== --- ELF/SyntheticSections.h +++ ELF/SyntheticSections.h @@ -438,6 +438,7 @@ 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; @@ -473,7 +474,7 @@ void addReloc(RelType DynType, InputSectionBase *InputSec, uint64_t OffsetInSec, Symbol *Sym, int64_t Addend, RelExpr Expr, RelType Type); - void addReloc(const DynamicReloc &Reloc); + virtual void addReloc(const DynamicReloc &Reloc); bool empty() const override { return Relocs.empty(); } size_t getSize() const override { return Relocs.size() * this->Entsize; } size_t getRelativeRelocCount() const { return NumRelativeRelocs; } @@ -517,6 +518,28 @@ SmallVector RelocData; }; +template +class RelrPackedRelocationSection final : public RelocationBaseSection { + typedef typename ELFT::Relr Elf_Relr; + +public: + RelrPackedRelocationSection(StringRef Name); + + void addReloc(const DynamicReloc &Reloc) override { + Relocs.push_back(Reloc); + } + 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 RelrRelocs; +}; + struct SymbolTableEntry { Symbol *Sym; size_t StrTabOffset; @@ -958,6 +981,7 @@ static PltSection *Plt; static PltSection *Iplt; static RelocationBaseSection *RelaDyn; + static RelocationBaseSection *RelrDyn; static RelocationBaseSection *RelaPlt; static RelocationBaseSection *RelaIplt; static StringTableSection *ShStrTab; Index: ELF/SyntheticSections.cpp =================================================================== --- ELF/SyntheticSections.cpp +++ ELF/SyntheticSections.cpp @@ -1288,6 +1288,12 @@ addInt(IsRela ? DT_RELACOUNT : DT_RELCOUNT, NumRelativeRels); } } + if (InX::RelrDyn && !InX::RelrDyn->empty()) { + addInSec(InX::RelrDyn->DynamicTag, InX::RelrDyn); + addSize(InX::RelrDyn->SizeDynamicTag, InX::RelrDyn->getParent()); + addInt(Config->AndroidRelrPackDynRelocs ? 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 @@ -1445,9 +1451,13 @@ } void RelocationBaseSection::addReloc(const DynamicReloc &Reloc) { - if (Reloc.Type == Target->RelativeRel) - ++NumRelativeRelocs; - Relocs.push_back(Reloc); + if (InX::RelrDyn && Reloc.Type == Target->RelativeRel) + InX::RelrDyn->addReloc(Reloc); + else { + if (Reloc.Type == Target->RelativeRel) + ++NumRelativeRelocs; + Relocs.push_back(Reloc); + } } void RelocationBaseSection::finalizeContents() { @@ -1688,6 +1698,89 @@ return RelocData.size() != OldSize; } +template +RelrPackedRelocationSection::RelrPackedRelocationSection(StringRef Name) + : RelocationBaseSection( + Name, Config->AndroidRelrPackDynRelocs ? SHT_ANDROID_RELR : SHT_RELR, + Config->AndroidRelrPackDynRelocs ? DT_ANDROID_RELR : DT_RELR, + Config->AndroidRelrPackDynRelocs ? DT_ANDROID_RELRSZ : DT_RELRSZ) { + this->Entsize = sizeof(Elf_Relr); +} + +template +bool RelrPackedRelocationSection::updateAllocSize() { + size_t OldSize = RelrRelocs.size(); + RelrRelocs.clear(); + + // Word type: uint32_t for Elf32, and uint64_t for Elf64. + typedef typename ELFT::uint Word; + + // Word size in number of bytes. + const size_t WordSize = sizeof(Word); + + // 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*WordSize - 1; + + // Get offsets for all relative relocations and sort them. + std::vector Offsets; + for (const DynamicReloc &Rel : Relocs) { + Offsets.push_back(Rel.getOffset()); + } + std::sort(Offsets.begin(), Offsets.end()); + + // Encode relocations in SHT_RELR section. + // Details of the encoding are described in this post: + // https://groups.google.com/d/msg/generic-abi/bX460iggiKg/Pi9aSwwABgAJ + Word Base = 0; + typename std::vector::iterator Curr = Offsets.begin(); + while (Curr != Offsets.end()) { + Word Current = *Curr; + if (Current%2 != 0) { + error("odd offset for RELR relocation (" + Twine(Current) + "), " + + "pass --pack-dyn-relocs=none to disable RELR relocations"); + ++Curr; + continue; + } + + Word Bits = 0; + typename std::vector::iterator Next = Curr; + if ((Base > 0) && (Base <= Current)) { + while (Next != Offsets.end()) { + Word Delta = *Next - Base; + // If Next is too far out, it cannot be folded into Curr. + if (Delta >= (NBits * WordSize)) + break; + // If Next is not a multiple of WordSize away, it cannot + // be folded into Curr. + if ((Delta % WordSize) != 0) + break; + // Next can be folded into Curr, add it to the bitmap. + Bits |= 1ULL << (Delta / WordSize); + ++Next; + } + } + + Elf_Relr R; + if (Bits == 0) { + R.r_data = Current; + // This is not a continuation entry, only one offset was + // consumed. Set base offset for subsequent bitmap entries. + Base = Current + WordSize; + ++Curr; + } else { + R.r_data = (Bits<<1) | 1; + // This is a continuation entry encoding multiple offsets + // in a bitmap. Advance base offset by NBits words. + Base += NBits * WordSize; + Curr = Next; + } + RelrRelocs.push_back(R); + } + + return RelrRelocs.size() != OldSize; +} + SymbolTableBaseSection::SymbolTableBaseSection(StringTableSection &StrTabSec) : SyntheticSection(StrTabSec.isDynamic() ? (uint64_t)SHF_ALLOC : 0, StrTabSec.isDynamic() ? SHT_DYNSYM : SHT_SYMTAB, @@ -2885,6 +2978,7 @@ PltSection *InX::Plt; PltSection *InX::Iplt; RelocationBaseSection *InX::RelaDyn; +RelocationBaseSection *InX::RelrDyn; RelocationBaseSection *InX::RelaPlt; RelocationBaseSection *InX::RelaIplt; StringTableSection *InX::ShStrTab; @@ -2946,6 +3040,11 @@ template class elf::AndroidPackedRelocationSection; template class elf::AndroidPackedRelocationSection; +template class elf::RelrPackedRelocationSection; +template class elf::RelrPackedRelocationSection; +template class elf::RelrPackedRelocationSection; +template class elf::RelrPackedRelocationSection; + template class elf::SymbolTableSection; template class elf::SymbolTableSection; template class elf::SymbolTableSection; Index: ELF/Writer.cpp =================================================================== --- ELF/Writer.cpp +++ ELF/Writer.cpp @@ -351,6 +351,11 @@ Add(InX::RelaDyn); } + if (Config->RelrPackDynRelocs) { + InX::RelrDyn = make>(".relr.dyn"); + Add(InX::RelrDyn); + } + // Add .got. MIPS' .got is so different from the other archs, // it has its own class. if (Config->EMachine == EM_MIPS) { @@ -1658,12 +1663,12 @@ // 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::VerDef, InX::DynStrTab, InX::Got, InX::MipsGot, - InX::IgotPlt, InX::GotPlt, InX::RelaDyn, InX::RelaIplt, - InX::RelaPlt, InX::Plt, InX::Iplt, InX::EhFrameHdr, - In::VerSym, In::VerNeed, InX::Dynamic}, + {InX::DynSymTab, InX::Bss, InX::BssRelRo, InX::GnuHashTab, + InX::HashTab, InX::SymTab, InX::ShStrTab, InX::StrTab, + In::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::VerSym, In::VerNeed, InX::Dynamic}, [](SyntheticSection *SS) { SS->finalizeContents(); }); if (!Script->HasSectionsCommand && !Config->Relocatable) @@ -1678,7 +1683,8 @@ // 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; @@ -1695,6 +1701,8 @@ if (InX::MipsGot) InX::MipsGot->updateAllocSize(); Changed |= InX::RelaDyn->updateAllocSize(); + if (InX::RelrDyn) + Changed |= InX::RelrDyn->updateAllocSize(); } while (Changed); }