Skip to content

Commit 417d2d7

Browse files
authored
[PAC][lld][AArch64][ELF] Support signed GOT (#113815)
Depends on #113811 Support `R_AARCH64_AUTH_ADR_GOT_PAGE`, `R_AARCH64_AUTH_GOT_LO12_NC` and `R_AARCH64_AUTH_GOT_ADD_LO12_NC` GOT-generating relocations. For preemptible symbols, dynamic relocation `R_AARCH64_AUTH_GLOB_DAT` is emitted. Otherwise, we unconditionally emit `R_AARCH64_AUTH_RELATIVE` dynamic relocation since pointers in signed GOT needs to be signed during dynamic link time.
1 parent f515d7a commit 417d2d7

8 files changed

+176
-8
lines changed

lld/ELF/Arch/AArch64.cpp

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -202,11 +202,16 @@ RelExpr AArch64::getRelExpr(RelType type, const Symbol &s,
202202
case R_AARCH64_LD64_GOT_LO12_NC:
203203
case R_AARCH64_TLSIE_LD64_GOTTPREL_LO12_NC:
204204
return R_GOT;
205+
case R_AARCH64_AUTH_LD64_GOT_LO12_NC:
206+
case R_AARCH64_AUTH_GOT_ADD_LO12_NC:
207+
return RE_AARCH64_AUTH_GOT;
205208
case R_AARCH64_LD64_GOTPAGE_LO15:
206209
return RE_AARCH64_GOT_PAGE;
207210
case R_AARCH64_ADR_GOT_PAGE:
208211
case R_AARCH64_TLSIE_ADR_GOTTPREL_PAGE21:
209212
return RE_AARCH64_GOT_PAGE_PC;
213+
case R_AARCH64_AUTH_ADR_GOT_PAGE:
214+
return RE_AARCH64_AUTH_GOT_PAGE_PC;
210215
case R_AARCH64_GOTPCREL32:
211216
case R_AARCH64_GOT_LD_PREL19:
212217
return R_GOT_PC;
@@ -258,6 +263,7 @@ int64_t AArch64::getImplicitAddend(const uint8_t *buf, RelType type) const {
258263
return read64(ctx, buf + 8);
259264
case R_AARCH64_NONE:
260265
case R_AARCH64_GLOB_DAT:
266+
case R_AARCH64_AUTH_GLOB_DAT:
261267
case R_AARCH64_JUMP_SLOT:
262268
return 0;
263269
case R_AARCH64_ABS16:
@@ -528,9 +534,11 @@ void AArch64::relocate(uint8_t *loc, const Relocation &rel,
528534
write32(ctx, loc, val);
529535
break;
530536
case R_AARCH64_ADD_ABS_LO12_NC:
537+
case R_AARCH64_AUTH_GOT_ADD_LO12_NC:
531538
write32Imm12(loc, val);
532539
break;
533540
case R_AARCH64_ADR_GOT_PAGE:
541+
case R_AARCH64_AUTH_ADR_GOT_PAGE:
534542
case R_AARCH64_ADR_PREL_PG_HI21:
535543
case R_AARCH64_TLSIE_ADR_GOTTPREL_PAGE21:
536544
case R_AARCH64_TLSDESC_ADR_PAGE21:
@@ -580,6 +588,7 @@ void AArch64::relocate(uint8_t *loc, const Relocation &rel,
580588
break;
581589
case R_AARCH64_LDST64_ABS_LO12_NC:
582590
case R_AARCH64_LD64_GOT_LO12_NC:
591+
case R_AARCH64_AUTH_LD64_GOT_LO12_NC:
583592
case R_AARCH64_TLSIE_LD64_GOTTPREL_LO12_NC:
584593
case R_AARCH64_TLSLE_LDST64_TPREL_LO12_NC:
585594
case R_AARCH64_TLSDESC_LD64_LO12:

lld/ELF/InputSection.cpp

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -783,6 +783,7 @@ uint64_t InputSectionBase::getRelocTargetVA(Ctx &ctx, const Relocation &r,
783783
case RE_ARM_SBREL:
784784
return r.sym->getVA(ctx, a) - getARMStaticBase(*r.sym);
785785
case R_GOT:
786+
case RE_AARCH64_AUTH_GOT:
786787
case R_RELAX_TLS_GD_TO_IE_ABS:
787788
return r.sym->getGotVA(ctx) + a;
788789
case RE_LOONGARCH_GOT:
@@ -810,6 +811,7 @@ uint64_t InputSectionBase::getRelocTargetVA(Ctx &ctx, const Relocation &r,
810811
case R_RELAX_TLS_GD_TO_IE_GOT_OFF:
811812
return r.sym->getGotOffset(ctx) + a;
812813
case RE_AARCH64_GOT_PAGE_PC:
814+
case RE_AARCH64_AUTH_GOT_PAGE_PC:
813815
case RE_AARCH64_RELAX_TLS_GD_TO_IE_PAGE_PC:
814816
return getAArch64Page(r.sym->getGotVA(ctx) + a) - getAArch64Page(p);
815817
case RE_AARCH64_GOT_PAGE:

lld/ELF/Relocations.cpp

Lines changed: 46 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -197,8 +197,9 @@ static bool needsPlt(RelExpr expr) {
197197
}
198198

199199
bool lld::elf::needsGot(RelExpr expr) {
200-
return oneof<R_GOT, R_GOT_OFF, RE_MIPS_GOT_LOCAL_PAGE, RE_MIPS_GOT_OFF,
201-
RE_MIPS_GOT_OFF32, RE_AARCH64_GOT_PAGE_PC, R_GOT_PC, R_GOTPLT,
200+
return oneof<R_GOT, RE_AARCH64_AUTH_GOT, R_GOT_OFF, RE_MIPS_GOT_LOCAL_PAGE,
201+
RE_MIPS_GOT_OFF, RE_MIPS_GOT_OFF32, RE_AARCH64_GOT_PAGE_PC,
202+
RE_AARCH64_AUTH_GOT_PAGE_PC, R_GOT_PC, R_GOTPLT,
202203
RE_AARCH64_GOT_PAGE, RE_LOONGARCH_GOT, RE_LOONGARCH_GOT_PAGE_PC>(
203204
expr);
204205
}
@@ -910,6 +911,25 @@ void elf::addGotEntry(Ctx &ctx, Symbol &sym) {
910911
ctx.target->symbolicRel);
911912
}
912913

914+
static void addGotAuthEntry(Ctx &ctx, Symbol &sym) {
915+
ctx.in.got->addEntry(sym);
916+
ctx.in.got->addAuthEntry(sym);
917+
uint64_t off = sym.getGotOffset(ctx);
918+
919+
// If preemptible, emit a GLOB_DAT relocation.
920+
if (sym.isPreemptible) {
921+
ctx.mainPart->relaDyn->addReloc({R_AARCH64_AUTH_GLOB_DAT, ctx.in.got.get(),
922+
off, DynamicReloc::AgainstSymbol, sym, 0,
923+
R_ABS});
924+
return;
925+
}
926+
927+
// Signed GOT requires dynamic relocation.
928+
ctx.in.got->getPartition(ctx).relaDyn->addReloc(
929+
{R_AARCH64_AUTH_RELATIVE, ctx.in.got.get(), off,
930+
DynamicReloc::AddendOnlyWithTargetVA, sym, 0, R_ABS});
931+
}
932+
913933
static void addTpOffsetGotEntry(Ctx &ctx, Symbol &sym) {
914934
ctx.in.got->addEntry(sym);
915935
uint64_t off = sym.getGotOffset(ctx);
@@ -956,11 +976,12 @@ bool RelocationScanner::isStaticLinkTimeConstant(RelExpr e, RelType type,
956976
// These expressions always compute a constant
957977
if (oneof<R_GOTPLT, R_GOT_OFF, R_RELAX_HINT, RE_MIPS_GOT_LOCAL_PAGE,
958978
RE_MIPS_GOTREL, RE_MIPS_GOT_OFF, RE_MIPS_GOT_OFF32,
959-
RE_MIPS_GOT_GP_PC, RE_AARCH64_GOT_PAGE_PC, R_GOT_PC, R_GOTONLY_PC,
979+
RE_MIPS_GOT_GP_PC, RE_AARCH64_GOT_PAGE_PC,
980+
RE_AARCH64_AUTH_GOT_PAGE_PC, R_GOT_PC, R_GOTONLY_PC,
960981
R_GOTPLTONLY_PC, R_PLT_PC, R_PLT_GOTREL, R_PLT_GOTPLT,
961982
R_GOTPLT_GOTREL, R_GOTPLT_PC, RE_PPC32_PLTREL, RE_PPC64_CALL_PLT,
962983
RE_PPC64_RELAX_TOC, RE_RISCV_ADD, RE_AARCH64_GOT_PAGE,
963-
RE_LOONGARCH_PLT_PAGE_PC, RE_LOONGARCH_GOT,
984+
RE_AARCH64_AUTH_GOT, RE_LOONGARCH_PLT_PAGE_PC, RE_LOONGARCH_GOT,
964985
RE_LOONGARCH_GOT_PAGE_PC>(e))
965986
return true;
966987

@@ -1075,7 +1096,10 @@ void RelocationScanner::processAux(RelExpr expr, RelType type, uint64_t offset,
10751096
} else if (!sym.isTls() || ctx.arg.emachine != EM_LOONGARCH) {
10761097
// Many LoongArch TLS relocs reuse the RE_LOONGARCH_GOT type, in which
10771098
// case the NEEDS_GOT flag shouldn't get set.
1078-
sym.setFlags(NEEDS_GOT);
1099+
if (expr == RE_AARCH64_AUTH_GOT || expr == RE_AARCH64_AUTH_GOT_PAGE_PC)
1100+
sym.setFlags(NEEDS_GOT | NEEDS_GOT_AUTH);
1101+
else
1102+
sym.setFlags(NEEDS_GOT | NEEDS_GOT_NONAUTH);
10791103
}
10801104
} else if (needsPlt(expr)) {
10811105
sym.setFlags(NEEDS_PLT);
@@ -1750,8 +1774,11 @@ static bool handleNonPreemptibleIfunc(Ctx &ctx, Symbol &sym, uint16_t flags) {
17501774
// don't try to call the PLT as if it were an ifunc resolver.
17511775
d.type = STT_FUNC;
17521776

1753-
if (flags & NEEDS_GOT)
1777+
if (flags & NEEDS_GOT) {
1778+
assert(!(flags & NEEDS_GOT_AUTH) &&
1779+
"R_AARCH64_AUTH_IRELATIVE is not supported yet");
17541780
addGotEntry(ctx, sym);
1781+
}
17551782
} else if (flags & NEEDS_GOT) {
17561783
// Redirect GOT accesses to point to the Igot.
17571784
sym.gotInIgot = true;
@@ -1772,8 +1799,19 @@ void elf::postScanRelocations(Ctx &ctx) {
17721799
return;
17731800
sym.allocateAux(ctx);
17741801

1775-
if (flags & NEEDS_GOT)
1776-
addGotEntry(ctx, sym);
1802+
if (flags & NEEDS_GOT) {
1803+
if ((flags & NEEDS_GOT_AUTH) && (flags & NEEDS_GOT_NONAUTH)) {
1804+
auto diag = Err(ctx);
1805+
diag << "both AUTH and non-AUTH GOT entries for '" << sym.getName()
1806+
<< "' requested, but only one type of GOT entry per symbol is "
1807+
"supported";
1808+
return;
1809+
}
1810+
if (flags & NEEDS_GOT_AUTH)
1811+
addGotAuthEntry(ctx, sym);
1812+
else
1813+
addGotEntry(ctx, sym);
1814+
}
17771815
if (flags & NEEDS_PLT)
17781816
addPltEntry(ctx, *ctx.in.plt, *ctx.in.gotPlt, *ctx.in.relaPlt,
17791817
ctx.target->pltRel, sym);

lld/ELF/Relocations.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -92,7 +92,9 @@ enum RelExpr {
9292
// of a relocation type, there are some relocations whose semantics are
9393
// unique to a target. Such relocation are marked with RE_<TARGET_NAME>.
9494
RE_AARCH64_GOT_PAGE_PC,
95+
RE_AARCH64_AUTH_GOT_PAGE_PC,
9596
RE_AARCH64_GOT_PAGE,
97+
RE_AARCH64_AUTH_GOT,
9698
RE_AARCH64_PAGE_PC,
9799
RE_AARCH64_RELAX_TLS_GD_TO_IE_PAGE_PC,
98100
RE_AARCH64_TLSDESC_PAGE,

lld/ELF/Symbols.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,8 @@ enum {
5151
NEEDS_TLSGD_TO_IE = 1 << 6,
5252
NEEDS_GOT_DTPREL = 1 << 7,
5353
NEEDS_TLSIE = 1 << 8,
54+
NEEDS_GOT_AUTH = 1 << 9,
55+
NEEDS_GOT_NONAUTH = 1 << 10,
5456
};
5557

5658
// The base class for real symbol classes.

lld/ELF/SyntheticSections.cpp

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -670,6 +670,10 @@ void GotSection::addEntry(const Symbol &sym) {
670670
ctx.symAux.back().gotIdx = numEntries++;
671671
}
672672

673+
void GotSection::addAuthEntry(const Symbol &sym) {
674+
authEntries.push_back({(numEntries - 1) * ctx.arg.wordsize, sym.isFunc()});
675+
}
676+
673677
bool GotSection::addTlsDescEntry(const Symbol &sym) {
674678
assert(sym.auxIdx == ctx.symAux.size() - 1);
675679
ctx.symAux.back().tlsDescIdx = numEntries;
@@ -732,6 +736,21 @@ void GotSection::writeTo(uint8_t *buf) {
732736
return;
733737
ctx.target->writeGotHeader(buf);
734738
ctx.target->relocateAlloc(*this, buf);
739+
for (const AuthEntryInfo &authEntry : authEntries) {
740+
// https://github.com/ARM-software/abi-aa/blob/2024Q3/pauthabielf64/pauthabielf64.rst#default-signing-schema
741+
// Signed GOT entries use the IA key for symbols of type STT_FUNC and the
742+
// DA key for all other symbol types, with the address of the GOT entry as
743+
// the modifier. The static linker must encode the signing schema into the
744+
// GOT slot.
745+
//
746+
// https://github.com/ARM-software/abi-aa/blob/2024Q3/pauthabielf64/pauthabielf64.rst#encoding-the-signing-schema
747+
// If address diversity is set and the discriminator
748+
// is 0 then modifier = Place
749+
uint8_t *dest = buf + authEntry.offset;
750+
uint64_t key = authEntry.isSymbolFunc ? /*IA=*/0b00 : /*DA=*/0b10;
751+
uint64_t addrDiversity = 1;
752+
write64(ctx, dest, (addrDiversity << 63) | (key << 60));
753+
}
735754
}
736755

737756
static uint64_t getMipsPageAddr(uint64_t addr) {

lld/ELF/SyntheticSections.h

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -112,6 +112,7 @@ class GotSection final : public SyntheticSection {
112112

113113
void addConstant(const Relocation &r);
114114
void addEntry(const Symbol &sym);
115+
void addAuthEntry(const Symbol &sym);
115116
bool addTlsDescEntry(const Symbol &sym);
116117
bool addDynTlsEntry(const Symbol &sym);
117118
bool addTlsIndex();
@@ -131,6 +132,11 @@ class GotSection final : public SyntheticSection {
131132
size_t numEntries = 0;
132133
uint32_t tlsIndexOff = -1;
133134
uint64_t size = 0;
135+
struct AuthEntryInfo {
136+
size_t offset;
137+
bool isSymbolFunc;
138+
};
139+
SmallVector<AuthEntryInfo, 0> authEntries;
134140
};
135141

136142
// .note.GNU-stack section.
Lines changed: 90 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,90 @@
1+
# REQUIRES: aarch64
2+
3+
# RUN: rm -rf %t && split-file %s %t && cd %t
4+
5+
# RUN: llvm-mc -filetype=obj -triple=aarch64 %p/Inputs/shared.s -o a.o
6+
# RUN: ld.lld -shared a.o -o a.so
7+
8+
#--- ok.s
9+
# RUN: llvm-mc -filetype=obj -triple=aarch64 ok.s -o ok.o
10+
11+
# RUN: ld.lld ok.o a.so -pie -o ok1
12+
# RUN: llvm-readelf -r -S -x .got ok1 | FileCheck %s --check-prefix=OK1
13+
14+
# RUN: ld.lld ok.o a.o -pie -o ok2
15+
# RUN: llvm-readelf -r -S -x .got -s ok2 | FileCheck %s --check-prefix=OK2
16+
17+
# OK1: Offset Info Type Symbol's Value Symbol's Name + Addend
18+
# OK1-NEXT: 0000000000020380 0000000100000412 R_AARCH64_AUTH_GLOB_DAT 0000000000000000 bar + 0
19+
# OK1-NEXT: 0000000000020388 0000000200000412 R_AARCH64_AUTH_GLOB_DAT 0000000000000000 zed + 0
20+
21+
## Symbol's values for bar and zed are equal since they contain no content (see Inputs/shared.s)
22+
# OK2: Offset Info Type Symbol's Value Symbol's Name + Addend
23+
# OK2-NEXT: 0000000000020320 0000000000000411 R_AARCH64_AUTH_RELATIVE 10260
24+
# OK2-NEXT: 0000000000020328 0000000000000411 R_AARCH64_AUTH_RELATIVE 10260
25+
26+
# OK1: Hex dump of section '.got':
27+
# OK1-NEXT: 0x00020380 00000000 00000080 00000000 000000a0
28+
## ^^
29+
## 0b10000000 bit 63 address diversity = true, bits 61..60 key = IA
30+
## ^^
31+
## 0b10100000 bit 63 address diversity = true, bits 61..60 key = DA
32+
33+
# OK2: Symbol table '.symtab' contains {{.*}} entries:
34+
# OK2: Num: Value Size Type Bind Vis Ndx Name
35+
# OK2: 0000000000010260 0 FUNC GLOBAL DEFAULT 6 bar
36+
# OK2: 0000000000010260 0 NOTYPE GLOBAL DEFAULT 6 zed
37+
38+
# OK2: Hex dump of section '.got':
39+
# OK2-NEXT: 0x00020320 00000000 00000080 00000000 000000a0
40+
## ^^
41+
## 0b10000000 bit 63 address diversity = true, bits 61..60 key = IA
42+
## ^^
43+
## 0b10100000 bit 63 address diversity = true, bits 61..60 key = DA
44+
45+
# RUN: llvm-objdump -d ok1 | FileCheck %s --check-prefix=OK1-ASM
46+
47+
# OK1-ASM: <_start>:
48+
# OK1-ASM-NEXT: adrp x0, 0x20000
49+
# OK1-ASM-NEXT: ldr x0, [x0, #0x380]
50+
# OK1-ASM-NEXT: adrp x1, 0x20000
51+
# OK1-ASM-NEXT: add x1, x1, #0x380
52+
# OK1-ASM-NEXT: adrp x0, 0x20000
53+
# OK1-ASM-NEXT: ldr x0, [x0, #0x388]
54+
# OK1-ASM-NEXT: adrp x1, 0x20000
55+
# OK1-ASM-NEXT: add x1, x1, #0x388
56+
57+
# RUN: llvm-objdump -d ok2 | FileCheck %s --check-prefix=OK2-ASM
58+
59+
# OK2-ASM: <_start>:
60+
# OK2-ASM-NEXT: adrp x0, 0x20000
61+
# OK2-ASM-NEXT: ldr x0, [x0, #0x320]
62+
# OK2-ASM-NEXT: adrp x1, 0x20000
63+
# OK2-ASM-NEXT: add x1, x1, #0x320
64+
# OK2-ASM-NEXT: adrp x0, 0x20000
65+
# OK2-ASM-NEXT: ldr x0, [x0, #0x328]
66+
# OK2-ASM-NEXT: adrp x1, 0x20000
67+
# OK2-ASM-NEXT: add x1, x1, #0x328
68+
69+
.globl _start
70+
_start:
71+
adrp x0, :got_auth:bar
72+
ldr x0, [x0, :got_auth_lo12:bar]
73+
adrp x1, :got_auth:bar
74+
add x1, x1, :got_auth_lo12:bar
75+
adrp x0, :got_auth:zed
76+
ldr x0, [x0, :got_auth_lo12:zed]
77+
adrp x1, :got_auth:zed
78+
add x1, x1, :got_auth_lo12:zed
79+
80+
#--- err.s
81+
# RUN: llvm-mc -filetype=obj -triple=aarch64 err.s -o err.o
82+
# RUN: not ld.lld err.o a.so -pie 2>&1 | FileCheck %s --check-prefix=ERR --implicit-check-not=error:
83+
# ERR: error: both AUTH and non-AUTH GOT entries for 'bar' requested, but only one type of GOT entry per symbol is supported
84+
85+
.globl _start
86+
_start:
87+
adrp x0, :got_auth:bar
88+
ldr x0, [x0, :got_auth_lo12:bar]
89+
adrp x0, :got:bar
90+
ldr x0, [x0, :got_lo12:bar]

0 commit comments

Comments
 (0)