Skip to content

Commit e179c9b

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 da083e3 commit e179c9b

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:
@@ -529,9 +535,11 @@ void AArch64::relocate(uint8_t *loc, const Relocation &rel,
529535
write32(ctx, loc, val);
530536
break;
531537
case R_AARCH64_ADD_ABS_LO12_NC:
538+
case R_AARCH64_AUTH_GOT_ADD_LO12_NC:
532539
write32Imm12(loc, val);
533540
break;
534541
case R_AARCH64_ADR_GOT_PAGE:
542+
case R_AARCH64_AUTH_ADR_GOT_PAGE:
535543
case R_AARCH64_ADR_PREL_PG_HI21:
536544
case R_AARCH64_TLSIE_ADR_GOTTPREL_PAGE21:
537545
case R_AARCH64_TLSDESC_ADR_PAGE21:
@@ -581,6 +589,7 @@ void AArch64::relocate(uint8_t *loc, const Relocation &rel,
581589
break;
582590
case R_AARCH64_LDST64_ABS_LO12_NC:
583591
case R_AARCH64_LD64_GOT_LO12_NC:
592+
case R_AARCH64_AUTH_LD64_GOT_LO12_NC:
584593
case R_AARCH64_TLSIE_LD64_GOTTPREL_LO12_NC:
585594
case R_AARCH64_TLSLE_LDST64_TPREL_LO12_NC:
586595
case R_AARCH64_TLSDESC_LD64_LO12:

lld/ELF/InputSection.cpp

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -754,6 +754,7 @@ uint64_t InputSectionBase::getRelocTargetVA(Ctx &ctx, const Relocation &r,
754754
case R_ARM_SBREL:
755755
return r.sym->getVA(ctx, a) - getARMStaticBase(*r.sym);
756756
case R_GOT:
757+
case R_AARCH64_AUTH_GOT:
757758
case R_RELAX_TLS_GD_TO_IE_ABS:
758759
return r.sym->getGotVA(ctx) + a;
759760
case R_LOONGARCH_GOT:
@@ -781,6 +782,7 @@ uint64_t InputSectionBase::getRelocTargetVA(Ctx &ctx, const Relocation &r,
781782
case R_RELAX_TLS_GD_TO_IE_GOT_OFF:
782783
return r.sym->getGotOffset(ctx) + a;
783784
case R_AARCH64_GOT_PAGE_PC:
785+
case R_AARCH64_AUTH_GOT_PAGE_PC:
784786
case R_AARCH64_RELAX_TLS_GD_TO_IE_PAGE_PC:
785787
return getAArch64Page(r.sym->getGotVA(ctx) + a) - getAArch64Page(p);
786788
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
}
@@ -933,14 +934,26 @@ void elf::addGotEntry(Ctx &ctx, Symbol &sym) {
933934

934935
// If preemptible, emit a GLOB_DAT relocation.
935936
if (sym.isPreemptible) {
936-
ctx.mainPart->relaDyn->addReloc({ctx.target->gotRel, ctx.in.got.get(), off,
937+
RelType gotRel = ctx.target->gotRel;
938+
if (sym.hasFlag(NEEDS_GOT_AUTH)) {
939+
assert(ctx.arg.emachine == EM_AARCH64);
940+
gotRel = R_AARCH64_AUTH_GLOB_DAT;
941+
}
942+
ctx.mainPart->relaDyn->addReloc({gotRel, ctx.in.got.get(), off,
937943
DynamicReloc::AgainstSymbol, sym, 0,
938944
R_ABS});
939945
return;
940946
}
941947

942948
// Otherwise, the value is either a link-time constant or the load base
943-
// plus a constant.
949+
// plus a constant. Signed GOT requires dynamic relocation.
950+
if (sym.hasFlag(NEEDS_GOT_AUTH)) {
951+
ctx.in.got->getPartition(ctx).relaDyn->addReloc(
952+
{R_AARCH64_AUTH_RELATIVE, ctx.in.got.get(), off,
953+
DynamicReloc::AddendOnlyWithTargetVA, sym, 0, R_ABS});
954+
return;
955+
}
956+
944957
if (!ctx.arg.isPic || isAbsolute(sym))
945958
ctx.in.got->addConstant({R_ABS, ctx.target->symbolicRel, off, 0, &sym});
946959
else
@@ -994,10 +1007,11 @@ bool RelocationScanner::isStaticLinkTimeConstant(RelExpr e, RelType type,
9941007
// These expressions always compute a constant
9951008
if (oneof<R_GOTPLT, R_GOT_OFF, R_RELAX_HINT, R_MIPS_GOT_LOCAL_PAGE,
9961009
R_MIPS_GOTREL, R_MIPS_GOT_OFF, R_MIPS_GOT_OFF32, R_MIPS_GOT_GP_PC,
997-
R_AARCH64_GOT_PAGE_PC, R_GOT_PC, R_GOTONLY_PC, R_GOTPLTONLY_PC,
998-
R_PLT_PC, R_PLT_GOTREL, R_PLT_GOTPLT, R_GOTPLT_GOTREL, R_GOTPLT_PC,
999-
R_PPC32_PLTREL, R_PPC64_CALL_PLT, R_PPC64_RELAX_TOC, R_RISCV_ADD,
1000-
R_AARCH64_GOT_PAGE, R_LOONGARCH_PLT_PAGE_PC, R_LOONGARCH_GOT,
1010+
R_AARCH64_GOT_PAGE_PC, R_AARCH64_AUTH_GOT_PAGE_PC, R_GOT_PC,
1011+
R_GOTONLY_PC, R_GOTPLTONLY_PC, R_PLT_PC, R_PLT_GOTREL, R_PLT_GOTPLT,
1012+
R_GOTPLT_GOTREL, R_GOTPLT_PC, R_PPC32_PLTREL, R_PPC64_CALL_PLT,
1013+
R_PPC64_RELAX_TOC, R_RISCV_ADD, R_AARCH64_GOT_PAGE,
1014+
R_AARCH64_AUTH_GOT, R_LOONGARCH_PLT_PAGE_PC, R_LOONGARCH_GOT,
10011015
R_LOONGARCH_GOT_PAGE_PC>(e))
10021016
return true;
10031017

@@ -1111,7 +1125,19 @@ void RelocationScanner::processAux(RelExpr expr, RelType type, uint64_t offset,
11111125
} else if (!sym.isTls() || ctx.arg.emachine != EM_LOONGARCH) {
11121126
// Many LoongArch TLS relocs reuse the R_LOONGARCH_GOT type, in which
11131127
// case the NEEDS_GOT flag shouldn't get set.
1114-
sym.setFlags(NEEDS_GOT);
1128+
bool needsGotAuth =
1129+
(expr == R_AARCH64_AUTH_GOT || expr == R_AARCH64_AUTH_GOT_PAGE_PC);
1130+
uint16_t flags = sym.flags.load(std::memory_order_relaxed);
1131+
if (!(flags & NEEDS_GOT)) {
1132+
if (needsGotAuth)
1133+
sym.setFlags(NEEDS_GOT | NEEDS_GOT_AUTH);
1134+
else
1135+
sym.setFlags(NEEDS_GOT);
1136+
} else if (needsGotAuth != static_cast<bool>(flags & NEEDS_GOT_AUTH)) {
1137+
fatal("both AUTH and non-AUTH GOT entries for '" + sym.getName() +
1138+
"' requested, but only one type of GOT entry per symbol is "
1139+
"supported");
1140+
}
11151141
}
11161142
} else if (needsPlt(expr)) {
11171143
sym.setFlags(NEEDS_PLT);

lld/ELF/Relocations.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -86,7 +86,9 @@ enum RelExpr {
8686
// of a relocation type, there are some relocations whose semantics are
8787
// unique to a target. Such relocation are marked with R_<TARGET_NAME>.
8888
R_AARCH64_GOT_PAGE_PC,
89+
R_AARCH64_AUTH_GOT_PAGE_PC,
8990
R_AARCH64_GOT_PAGE,
91+
R_AARCH64_AUTH_GOT,
9092
R_AARCH64_PAGE_PC,
9193
R_AARCH64_RELAX_TLS_GD_TO_IE_PAGE_PC,
9294
R_AARCH64_TLSDESC_PAGE,

lld/ELF/Symbols.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,7 @@ enum {
5454
NEEDS_TLSGD_TO_IE = 1 << 6,
5555
NEEDS_GOT_DTPREL = 1 << 7,
5656
NEEDS_TLSIE = 1 << 8,
57+
NEEDS_GOT_AUTH = 1 << 9,
5758
};
5859

5960
// 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
@@ -664,6 +664,8 @@ void GotSection::addConstant(const Relocation &r) { relocations.push_back(r); }
664664
void GotSection::addEntry(const Symbol &sym) {
665665
assert(sym.auxIdx == ctx.symAux.size() - 1);
666666
ctx.symAux.back().gotIdx = numEntries++;
667+
if (sym.hasFlag(NEEDS_GOT_AUTH))
668+
authEntries.push_back({(numEntries - 1) * ctx.arg.wordsize, sym.isFunc()});
667669
}
668670

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

733750
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)