Skip to content

Commit a9c43b9

Browse files
authored
[lld][AArch64][ELF][PAC] Support .relr.auth.dyn section (#96496)
This re-applies #87635 after the issue described in #87635 (comment) is fixed in ebc123e. A corresponding test is also added. Original PR description below. 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 deb039e commit a9c43b9

File tree

6 files changed

+220
-48
lines changed

6 files changed

+220
-48
lines changed

lld/ELF/Arch/AArch64.cpp

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -429,6 +429,19 @@ void AArch64::relocate(uint8_t *loc, const Relocation &rel,
429429
case R_AARCH64_PREL64:
430430
write64(loc, val);
431431
break;
432+
case R_AARCH64_AUTH_ABS64:
433+
// If val is wider than 32 bits, the relocation must have been moved from
434+
// .relr.auth.dyn to .rela.dyn, and the addend write is not needed.
435+
//
436+
// If val fits in 32 bits, we have two potential scenarios:
437+
// * True RELR: Write the 32-bit `val`.
438+
// * RELA: Even if the value now fits in 32 bits, it might have been
439+
// converted from RELR during an iteration in
440+
// finalizeAddressDependentContent(). Writing the value is harmless
441+
// because dynamic linking ignores it.
442+
if (isInt<32>(val))
443+
write32(loc, val);
444+
break;
432445
case R_AARCH64_ADD_ABS_LO12_NC:
433446
or32AArch64Imm(loc, val);
434447
break;

lld/ELF/Relocations.cpp

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

lld/ELF/SyntheticSections.cpp

Lines changed: 18 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1420,6 +1420,12 @@ DynamicSection<ELFT>::computeContents() {
14201420
addInt(config->useAndroidRelrTags ? DT_ANDROID_RELRENT : DT_RELRENT,
14211421
sizeof(Elf_Relr));
14221422
}
1423+
if (part.relrAuthDyn && part.relrAuthDyn->getParent() &&
1424+
!part.relrAuthDyn->relocs.empty()) {
1425+
addInSec(DT_AARCH64_AUTH_RELR, *part.relrAuthDyn);
1426+
addInt(DT_AARCH64_AUTH_RELRSZ, part.relrAuthDyn->getParent()->size);
1427+
addInt(DT_AARCH64_AUTH_RELRENT, sizeof(Elf_Relr));
1428+
}
14231429
if (isMain && in.relaPlt->isNeeded()) {
14241430
addInSec(DT_JMPREL, *in.relaPlt);
14251431
entries.emplace_back(DT_PLTRELSZ, addPltRelSz());
@@ -1731,10 +1737,13 @@ template <class ELFT> void RelocationSection<ELFT>::writeTo(uint8_t *buf) {
17311737
}
17321738
}
17331739

1734-
RelrBaseSection::RelrBaseSection(unsigned concurrency)
1735-
: SyntheticSection(SHF_ALLOC,
1736-
config->useAndroidRelrTags ? SHT_ANDROID_RELR : SHT_RELR,
1737-
config->wordsize, ".relr.dyn"),
1740+
RelrBaseSection::RelrBaseSection(unsigned concurrency, bool isAArch64Auth)
1741+
: SyntheticSection(
1742+
SHF_ALLOC,
1743+
isAArch64Auth
1744+
? SHT_AARCH64_AUTH_RELR
1745+
: (config->useAndroidRelrTags ? SHT_ANDROID_RELR : SHT_RELR),
1746+
config->wordsize, isAArch64Auth ? ".relr.auth.dyn" : ".relr.dyn"),
17381747
relocsVec(concurrency) {}
17391748

17401749
void RelrBaseSection::mergeRels() {
@@ -2002,8 +2011,8 @@ bool AndroidPackedRelocationSection<ELFT>::updateAllocSize() {
20022011
}
20032012

20042013
template <class ELFT>
2005-
RelrSection<ELFT>::RelrSection(unsigned concurrency)
2006-
: RelrBaseSection(concurrency) {
2014+
RelrSection<ELFT>::RelrSection(unsigned concurrency, bool isAArch64Auth)
2015+
: RelrBaseSection(concurrency, isAArch64Auth) {
20072016
this->entsize = config->wordsize;
20082017
}
20092018

@@ -4779,6 +4788,9 @@ template <class ELFT> void elf::createSyntheticSections() {
47794788
if (config->relrPackDynRelocs) {
47804789
part.relrDyn = std::make_unique<RelrSection<ELFT>>(threadCount);
47814790
add(*part.relrDyn);
4791+
part.relrAuthDyn = std::make_unique<RelrSection<ELFT>>(
4792+
threadCount, /*isAArch64Auth=*/true);
4793+
add(*part.relrAuthDyn);
47824794
}
47834795

47844796
if (config->ehFrameHdr) {

lld/ELF/SyntheticSections.h

Lines changed: 10 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -548,7 +548,9 @@ class RelocationBaseSection : public SyntheticSection {
548548
static bool classof(const SectionBase *d) {
549549
return SyntheticSection::classof(d) &&
550550
(d->type == llvm::ELF::SHT_RELA || d->type == llvm::ELF::SHT_REL ||
551-
d->type == llvm::ELF::SHT_RELR);
551+
d->type == llvm::ELF::SHT_RELR ||
552+
(d->type == llvm::ELF::SHT_AARCH64_AUTH_RELR &&
553+
config->emachine == llvm::ELF::EM_AARCH64));
552554
}
553555
int32_t dynamicTag, sizeDynamicTag;
554556
SmallVector<DynamicReloc, 0> relocs;
@@ -596,15 +598,17 @@ class AndroidPackedRelocationSection final : public RelocationBaseSection {
596598
};
597599

598600
struct RelativeReloc {
599-
uint64_t getOffset() const { return inputSec->getVA(offsetInSec); }
601+
uint64_t getOffset() const {
602+
return inputSec->getVA(inputSec->relocs()[relocIdx].offset);
603+
}
600604

601605
const InputSectionBase *inputSec;
602-
uint64_t offsetInSec;
606+
size_t relocIdx;
603607
};
604608

605609
class RelrBaseSection : public SyntheticSection {
606610
public:
607-
RelrBaseSection(unsigned concurrency);
611+
RelrBaseSection(unsigned concurrency, bool isAArch64Auth = false);
608612
void mergeRels();
609613
bool isNeeded() const override {
610614
return !relocs.empty() ||
@@ -622,7 +626,7 @@ template <class ELFT> class RelrSection final : public RelrBaseSection {
622626
using Elf_Relr = typename ELFT::Relr;
623627

624628
public:
625-
RelrSection(unsigned concurrency);
629+
RelrSection(unsigned concurrency, bool isAArch64Auth = false);
626630

627631
bool updateAllocSize() override;
628632
size_t getSize() const override { return relrRelocs.size() * this->entsize; }
@@ -1460,6 +1464,7 @@ struct Partition {
14601464
std::unique_ptr<PackageMetadataNote> packageMetadataNote;
14611465
std::unique_ptr<RelocationBaseSection> relaDyn;
14621466
std::unique_ptr<RelrBaseSection> relrDyn;
1467+
std::unique_ptr<RelrBaseSection> relrAuthDyn;
14631468
std::unique_ptr<VersionDefinitionSection> verDef;
14641469
std::unique_ptr<SyntheticSection> verNeed;
14651470
std::unique_ptr<VersionTableSection> verSym;

lld/ELF/Writer.cpp

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1458,10 +1458,33 @@ template <class ELFT> void Writer<ELFT>::finalizeAddressDependentContent() {
14581458
in.mipsGot->updateAllocSize();
14591459

14601460
for (Partition &part : partitions) {
1461+
// The R_AARCH64_AUTH_RELATIVE has a smaller addend field as bits [63:32]
1462+
// encode the signing schema. We've put relocations in .relr.auth.dyn
1463+
// during RelocationScanner::processAux, but the target VA for some of
1464+
// them might be wider than 32 bits. We can only know the final VA at this
1465+
// point, so move relocations with large values from .relr.auth.dyn to
1466+
// .rela.dyn. See also AArch64::relocate.
1467+
if (part.relrAuthDyn) {
1468+
auto it = llvm::remove_if(
1469+
part.relrAuthDyn->relocs, [&part](const RelativeReloc &elem) {
1470+
const Relocation &reloc = elem.inputSec->relocs()[elem.relocIdx];
1471+
if (isInt<32>(reloc.sym->getVA(reloc.addend)))
1472+
return false;
1473+
part.relaDyn->addReloc({R_AARCH64_AUTH_RELATIVE, elem.inputSec,
1474+
reloc.offset,
1475+
DynamicReloc::AddendOnlyWithTargetVA,
1476+
*reloc.sym, reloc.addend, R_ABS});
1477+
return true;
1478+
});
1479+
changed |= (it != part.relrAuthDyn->relocs.end());
1480+
part.relrAuthDyn->relocs.erase(it, part.relrAuthDyn->relocs.end());
1481+
}
14611482
if (part.relaDyn)
14621483
changed |= part.relaDyn->updateAllocSize();
14631484
if (part.relrDyn)
14641485
changed |= part.relrDyn->updateAllocSize();
1486+
if (part.relrAuthDyn)
1487+
changed |= part.relrAuthDyn->updateAllocSize();
14651488
if (part.memtagGlobalDescriptors)
14661489
changed |= part.memtagGlobalDescriptors->updateAllocSize();
14671490
}
@@ -1625,6 +1648,14 @@ static void removeUnusedSyntheticSections() {
16251648
auto *sec = cast<SyntheticSection>(s);
16261649
if (sec->getParent() && sec->isNeeded())
16271650
return false;
1651+
// .relr.auth.dyn relocations may be moved to .rela.dyn in
1652+
// finalizeAddressDependentContent, making .rela.dyn no longer empty.
1653+
// Conservatively keep .rela.dyn. .relr.auth.dyn can be made empty, but
1654+
// we would fail to remove it here.
1655+
if (config->emachine == EM_AARCH64 && config->relrPackDynRelocs)
1656+
if (auto *relSec = dyn_cast<RelocationBaseSection>(sec))
1657+
if (relSec == mainPart->relaDyn.get())
1658+
return false;
16281659
unused.insert(sec);
16291660
return true;
16301661
});
@@ -1937,6 +1968,10 @@ template <class ELFT> void Writer<ELFT>::finalizeSections() {
19371968
part.relrDyn->mergeRels();
19381969
finalizeSynthetic(part.relrDyn.get());
19391970
}
1971+
if (part.relrAuthDyn) {
1972+
part.relrAuthDyn->mergeRels();
1973+
finalizeSynthetic(part.relrAuthDyn.get());
1974+
}
19401975

19411976
finalizeSynthetic(part.dynSymTab.get());
19421977
finalizeSynthetic(part.gnuHashTab.get());

0 commit comments

Comments
 (0)