Skip to content

Commit 0f60cdf

Browse files
committed
[𝘀𝗽𝗿] initial version
Created using spr 1.3.5
2 parents 3fc7419 + 0eb9c6c commit 0f60cdf

File tree

7 files changed

+82
-89
lines changed

7 files changed

+82
-89
lines changed

lld/ELF/Arch/AArch64.cpp

Lines changed: 8 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -527,35 +527,17 @@ void AArch64::relocate(uint8_t *loc, const Relocation &rel,
527527
write32(ctx, loc, val);
528528
break;
529529
case R_AARCH64_ABS64:
530-
// AArch64 relocations to tagged symbols have extended semantics, as
531-
// described here:
532-
// https://github.com/ARM-software/abi-aa/blob/main/memtagabielf64/memtagabielf64.rst#841extended-semantics-of-r_aarch64_relative.
533-
// tl;dr: encode the symbol's special addend in the place, which is an
534-
// offset to the point where the logical tag is derived from. Quick hack, if
535-
// the addend is within the symbol's bounds, no need to encode the tag
536-
// derivation offset.
537-
if (rel.sym && rel.sym->isTagged() &&
538-
(rel.addend < 0 ||
539-
rel.addend >= static_cast<int64_t>(rel.sym->getSize())))
540-
write64(ctx, loc, -rel.addend);
541-
else
542-
write64(ctx, loc, val);
530+
write64(ctx, loc, val);
543531
break;
544532
case R_AARCH64_PREL64:
545533
write64(ctx, loc, val);
546534
break;
547535
case R_AARCH64_AUTH_ABS64:
548-
// If val is wider than 32 bits, the relocation must have been moved from
549-
// .relr.auth.dyn to .rela.dyn, and the addend write is not needed.
550-
//
551-
// If val fits in 32 bits, we have two potential scenarios:
552-
// * True RELR: Write the 32-bit `val`.
553-
// * RELA: Even if the value now fits in 32 bits, it might have been
554-
// converted from RELR during an iteration in
555-
// finalizeAddressDependentContent(). Writing the value is harmless
556-
// because dynamic linking ignores it.
557-
if (isInt<32>(val))
558-
write32(ctx, loc, val);
536+
// This is used for the addend of a .relr.auth.dyn entry,
537+
// which is a 32-bit value; the upper 32 bits are used to
538+
// encode the schema.
539+
checkInt(ctx, loc, val, 32, rel);
540+
write32(ctx, loc, val);
559541
break;
560542
case R_AARCH64_ADD_ABS_LO12_NC:
561543
case R_AARCH64_AUTH_GOT_ADD_LO12_NC:
@@ -947,6 +929,8 @@ void AArch64::relocateAlloc(InputSection &sec, uint8_t *buf) const {
947929
AArch64Relaxer relaxer(ctx, sec.relocs());
948930
for (size_t i = 0, size = sec.relocs().size(); i != size; ++i) {
949931
const Relocation &rel = sec.relocs()[i];
932+
if (rel.expr == R_NONE) // See finalizeAddressDependentContent()
933+
continue;
950934
uint8_t *loc = buf + rel.offset;
951935
const uint64_t val = sec.getRelocTargetVA(ctx, rel, secAddr + rel.offset);
952936

lld/ELF/InputSection.cpp

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -784,6 +784,8 @@ uint64_t InputSectionBase::getRelocTargetVA(Ctx &ctx, const Relocation &r,
784784
return r.sym->getVA(ctx, a);
785785
case R_ADDEND:
786786
return a;
787+
case R_ADDEND_NEG:
788+
return -static_cast<uint64_t>(a);
787789
case R_RELAX_HINT:
788790
return 0;
789791
case RE_ARM_SBREL:

lld/ELF/Relocations.cpp

Lines changed: 32 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -704,40 +704,44 @@ static void addRelativeReloc(Ctx &ctx, InputSectionBase &isec,
704704
uint64_t offsetInSec, Symbol &sym, int64_t addend,
705705
RelExpr expr, RelType type) {
706706
Partition &part = isec.getPartition(ctx);
707-
708-
if (sym.isTagged()) {
709-
part.relaDyn->addRelativeReloc<shard>(ctx.target->relativeRel, isec,
710-
offsetInSec, sym, addend, type, expr);
711-
// With MTE globals, we always want to derive the address tag by `ldg`-ing
712-
// the symbol. When we have a RELATIVE relocation though, we no longer have
713-
// a reference to the symbol. Because of this, when we have an addend that
714-
// puts the result of the RELATIVE relocation out-of-bounds of the symbol
715-
// (e.g. the addend is outside of [0, sym.getSize()]), the AArch64 MemtagABI
716-
// says we should store the offset to the start of the symbol in the target
717-
// field. This is described in further detail in:
718-
// https://github.com/ARM-software/abi-aa/blob/main/memtagabielf64/memtagabielf64.rst#841extended-semantics-of-r_aarch64_relative
719-
if (addend < 0 || static_cast<uint64_t>(addend) >= sym.getSize())
720-
isec.relocations.push_back({expr, type, offsetInSec, addend, &sym});
721-
return;
722-
}
707+
bool isAArch64Auth =
708+
ctx.arg.emachine == EM_AARCH64 && type == R_AARCH64_AUTH_ABS64;
723709

724710
// Add a relative relocation. If relrDyn section is enabled, and the
725711
// relocation offset is guaranteed to be even, add the relocation to
726712
// the relrDyn section, otherwise add it to the relaDyn section.
727713
// relrDyn sections don't support odd offsets. Also, relrDyn sections
728714
// don't store the addend values, so we must write it to the relocated
729715
// address.
730-
if (part.relrDyn && isec.addralign >= 2 && offsetInSec % 2 == 0) {
731-
isec.addReloc({expr, type, offsetInSec, addend, &sym});
732-
if (shard)
733-
part.relrDyn->relocsVec[parallel::getThreadIndex()].push_back(
734-
{&isec, isec.relocs().size() - 1});
735-
else
736-
part.relrDyn->relocs.push_back({&isec, isec.relocs().size() - 1});
716+
//
717+
// When symbol values are determined in finalizeAddressDependentContent,
718+
// some .relr.auth.dyn relocations may be moved to .rela.dyn.
719+
RelrBaseSection *relrDyn = part.relrDyn.get();
720+
if (isAArch64Auth)
721+
relrDyn = part.relrAuthDyn.get();
722+
else if (sym.isTagged())
723+
relrDyn = nullptr;
724+
if (relrDyn && isec.addralign >= 2 && offsetInSec % 2 == 0) {
725+
relrDyn->addRelativeReloc<shard>(isec, offsetInSec, sym, addend, type,
726+
expr);
737727
return;
738728
}
739-
part.relaDyn->addRelativeReloc<shard>(ctx.target->relativeRel, isec,
740-
offsetInSec, sym, addend, type, expr);
729+
RelType relativeType = ctx.target->relativeRel;
730+
if (isAArch64Auth)
731+
relativeType = R_AARCH64_AUTH_RELATIVE;
732+
part.relaDyn->addRelativeReloc<shard>(relativeType, isec, offsetInSec, sym,
733+
addend, type, expr);
734+
// With MTE globals, we always want to derive the address tag by `ldg`-ing
735+
// the symbol. When we have a RELATIVE relocation though, we no longer have
736+
// a reference to the symbol. Because of this, when we have an addend that
737+
// puts the result of the RELATIVE relocation out-of-bounds of the symbol
738+
// (e.g. the addend is outside of [0, sym.getSize()]), the AArch64 MemtagABI
739+
// says we should store the offset to the start of the symbol in the target
740+
// field. This is described in further detail in:
741+
// https://github.com/ARM-software/abi-aa/blob/main/memtagabielf64/memtagabielf64.rst#841extended-semantics-of-r_aarch64_relative
742+
if (sym.isTagged() && !isAArch64Auth &&
743+
(addend < 0 || static_cast<uint64_t>(addend) >= sym.getSize()))
744+
isec.addReloc({R_ADDEND_NEG, type, offsetInSec, addend, &sym});
741745
}
742746

743747
template <class PltSection, class GotPltSection>
@@ -996,7 +1000,9 @@ void RelocScan::process(RelExpr expr, RelType type, uint64_t offset,
9961000
if (canWrite) {
9971001
RelType rel = ctx.target->getDynRel(type);
9981002
if (oneof<R_GOT, RE_LOONGARCH_GOT>(expr) ||
999-
(rel == ctx.target->symbolicRel && !sym.isPreemptible)) {
1003+
((rel == ctx.target->symbolicRel ||
1004+
(ctx.arg.emachine == EM_AARCH64 && type == R_AARCH64_AUTH_ABS64)) &&
1005+
!sym.isPreemptible)) {
10001006
addRelativeReloc<true>(ctx, *sec, offset, sym, addend, expr, type);
10011007
return;
10021008
}
@@ -1005,24 +1011,6 @@ void RelocScan::process(RelExpr expr, RelType type, uint64_t offset,
10051011
rel = ctx.target->relativeRel;
10061012
std::lock_guard<std::mutex> lock(ctx.relocMutex);
10071013
Partition &part = sec->getPartition(ctx);
1008-
if (ctx.arg.emachine == EM_AARCH64 && type == R_AARCH64_AUTH_ABS64) {
1009-
// For a preemptible symbol, we can't use a relative relocation. For an
1010-
// undefined symbol, we can't compute offset at link-time and use a
1011-
// relative relocation. Use a symbolic relocation instead.
1012-
if (sym.isPreemptible) {
1013-
part.relaDyn->addSymbolReloc(type, *sec, offset, sym, addend, type);
1014-
} else if (part.relrAuthDyn && sec->addralign >= 2 && offset % 2 == 0) {
1015-
// When symbol values are determined in
1016-
// finalizeAddressDependentContent, some .relr.auth.dyn relocations
1017-
// may be moved to .rela.dyn.
1018-
sec->addReloc({expr, type, offset, addend, &sym});
1019-
part.relrAuthDyn->relocs.push_back({sec, sec->relocs().size() - 1});
1020-
} else {
1021-
part.relaDyn->addReloc({R_AARCH64_AUTH_RELATIVE, sec, offset, false,
1022-
sym, addend, R_ABS});
1023-
}
1024-
return;
1025-
}
10261014
if (LLVM_UNLIKELY(type == ctx.target->iRelSymbolicRel)) {
10271015
if (sym.isPreemptible) {
10281016
auto diag = Err(ctx);

lld/ELF/Relocations.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,7 @@ using JumpModType = uint32_t;
4242
enum RelExpr {
4343
R_ABS,
4444
R_ADDEND,
45+
R_ADDEND_NEG,
4546
R_DTPREL,
4647
R_GOT,
4748
R_GOT_OFF,

lld/ELF/SyntheticSections.cpp

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -674,7 +674,6 @@ GotSection::GotSection(Ctx &ctx)
674674
numEntries = ctx.target->gotHeaderEntriesNum;
675675
}
676676

677-
void GotSection::addConstant(const Relocation &r) { relocations.push_back(r); }
678677
void GotSection::addEntry(const Symbol &sym) {
679678
assert(sym.auxIdx == ctx.symAux.size() - 1);
680679
ctx.symAux.back().gotIdx = numEntries++;
@@ -1708,6 +1707,9 @@ void RelocationBaseSection::partitionRels() {
17081707
}
17091708

17101709
void RelocationBaseSection::finalizeContents() {
1710+
mergeRels();
1711+
// Compute DT_RELACOUNT to be used by part.dynamic.
1712+
partitionRels();
17111713
SymbolTableBaseSection *symTab = getPartition(ctx).dynSymTab.get();
17121714

17131715
// When linking glibc statically, .rel{,a}.plt contains R_*_IRELATIVE
@@ -1797,6 +1799,8 @@ void RelrBaseSection::mergeRels() {
17971799
relocsVec.clear();
17981800
}
17991801

1802+
void RelrBaseSection::finalizeContents() { mergeRels(); }
1803+
18001804
template <class ELFT>
18011805
AndroidPackedRelocationSection<ELFT>::AndroidPackedRelocationSection(
18021806
Ctx &ctx, StringRef name, unsigned concurrency)

lld/ELF/SyntheticSections.h

Lines changed: 29 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -113,7 +113,7 @@ class GotSection final : public SyntheticSection {
113113
bool isNeeded() const override;
114114
void writeTo(uint8_t *buf) override;
115115

116-
void addConstant(const Relocation &r);
116+
void addConstant(const Relocation &r) { addReloc(r); }
117117
void addEntry(const Symbol &sym);
118118
void addAuthEntry(const Symbol &sym);
119119
bool addTlsDescEntry(const Symbol &sym);
@@ -530,14 +530,14 @@ class RelocationBaseSection : public SyntheticSection {
530530
}
531531
size_t getSize() const override { return relocs.size() * this->entsize; }
532532
size_t getRelativeRelocCount() const { return numRelativeRelocs; }
533-
void mergeRels();
534-
void partitionRels();
535533
void finalizeContents() override;
536534

537535
int32_t dynamicTag, sizeDynamicTag;
538536
SmallVector<DynamicReloc, 0> relocs;
539537

540538
protected:
539+
void mergeRels();
540+
void partitionRels();
541541
void computeRels();
542542
// Used when parallel relocation scanning adds relocations. The elements
543543
// will be moved into relocs by mergeRel().
@@ -585,22 +585,46 @@ struct RelativeReloc {
585585
return inputSec->getVA(inputSec->relocs()[relocIdx].offset);
586586
}
587587

588-
const InputSectionBase *inputSec;
588+
InputSectionBase *inputSec;
589589
size_t relocIdx;
590590
};
591591

592592
class RelrBaseSection : public SyntheticSection {
593593
public:
594594
RelrBaseSection(Ctx &, unsigned concurrency, bool isAArch64Auth = false);
595-
void mergeRels();
595+
/// Add a dynamic relocation without writing an addend to the output section.
596+
/// This overload can be used if the addends are written directly instead of
597+
/// using relocations on the input section.
598+
template <bool shard = false> void addReloc(const RelativeReloc &reloc) {
599+
relocs.push_back(reloc);
600+
}
601+
/// Add a relative dynamic relocation that uses the target address of \p sym
602+
/// (i.e. InputSection::getRelocTargetVA()) + \p addend as the addend.
603+
template <bool shard = false>
604+
void addRelativeReloc(InputSectionBase &isec, uint64_t offsetInSec,
605+
Symbol &sym, int64_t addend, RelType addendRelType,
606+
RelExpr expr) {
607+
assert(expr != R_ADDEND && "expected non-addend relocation expression");
608+
isec.addReloc({expr, addendRelType, offsetInSec, addend, &sym});
609+
addReloc<shard>({&isec, isec.relocs().size() - 1});
610+
}
596611
bool isNeeded() const override {
597612
return !relocs.empty() ||
598613
llvm::any_of(relocsVec, [](auto &v) { return !v.empty(); });
599614
}
615+
void finalizeContents() override;
600616
SmallVector<RelativeReloc, 0> relocs;
617+
618+
protected:
619+
void mergeRels();
601620
SmallVector<SmallVector<RelativeReloc, 0>, 0> relocsVec;
602621
};
603622

623+
template <>
624+
inline void RelrBaseSection::addReloc<true>(const RelativeReloc &reloc) {
625+
relocsVec[llvm::parallel::getThreadIndex()].push_back(reloc);
626+
}
627+
604628
// RelrSection is used to encode offsets for relative relocations.
605629
// Proposal for adding SHT_RELR sections to generic-abi is here:
606630
// https://groups.google.com/forum/#!topic/generic-abi/bX460iggiKg

lld/ELF/Writer.cpp

Lines changed: 5 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1583,9 +1583,10 @@ template <class ELFT> void Writer<ELFT>::finalizeAddressDependentContent() {
15831583
if (part.relrAuthDyn) {
15841584
auto it = llvm::remove_if(
15851585
part.relrAuthDyn->relocs, [this, &part](const RelativeReloc &elem) {
1586-
const Relocation &reloc = elem.inputSec->relocs()[elem.relocIdx];
1586+
Relocation &reloc = elem.inputSec->relocs()[elem.relocIdx];
15871587
if (isInt<32>(reloc.sym->getVA(ctx, reloc.addend)))
15881588
return false;
1589+
reloc.expr = R_NONE;
15891590
part.relaDyn->addReloc({R_AARCH64_AUTH_RELATIVE, elem.inputSec,
15901591
reloc.offset, false, *reloc.sym,
15911592
reloc.addend, R_ABS});
@@ -2110,20 +2111,9 @@ template <class ELFT> void Writer<ELFT>::finalizeSections() {
21102111
// Dynamic section must be the last one in this list and dynamic
21112112
// symbol table section (dynSymTab) must be the first one.
21122113
for (Partition &part : ctx.partitions) {
2113-
if (part.relaDyn) {
2114-
part.relaDyn->mergeRels();
2115-
// Compute DT_RELACOUNT to be used by part.dynamic.
2116-
part.relaDyn->partitionRels();
2117-
finalizeSynthetic(ctx, part.relaDyn.get());
2118-
}
2119-
if (part.relrDyn) {
2120-
part.relrDyn->mergeRels();
2121-
finalizeSynthetic(ctx, part.relrDyn.get());
2122-
}
2123-
if (part.relrAuthDyn) {
2124-
part.relrAuthDyn->mergeRels();
2125-
finalizeSynthetic(ctx, part.relrAuthDyn.get());
2126-
}
2114+
finalizeSynthetic(ctx, part.relaDyn.get());
2115+
finalizeSynthetic(ctx, part.relrDyn.get());
2116+
finalizeSynthetic(ctx, part.relrAuthDyn.get());
21272117

21282118
finalizeSynthetic(ctx, part.dynSymTab.get());
21292119
finalizeSynthetic(ctx, part.gnuHashTab.get());

0 commit comments

Comments
 (0)