Skip to content

Commit 500cfcf

Browse files
committed
[lld][AArch64][ELF][PAC] Support .relr.auth.dyn section
Support `R_AARCH64_AUTH_RELATIVE` relocation compression as described in https://github.com/ARM-software/abi-aa/blob/main/pauthabielf64/pauthabielf64.rst#relocation-compression
1 parent a1f4ac7 commit 500cfcf

File tree

6 files changed

+233
-47
lines changed

6 files changed

+233
-47
lines changed

lld/ELF/Arch/AArch64.cpp

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -400,6 +400,19 @@ void AArch64::relocate(uint8_t *loc, const Relocation &rel,
400400
case R_AARCH64_PREL64:
401401
write64(loc, val);
402402
break;
403+
case R_AARCH64_AUTH_ABS64:
404+
// If val is wider than 32 bits, the relocation must have been moved from
405+
// .relr.auth.dyn to .rela.dyn, and the addend write is not needed.
406+
//
407+
// If val fits in 32 bits, we have two potential scenarios:
408+
// * True RELR: Write the 32-bit `val`
409+
// * RELA: Even if the value now fits in 32 bits, it might have been
410+
// converted from RELR during an iteration in
411+
// finalizeAddressDependentContent(). Writing the value is harmless
412+
// because dynamic linking ignores it.
413+
if (isInt<32>(val))
414+
write32(loc, val);
415+
break;
403416
case R_AARCH64_ADD_ABS_LO12_NC:
404417
or32AArch64Imm(loc, val);
405418
break;

lld/ELF/Relocations.cpp

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -898,9 +898,9 @@ static void addRelativeReloc(InputSectionBase &isec, uint64_t offsetInSec,
898898
isec.addReloc({expr, type, offsetInSec, addend, &sym});
899899
if (shard)
900900
part.relrDyn->relocsVec[parallel::getThreadIndex()].push_back(
901-
{&isec, offsetInSec});
901+
{&isec, isec.relocs().size() - 1});
902902
else
903-
part.relrDyn->relocs.push_back({&isec, offsetInSec});
903+
part.relrDyn->relocs.push_back({&isec, isec.relocs().size() - 1});
904904
return;
905905
}
906906
part.relaDyn->addRelativeReloc<shard>(target->relativeRel, isec, offsetInSec,
@@ -1154,6 +1154,12 @@ void RelocationScanner::processAux(RelExpr expr, RelType type, uint64_t offset,
11541154
// relative relocation. Use a symbolic relocation instead.
11551155
if (sym.isPreemptible) {
11561156
part.relaDyn->addSymbolReloc(type, *sec, offset, sym, addend, type);
1157+
} else if (part.relrAuthDyn && sec->addralign >= 2 && offset % 2 == 0) {
1158+
// When symbol values are determined in
1159+
// finalizeAddressDependentContent, some .relr.auth.dyn relocations
1160+
// may be moved to .rela.dyn.
1161+
sec->addReloc({expr, type, offset, addend, &sym});
1162+
part.relrAuthDyn->relocs.push_back({sec, sec->relocs().size() - 1});
11571163
} else {
11581164
part.relaDyn->addReloc({R_AARCH64_AUTH_RELATIVE, sec, offset,
11591165
DynamicReloc::AddendOnlyWithTargetVA, sym,

lld/ELF/SyntheticSections.cpp

Lines changed: 15 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1416,6 +1416,12 @@ DynamicSection<ELFT>::computeContents() {
14161416
addInt(config->useAndroidRelrTags ? DT_ANDROID_RELRENT : DT_RELRENT,
14171417
sizeof(Elf_Relr));
14181418
}
1419+
if (part.relrAuthDyn && part.relrAuthDyn->getParent() &&
1420+
!part.relrAuthDyn->relocs.empty()) {
1421+
addInSec(DT_AARCH64_AUTH_RELR, *part.relrAuthDyn);
1422+
addInt(DT_AARCH64_AUTH_RELRSZ, part.relrAuthDyn->getParent()->size);
1423+
addInt(DT_AARCH64_AUTH_RELRENT, sizeof(Elf_Relr));
1424+
}
14191425
if (isMain && in.relaPlt->isNeeded()) {
14201426
addInSec(DT_JMPREL, *in.relaPlt);
14211427
entries.emplace_back(DT_PLTRELSZ, addPltRelSz());
@@ -1727,10 +1733,13 @@ template <class ELFT> void RelocationSection<ELFT>::writeTo(uint8_t *buf) {
17271733
}
17281734
}
17291735

1730-
RelrBaseSection::RelrBaseSection(unsigned concurrency)
1731-
: SyntheticSection(SHF_ALLOC,
1732-
config->useAndroidRelrTags ? SHT_ANDROID_RELR : SHT_RELR,
1733-
config->wordsize, ".relr.dyn"),
1736+
RelrBaseSection::RelrBaseSection(unsigned concurrency, bool isAArch64Auth)
1737+
: SyntheticSection(
1738+
SHF_ALLOC,
1739+
isAArch64Auth
1740+
? SHT_AARCH64_AUTH_RELR
1741+
: (config->useAndroidRelrTags ? SHT_ANDROID_RELR : SHT_RELR),
1742+
config->wordsize, isAArch64Auth ? ".relr.auth.dyn" : ".relr.dyn"),
17341743
relocsVec(concurrency) {}
17351744

17361745
void RelrBaseSection::mergeRels() {
@@ -1998,8 +2007,8 @@ bool AndroidPackedRelocationSection<ELFT>::updateAllocSize() {
19982007
}
19992008

20002009
template <class ELFT>
2001-
RelrSection<ELFT>::RelrSection(unsigned concurrency)
2002-
: RelrBaseSection(concurrency) {
2010+
RelrSection<ELFT>::RelrSection(unsigned concurrency, bool isAArch64Auth)
2011+
: RelrBaseSection(concurrency, isAArch64Auth) {
20032012
this->entsize = config->wordsize;
20042013
}
20052014

lld/ELF/SyntheticSections.h

Lines changed: 10 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -543,7 +543,9 @@ class RelocationBaseSection : public SyntheticSection {
543543
static bool classof(const SectionBase *d) {
544544
return SyntheticSection::classof(d) &&
545545
(d->type == llvm::ELF::SHT_RELA || d->type == llvm::ELF::SHT_REL ||
546-
d->type == llvm::ELF::SHT_RELR);
546+
d->type == llvm::ELF::SHT_RELR ||
547+
(config->emachine == llvm::ELF::EM_AARCH64 &&
548+
d->type == llvm::ELF::SHT_AARCH64_AUTH_RELR));
547549
}
548550
int32_t dynamicTag, sizeDynamicTag;
549551
SmallVector<DynamicReloc, 0> relocs;
@@ -591,15 +593,17 @@ class AndroidPackedRelocationSection final : public RelocationBaseSection {
591593
};
592594

593595
struct RelativeReloc {
594-
uint64_t getOffset() const { return inputSec->getVA(offsetInSec); }
596+
uint64_t getOffset() const {
597+
return inputSec->getVA(inputSec->relocs()[relocIdx].offset);
598+
}
595599

596600
const InputSectionBase *inputSec;
597-
uint64_t offsetInSec;
601+
size_t relocIdx;
598602
};
599603

600604
class RelrBaseSection : public SyntheticSection {
601605
public:
602-
RelrBaseSection(unsigned concurrency);
606+
RelrBaseSection(unsigned concurrency, bool isAArch64Auth = false);
603607
void mergeRels();
604608
bool isNeeded() const override {
605609
return !relocs.empty() ||
@@ -617,7 +621,7 @@ template <class ELFT> class RelrSection final : public RelrBaseSection {
617621
using Elf_Relr = typename ELFT::Relr;
618622

619623
public:
620-
RelrSection(unsigned concurrency);
624+
RelrSection(unsigned concurrency, bool isAArch64Auth = false);
621625

622626
bool updateAllocSize() override;
623627
size_t getSize() const override { return relrRelocs.size() * this->entsize; }
@@ -1319,6 +1323,7 @@ struct Partition {
13191323
std::unique_ptr<PackageMetadataNote> packageMetadataNote;
13201324
std::unique_ptr<RelocationBaseSection> relaDyn;
13211325
std::unique_ptr<RelrBaseSection> relrDyn;
1326+
std::unique_ptr<RelrBaseSection> relrAuthDyn;
13221327
std::unique_ptr<VersionDefinitionSection> verDef;
13231328
std::unique_ptr<SyntheticSection> verNeed;
13241329
std::unique_ptr<VersionTableSection> verSym;

lld/ELF/Writer.cpp

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -456,6 +456,9 @@ template <class ELFT> void elf::createSyntheticSections() {
456456
if (config->relrPackDynRelocs) {
457457
part.relrDyn = std::make_unique<RelrSection<ELFT>>(threadCount);
458458
add(*part.relrDyn);
459+
part.relrAuthDyn = std::make_unique<RelrSection<ELFT>>(
460+
threadCount, /*isAArch64Auth=*/true);
461+
add(*part.relrAuthDyn);
459462
}
460463

461464
if (!config->relocatable) {
@@ -1730,9 +1733,33 @@ template <class ELFT> void Writer<ELFT>::finalizeAddressDependentContent() {
17301733
in.mipsGot->updateAllocSize();
17311734

17321735
for (Partition &part : partitions) {
1736+
// The R_AARCH64_AUTH_RELATIVE has a smaller addend field as bits [63:32]
1737+
// encode the signing schema. We've put relocations in .relr.auth.dyn
1738+
// during RelocationScanner::processAux, but the target VA for some of
1739+
// them might be wider than 32 bits. We can only know the final VA at this
1740+
// point, so move relocations with large values from .relr.auth.dyn to
1741+
// .rela.dyn.
1742+
if (part.relrAuthDyn) {
1743+
auto it = llvm::remove_if(
1744+
part.relrAuthDyn->relocs, [&part](const RelativeReloc &elem) {
1745+
const Relocation &reloc = elem.inputSec->relocs()[elem.relocIdx];
1746+
if (isInt<32>(reloc.sym->getVA(reloc.addend)))
1747+
return false;
1748+
part.relaDyn->addReloc({R_AARCH64_AUTH_RELATIVE, elem.inputSec,
1749+
reloc.offset,
1750+
DynamicReloc::AddendOnlyWithTargetVA,
1751+
*reloc.sym, reloc.addend, R_ABS});
1752+
// See also AArch64::relocate
1753+
return true;
1754+
});
1755+
changed |= (it != part.relrAuthDyn->relocs.end());
1756+
part.relrAuthDyn->relocs.erase(it, part.relrAuthDyn->relocs.end());
1757+
}
17331758
changed |= part.relaDyn->updateAllocSize();
17341759
if (part.relrDyn)
17351760
changed |= part.relrDyn->updateAllocSize();
1761+
if (part.relrAuthDyn)
1762+
changed |= part.relrAuthDyn->updateAllocSize();
17361763
if (part.memtagGlobalDescriptors)
17371764
changed |= part.memtagGlobalDescriptors->updateAllocSize();
17381765
}
@@ -1883,6 +1910,14 @@ static void removeUnusedSyntheticSections() {
18831910
auto *sec = cast<SyntheticSection>(s);
18841911
if (sec->getParent() && sec->isNeeded())
18851912
return false;
1913+
// .relr.auth.dyn relocations may be moved to .rela.dyn in
1914+
// finalizeAddressDependentContent, making .rela.dyn no longer empty.
1915+
// Conservatively keep .rela.dyn. .relr.auth.dyn can be made empty, but
1916+
// we would fail to remove it here.
1917+
if (config->emachine == EM_AARCH64 && config->relrPackDynRelocs)
1918+
if (auto *relSec = dyn_cast<RelocationBaseSection>(sec))
1919+
if (relSec == mainPart->relaDyn.get())
1920+
return false;
18861921
unused.insert(sec);
18871922
return true;
18881923
});
@@ -2195,6 +2230,10 @@ template <class ELFT> void Writer<ELFT>::finalizeSections() {
21952230
part.relrDyn->mergeRels();
21962231
finalizeSynthetic(part.relrDyn.get());
21972232
}
2233+
if (part.relrAuthDyn) {
2234+
part.relrAuthDyn->mergeRels();
2235+
finalizeSynthetic(part.relrAuthDyn.get());
2236+
}
21982237

21992238
finalizeSynthetic(part.dynSymTab.get());
22002239
finalizeSynthetic(part.gnuHashTab.get());

0 commit comments

Comments
 (0)