Skip to content

Commit e6b7d20

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 9becc4a commit e6b7d20

File tree

8 files changed

+165
-9
lines changed

8 files changed

+165
-9
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 R_AARCH64_GOT_PAGE;
207210
case R_AARCH64_ADR_GOT_PAGE:
208211
case R_AARCH64_TLSIE_ADR_GOTTPREL_PAGE21:
209212
return R_AARCH64_GOT_PAGE_PC;
213+
case R_AARCH64_AUTH_ADR_GOT_PAGE:
214+
return R_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
@@ -789,6 +789,7 @@ uint64_t InputSectionBase::getRelocTargetVA(Ctx &ctx, const Relocation &r,
789789
case R_ARM_SBREL:
790790
return r.sym->getVA(ctx, a) - getARMStaticBase(*r.sym);
791791
case R_GOT:
792+
case R_AARCH64_AUTH_GOT:
792793
case R_RELAX_TLS_GD_TO_IE_ABS:
793794
return r.sym->getGotVA(ctx) + a;
794795
case R_LOONGARCH_GOT:
@@ -816,6 +817,7 @@ uint64_t InputSectionBase::getRelocTargetVA(Ctx &ctx, const Relocation &r,
816817
case R_RELAX_TLS_GD_TO_IE_GOT_OFF:
817818
return r.sym->getGotOffset(ctx) + a;
818819
case R_AARCH64_GOT_PAGE_PC:
820+
case R_AARCH64_AUTH_GOT_PAGE_PC:
819821
case R_AARCH64_RELAX_TLS_GD_TO_IE_PAGE_PC:
820822
return getAArch64Page(r.sym->getGotVA(ctx) + a) - getAArch64Page(p);
821823
case R_AARCH64_GOT_PAGE:

lld/ELF/Relocations.cpp

Lines changed: 35 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -210,8 +210,9 @@ static bool needsPlt(RelExpr expr) {
210210
}
211211

212212
bool lld::elf::needsGot(RelExpr expr) {
213-
return oneof<R_GOT, R_GOT_OFF, R_MIPS_GOT_LOCAL_PAGE, R_MIPS_GOT_OFF,
214-
R_MIPS_GOT_OFF32, R_AARCH64_GOT_PAGE_PC, R_GOT_PC, R_GOTPLT,
213+
return oneof<R_GOT, R_AARCH64_AUTH_GOT, R_GOT_OFF, R_MIPS_GOT_LOCAL_PAGE,
214+
R_MIPS_GOT_OFF, R_MIPS_GOT_OFF32, R_AARCH64_GOT_PAGE_PC,
215+
R_AARCH64_AUTH_GOT_PAGE_PC, R_GOT_PC, R_GOTPLT,
215216
R_AARCH64_GOT_PAGE, R_LOONGARCH_GOT, R_LOONGARCH_GOT_PAGE_PC>(
216217
expr);
217218
}
@@ -910,14 +911,26 @@ void elf::addGotEntry(Ctx &ctx, Symbol &sym) {
910911

911912
// If preemptible, emit a GLOB_DAT relocation.
912913
if (sym.isPreemptible) {
913-
ctx.mainPart->relaDyn->addReloc({ctx.target->gotRel, ctx.in.got.get(), off,
914+
RelType gotRel = ctx.target->gotRel;
915+
if (sym.hasFlag(NEEDS_GOT_AUTH)) {
916+
assert(ctx.arg.emachine == EM_AARCH64);
917+
gotRel = R_AARCH64_AUTH_GLOB_DAT;
918+
}
919+
ctx.mainPart->relaDyn->addReloc({gotRel, ctx.in.got.get(), off,
914920
DynamicReloc::AgainstSymbol, sym, 0,
915921
R_ABS});
916922
return;
917923
}
918924

919925
// Otherwise, the value is either a link-time constant or the load base
920-
// plus a constant.
926+
// plus a constant. Signed GOT requires dynamic relocation.
927+
if (sym.hasFlag(NEEDS_GOT_AUTH)) {
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+
return;
932+
}
933+
921934
if (!ctx.arg.isPic || isAbsolute(sym))
922935
ctx.in.got->addConstant({R_ABS, ctx.target->symbolicRel, off, 0, &sym});
923936
else
@@ -971,10 +984,11 @@ bool RelocationScanner::isStaticLinkTimeConstant(RelExpr e, RelType type,
971984
// These expressions always compute a constant
972985
if (oneof<R_GOTPLT, R_GOT_OFF, R_RELAX_HINT, R_MIPS_GOT_LOCAL_PAGE,
973986
R_MIPS_GOTREL, R_MIPS_GOT_OFF, R_MIPS_GOT_OFF32, R_MIPS_GOT_GP_PC,
974-
R_AARCH64_GOT_PAGE_PC, R_GOT_PC, R_GOTONLY_PC, R_GOTPLTONLY_PC,
975-
R_PLT_PC, R_PLT_GOTREL, R_PLT_GOTPLT, R_GOTPLT_GOTREL, R_GOTPLT_PC,
976-
R_PPC32_PLTREL, R_PPC64_CALL_PLT, R_PPC64_RELAX_TOC, R_RISCV_ADD,
977-
R_AARCH64_GOT_PAGE, R_LOONGARCH_PLT_PAGE_PC, R_LOONGARCH_GOT,
987+
R_AARCH64_GOT_PAGE_PC, R_AARCH64_AUTH_GOT_PAGE_PC, R_GOT_PC,
988+
R_GOTONLY_PC, R_GOTPLTONLY_PC, R_PLT_PC, R_PLT_GOTREL, R_PLT_GOTPLT,
989+
R_GOTPLT_GOTREL, R_GOTPLT_PC, R_PPC32_PLTREL, R_PPC64_CALL_PLT,
990+
R_PPC64_RELAX_TOC, R_RISCV_ADD, R_AARCH64_GOT_PAGE,
991+
R_AARCH64_AUTH_GOT, R_LOONGARCH_PLT_PAGE_PC, R_LOONGARCH_GOT,
978992
R_LOONGARCH_GOT_PAGE_PC>(e))
979993
return true;
980994

@@ -1089,7 +1103,19 @@ void RelocationScanner::processAux(RelExpr expr, RelType type, uint64_t offset,
10891103
} else if (!sym.isTls() || ctx.arg.emachine != EM_LOONGARCH) {
10901104
// Many LoongArch TLS relocs reuse the R_LOONGARCH_GOT type, in which
10911105
// case the NEEDS_GOT flag shouldn't get set.
1092-
sym.setFlags(NEEDS_GOT);
1106+
bool needsGotAuth =
1107+
(expr == R_AARCH64_AUTH_GOT || expr == R_AARCH64_AUTH_GOT_PAGE_PC);
1108+
uint16_t flags = sym.flags.load(std::memory_order_relaxed);
1109+
if (!(flags & NEEDS_GOT)) {
1110+
if (needsGotAuth)
1111+
sym.setFlags(NEEDS_GOT | NEEDS_GOT_AUTH);
1112+
else
1113+
sym.setFlags(NEEDS_GOT);
1114+
} else if (needsGotAuth != static_cast<bool>(flags & NEEDS_GOT_AUTH)) {
1115+
fatal("both AUTH and non-AUTH GOT entries for '" + sym.getName() +
1116+
"' requested, but only one type of GOT entry per symbol is "
1117+
"supported");
1118+
}
10931119
}
10941120
} else if (needsPlt(expr)) {
10951121
sym.setFlags(NEEDS_PLT);

lld/ELF/Relocations.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -91,7 +91,9 @@ enum RelExpr {
9191
// of a relocation type, there are some relocations whose semantics are
9292
// unique to a target. Such relocation are marked with R_<TARGET_NAME>.
9393
R_AARCH64_GOT_PAGE_PC,
94+
R_AARCH64_AUTH_GOT_PAGE_PC,
9495
R_AARCH64_GOT_PAGE,
96+
R_AARCH64_AUTH_GOT,
9597
R_AARCH64_PAGE_PC,
9698
R_AARCH64_RELAX_TLS_GD_TO_IE_PAGE_PC,
9799
R_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)