Skip to content

Commit db99224

Browse files
committed
[PAC][lld][AArch64][ELF] Support signed GOT
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 eeadd01 commit db99224

File tree

8 files changed

+163
-7
lines changed

8 files changed

+163
-7
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 R_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 R_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: 33 additions & 7 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
}
@@ -896,14 +897,26 @@ void elf::addGotEntry(Ctx &ctx, Symbol &sym) {
896897

897898
// If preemptible, emit a GLOB_DAT relocation.
898899
if (sym.isPreemptible) {
899-
ctx.mainPart->relaDyn->addReloc({ctx.target->gotRel, ctx.in.got.get(), off,
900+
RelType gotRel = ctx.target->gotRel;
901+
if (sym.hasFlag(NEEDS_GOT_AUTH)) {
902+
assert(ctx.arg.emachine == EM_AARCH64);
903+
gotRel = R_AARCH64_AUTH_GLOB_DAT;
904+
}
905+
ctx.mainPart->relaDyn->addReloc({gotRel, ctx.in.got.get(), off,
900906
DynamicReloc::AgainstSymbol, sym, 0,
901907
R_ABS});
902908
return;
903909
}
904910

905911
// Otherwise, the value is either a link-time constant or the load base
906-
// plus a constant.
912+
// plus a constant. Signed GOT requires dynamic relocation.
913+
if (sym.hasFlag(NEEDS_GOT_AUTH)) {
914+
ctx.in.got->getPartition(ctx).relaDyn->addReloc(
915+
{R_AARCH64_AUTH_RELATIVE, ctx.in.got.get(), off,
916+
DynamicReloc::AddendOnlyWithTargetVA, sym, 0, R_ABS});
917+
return;
918+
}
919+
907920
if (!ctx.arg.isPic || isAbsolute(sym))
908921
ctx.in.got->addConstant({R_ABS, ctx.target->symbolicRel, off, 0, &sym});
909922
else
@@ -957,11 +970,12 @@ bool RelocationScanner::isStaticLinkTimeConstant(RelExpr e, RelType type,
957970
// These expressions always compute a constant
958971
if (oneof<R_GOTPLT, R_GOT_OFF, R_RELAX_HINT, RE_MIPS_GOT_LOCAL_PAGE,
959972
RE_MIPS_GOTREL, RE_MIPS_GOT_OFF, RE_MIPS_GOT_OFF32,
960-
RE_MIPS_GOT_GP_PC, RE_AARCH64_GOT_PAGE_PC, R_GOT_PC, R_GOTONLY_PC,
973+
RE_MIPS_GOT_GP_PC, RE_AARCH64_GOT_PAGE_PC,
974+
RE_AARCH64_AUTH_GOT_PAGE_PC, R_GOT_PC, R_GOTONLY_PC,
961975
R_GOTPLTONLY_PC, R_PLT_PC, R_PLT_GOTREL, R_PLT_GOTPLT,
962976
R_GOTPLT_GOTREL, R_GOTPLT_PC, RE_PPC32_PLTREL, RE_PPC64_CALL_PLT,
963977
RE_PPC64_RELAX_TOC, RE_RISCV_ADD, RE_AARCH64_GOT_PAGE,
964-
RE_LOONGARCH_PLT_PAGE_PC, RE_LOONGARCH_GOT,
978+
RE_AARCH64_AUTH_GOT, RE_LOONGARCH_PLT_PAGE_PC, RE_LOONGARCH_GOT,
965979
RE_LOONGARCH_GOT_PAGE_PC>(e))
966980
return true;
967981

@@ -1076,7 +1090,19 @@ void RelocationScanner::processAux(RelExpr expr, RelType type, uint64_t offset,
10761090
} else if (!sym.isTls() || ctx.arg.emachine != EM_LOONGARCH) {
10771091
// Many LoongArch TLS relocs reuse the RE_LOONGARCH_GOT type, in which
10781092
// case the NEEDS_GOT flag shouldn't get set.
1079-
sym.setFlags(NEEDS_GOT);
1093+
bool needsGotAuth =
1094+
(expr == R_AARCH64_AUTH_GOT || expr == R_AARCH64_AUTH_GOT_PAGE_PC);
1095+
uint16_t flags = sym.flags.load(std::memory_order_relaxed);
1096+
if (!(flags & NEEDS_GOT)) {
1097+
if (needsGotAuth)
1098+
sym.setFlags(NEEDS_GOT | NEEDS_GOT_AUTH);
1099+
else
1100+
sym.setFlags(NEEDS_GOT);
1101+
} else if (needsGotAuth != static_cast<bool>(flags & NEEDS_GOT_AUTH)) {
1102+
fatal("both AUTH and non-AUTH GOT entries for '" + sym.getName() +
1103+
"' requested, but only one type of GOT entry per symbol is "
1104+
"supported");
1105+
}
10801106
}
10811107
} else if (needsPlt(expr)) {
10821108
sym.setFlags(NEEDS_PLT);

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: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,7 @@ 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,
5455
};
5556

5657
// The base class for real symbol classes.

lld/ELF/SyntheticSections.cpp

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -668,6 +668,8 @@ void GotSection::addConstant(const Relocation &r) { relocations.push_back(r); }
668668
void GotSection::addEntry(const Symbol &sym) {
669669
assert(sym.auxIdx == ctx.symAux.size() - 1);
670670
ctx.symAux.back().gotIdx = numEntries++;
671+
if (sym.hasFlag(NEEDS_GOT_AUTH))
672+
authEntries.push_back({(numEntries - 1) * ctx.arg.wordsize, sym.isFunc()});
671673
}
672674

673675
bool GotSection::addTlsDescEntry(const Symbol &sym) {
@@ -732,6 +734,21 @@ void GotSection::writeTo(uint8_t *buf) {
732734
return;
733735
ctx.target->writeGotHeader(buf);
734736
ctx.target->relocateAlloc(*this, buf);
737+
for (const AuthEntryInfo &authEntry : authEntries) {
738+
// https://github.com/ARM-software/abi-aa/blob/main/pauthabielf64/pauthabielf64.rst#default-signing-schema
739+
// Signed GOT entries use the IA key for symbols of type STT_FUNC and the
740+
// DA key for all other symbol types, with the address of the GOT entry as
741+
// the modifier. The static linker must encode the signing schema into the
742+
// GOT slot.
743+
//
744+
// https://github.com/ARM-software/abi-aa/blob/main/pauthabielf64/pauthabielf64.rst#encoding-the-signing-schema
745+
// If address diversity is set and the discriminator
746+
// is 0 then modifier = Place
747+
uint8_t *dest = buf + authEntry.offset;
748+
uint64_t key = authEntry.isSymbolFunc ? /*IA*/ 0b00 : /*DA*/ 0b10;
749+
uint64_t addrDiversity = 1;
750+
write64(ctx, dest, (addrDiversity << 63) | (key << 60));
751+
}
735752
}
736753

737754
static uint64_t getMipsPageAddr(uint64_t addr) {

lld/ELF/SyntheticSections.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -131,6 +131,11 @@ class GotSection final : public SyntheticSection {
131131
size_t numEntries = 0;
132132
uint32_t tlsIndexOff = -1;
133133
uint64_t size = 0;
134+
struct AuthEntryInfo {
135+
size_t offset;
136+
bool isSymbolFunc;
137+
};
138+
SmallVector<AuthEntryInfo, 0> authEntries;
134139
};
135140

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

0 commit comments

Comments
 (0)