[lld] 417d2d7 - [PAC][lld][AArch64][ELF] Support signed GOT (#113815)
via llvm-commits
llvm-commits at lists.llvm.org
Mon Dec 16 23:23:05 PST 2024
Author: Daniil Kovalev
Date: 2024-12-17T10:23:01+03:00
New Revision: 417d2d7ce694acfa09a7d950cf1c5c41796eb313
URL: https://github.com/llvm/llvm-project/commit/417d2d7ce694acfa09a7d950cf1c5c41796eb313
DIFF: https://github.com/llvm/llvm-project/commit/417d2d7ce694acfa09a7d950cf1c5c41796eb313.diff
LOG: [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.
Added:
lld/test/ELF/aarch64-got-relocations-pauth.s
Modified:
lld/ELF/Arch/AArch64.cpp
lld/ELF/InputSection.cpp
lld/ELF/Relocations.cpp
lld/ELF/Relocations.h
lld/ELF/Symbols.h
lld/ELF/SyntheticSections.cpp
lld/ELF/SyntheticSections.h
Removed:
################################################################################
diff --git a/lld/ELF/Arch/AArch64.cpp b/lld/ELF/Arch/AArch64.cpp
index 99fc750486e4b4..9571e0e9566fc3 100644
--- a/lld/ELF/Arch/AArch64.cpp
+++ b/lld/ELF/Arch/AArch64.cpp
@@ -202,11 +202,16 @@ RelExpr AArch64::getRelExpr(RelType type, const Symbol &s,
case R_AARCH64_LD64_GOT_LO12_NC:
case R_AARCH64_TLSIE_LD64_GOTTPREL_LO12_NC:
return R_GOT;
+ case R_AARCH64_AUTH_LD64_GOT_LO12_NC:
+ case R_AARCH64_AUTH_GOT_ADD_LO12_NC:
+ return RE_AARCH64_AUTH_GOT;
case R_AARCH64_LD64_GOTPAGE_LO15:
return RE_AARCH64_GOT_PAGE;
case R_AARCH64_ADR_GOT_PAGE:
case R_AARCH64_TLSIE_ADR_GOTTPREL_PAGE21:
return RE_AARCH64_GOT_PAGE_PC;
+ case R_AARCH64_AUTH_ADR_GOT_PAGE:
+ return RE_AARCH64_AUTH_GOT_PAGE_PC;
case R_AARCH64_GOTPCREL32:
case R_AARCH64_GOT_LD_PREL19:
return R_GOT_PC;
@@ -258,6 +263,7 @@ int64_t AArch64::getImplicitAddend(const uint8_t *buf, RelType type) const {
return read64(ctx, buf + 8);
case R_AARCH64_NONE:
case R_AARCH64_GLOB_DAT:
+ case R_AARCH64_AUTH_GLOB_DAT:
case R_AARCH64_JUMP_SLOT:
return 0;
case R_AARCH64_ABS16:
@@ -528,9 +534,11 @@ void AArch64::relocate(uint8_t *loc, const Relocation &rel,
write32(ctx, loc, val);
break;
case R_AARCH64_ADD_ABS_LO12_NC:
+ case R_AARCH64_AUTH_GOT_ADD_LO12_NC:
write32Imm12(loc, val);
break;
case R_AARCH64_ADR_GOT_PAGE:
+ case R_AARCH64_AUTH_ADR_GOT_PAGE:
case R_AARCH64_ADR_PREL_PG_HI21:
case R_AARCH64_TLSIE_ADR_GOTTPREL_PAGE21:
case R_AARCH64_TLSDESC_ADR_PAGE21:
@@ -580,6 +588,7 @@ void AArch64::relocate(uint8_t *loc, const Relocation &rel,
break;
case R_AARCH64_LDST64_ABS_LO12_NC:
case R_AARCH64_LD64_GOT_LO12_NC:
+ case R_AARCH64_AUTH_LD64_GOT_LO12_NC:
case R_AARCH64_TLSIE_LD64_GOTTPREL_LO12_NC:
case R_AARCH64_TLSLE_LDST64_TPREL_LO12_NC:
case R_AARCH64_TLSDESC_LD64_LO12:
diff --git a/lld/ELF/InputSection.cpp b/lld/ELF/InputSection.cpp
index 7e76bae19fc6a2..26dc5c606f57f9 100644
--- a/lld/ELF/InputSection.cpp
+++ b/lld/ELF/InputSection.cpp
@@ -783,6 +783,7 @@ uint64_t InputSectionBase::getRelocTargetVA(Ctx &ctx, const Relocation &r,
case RE_ARM_SBREL:
return r.sym->getVA(ctx, a) - getARMStaticBase(*r.sym);
case R_GOT:
+ case RE_AARCH64_AUTH_GOT:
case R_RELAX_TLS_GD_TO_IE_ABS:
return r.sym->getGotVA(ctx) + a;
case RE_LOONGARCH_GOT:
@@ -810,6 +811,7 @@ uint64_t InputSectionBase::getRelocTargetVA(Ctx &ctx, const Relocation &r,
case R_RELAX_TLS_GD_TO_IE_GOT_OFF:
return r.sym->getGotOffset(ctx) + a;
case RE_AARCH64_GOT_PAGE_PC:
+ case RE_AARCH64_AUTH_GOT_PAGE_PC:
case RE_AARCH64_RELAX_TLS_GD_TO_IE_PAGE_PC:
return getAArch64Page(r.sym->getGotVA(ctx) + a) - getAArch64Page(p);
case RE_AARCH64_GOT_PAGE:
diff --git a/lld/ELF/Relocations.cpp b/lld/ELF/Relocations.cpp
index 41c04b29034563..07cbdb7806fde1 100644
--- a/lld/ELF/Relocations.cpp
+++ b/lld/ELF/Relocations.cpp
@@ -197,8 +197,9 @@ static bool needsPlt(RelExpr expr) {
}
bool lld::elf::needsGot(RelExpr expr) {
- return oneof<R_GOT, R_GOT_OFF, RE_MIPS_GOT_LOCAL_PAGE, RE_MIPS_GOT_OFF,
- RE_MIPS_GOT_OFF32, RE_AARCH64_GOT_PAGE_PC, R_GOT_PC, R_GOTPLT,
+ return oneof<R_GOT, RE_AARCH64_AUTH_GOT, R_GOT_OFF, RE_MIPS_GOT_LOCAL_PAGE,
+ RE_MIPS_GOT_OFF, RE_MIPS_GOT_OFF32, RE_AARCH64_GOT_PAGE_PC,
+ RE_AARCH64_AUTH_GOT_PAGE_PC, R_GOT_PC, R_GOTPLT,
RE_AARCH64_GOT_PAGE, RE_LOONGARCH_GOT, RE_LOONGARCH_GOT_PAGE_PC>(
expr);
}
@@ -910,6 +911,25 @@ void elf::addGotEntry(Ctx &ctx, Symbol &sym) {
ctx.target->symbolicRel);
}
+static void addGotAuthEntry(Ctx &ctx, Symbol &sym) {
+ ctx.in.got->addEntry(sym);
+ ctx.in.got->addAuthEntry(sym);
+ uint64_t off = sym.getGotOffset(ctx);
+
+ // If preemptible, emit a GLOB_DAT relocation.
+ if (sym.isPreemptible) {
+ ctx.mainPart->relaDyn->addReloc({R_AARCH64_AUTH_GLOB_DAT, ctx.in.got.get(),
+ off, DynamicReloc::AgainstSymbol, sym, 0,
+ R_ABS});
+ return;
+ }
+
+ // Signed GOT requires dynamic relocation.
+ ctx.in.got->getPartition(ctx).relaDyn->addReloc(
+ {R_AARCH64_AUTH_RELATIVE, ctx.in.got.get(), off,
+ DynamicReloc::AddendOnlyWithTargetVA, sym, 0, R_ABS});
+}
+
static void addTpOffsetGotEntry(Ctx &ctx, Symbol &sym) {
ctx.in.got->addEntry(sym);
uint64_t off = sym.getGotOffset(ctx);
@@ -956,11 +976,12 @@ bool RelocationScanner::isStaticLinkTimeConstant(RelExpr e, RelType type,
// These expressions always compute a constant
if (oneof<R_GOTPLT, R_GOT_OFF, R_RELAX_HINT, RE_MIPS_GOT_LOCAL_PAGE,
RE_MIPS_GOTREL, RE_MIPS_GOT_OFF, RE_MIPS_GOT_OFF32,
- RE_MIPS_GOT_GP_PC, RE_AARCH64_GOT_PAGE_PC, R_GOT_PC, R_GOTONLY_PC,
+ RE_MIPS_GOT_GP_PC, RE_AARCH64_GOT_PAGE_PC,
+ RE_AARCH64_AUTH_GOT_PAGE_PC, R_GOT_PC, R_GOTONLY_PC,
R_GOTPLTONLY_PC, R_PLT_PC, R_PLT_GOTREL, R_PLT_GOTPLT,
R_GOTPLT_GOTREL, R_GOTPLT_PC, RE_PPC32_PLTREL, RE_PPC64_CALL_PLT,
RE_PPC64_RELAX_TOC, RE_RISCV_ADD, RE_AARCH64_GOT_PAGE,
- RE_LOONGARCH_PLT_PAGE_PC, RE_LOONGARCH_GOT,
+ RE_AARCH64_AUTH_GOT, RE_LOONGARCH_PLT_PAGE_PC, RE_LOONGARCH_GOT,
RE_LOONGARCH_GOT_PAGE_PC>(e))
return true;
@@ -1075,7 +1096,10 @@ void RelocationScanner::processAux(RelExpr expr, RelType type, uint64_t offset,
} else if (!sym.isTls() || ctx.arg.emachine != EM_LOONGARCH) {
// Many LoongArch TLS relocs reuse the RE_LOONGARCH_GOT type, in which
// case the NEEDS_GOT flag shouldn't get set.
- sym.setFlags(NEEDS_GOT);
+ if (expr == RE_AARCH64_AUTH_GOT || expr == RE_AARCH64_AUTH_GOT_PAGE_PC)
+ sym.setFlags(NEEDS_GOT | NEEDS_GOT_AUTH);
+ else
+ sym.setFlags(NEEDS_GOT | NEEDS_GOT_NONAUTH);
}
} else if (needsPlt(expr)) {
sym.setFlags(NEEDS_PLT);
@@ -1750,8 +1774,11 @@ static bool handleNonPreemptibleIfunc(Ctx &ctx, Symbol &sym, uint16_t flags) {
// don't try to call the PLT as if it were an ifunc resolver.
d.type = STT_FUNC;
- if (flags & NEEDS_GOT)
+ if (flags & NEEDS_GOT) {
+ assert(!(flags & NEEDS_GOT_AUTH) &&
+ "R_AARCH64_AUTH_IRELATIVE is not supported yet");
addGotEntry(ctx, sym);
+ }
} else if (flags & NEEDS_GOT) {
// Redirect GOT accesses to point to the Igot.
sym.gotInIgot = true;
@@ -1772,8 +1799,19 @@ void elf::postScanRelocations(Ctx &ctx) {
return;
sym.allocateAux(ctx);
- if (flags & NEEDS_GOT)
- addGotEntry(ctx, sym);
+ if (flags & NEEDS_GOT) {
+ if ((flags & NEEDS_GOT_AUTH) && (flags & NEEDS_GOT_NONAUTH)) {
+ auto diag = Err(ctx);
+ diag << "both AUTH and non-AUTH GOT entries for '" << sym.getName()
+ << "' requested, but only one type of GOT entry per symbol is "
+ "supported";
+ return;
+ }
+ if (flags & NEEDS_GOT_AUTH)
+ addGotAuthEntry(ctx, sym);
+ else
+ addGotEntry(ctx, sym);
+ }
if (flags & NEEDS_PLT)
addPltEntry(ctx, *ctx.in.plt, *ctx.in.gotPlt, *ctx.in.relaPlt,
ctx.target->pltRel, sym);
diff --git a/lld/ELF/Relocations.h b/lld/ELF/Relocations.h
index 7ca203257ea876..d993ab77adc3cc 100644
--- a/lld/ELF/Relocations.h
+++ b/lld/ELF/Relocations.h
@@ -92,7 +92,9 @@ enum RelExpr {
// of a relocation type, there are some relocations whose semantics are
// unique to a target. Such relocation are marked with RE_<TARGET_NAME>.
RE_AARCH64_GOT_PAGE_PC,
+ RE_AARCH64_AUTH_GOT_PAGE_PC,
RE_AARCH64_GOT_PAGE,
+ RE_AARCH64_AUTH_GOT,
RE_AARCH64_PAGE_PC,
RE_AARCH64_RELAX_TLS_GD_TO_IE_PAGE_PC,
RE_AARCH64_TLSDESC_PAGE,
diff --git a/lld/ELF/Symbols.h b/lld/ELF/Symbols.h
index fac957a7248856..a59faf1037cb2f 100644
--- a/lld/ELF/Symbols.h
+++ b/lld/ELF/Symbols.h
@@ -51,6 +51,8 @@ enum {
NEEDS_TLSGD_TO_IE = 1 << 6,
NEEDS_GOT_DTPREL = 1 << 7,
NEEDS_TLSIE = 1 << 8,
+ NEEDS_GOT_AUTH = 1 << 9,
+ NEEDS_GOT_NONAUTH = 1 << 10,
};
// The base class for real symbol classes.
diff --git a/lld/ELF/SyntheticSections.cpp b/lld/ELF/SyntheticSections.cpp
index c8a05e4b9c3cc6..baa7a083404fe7 100644
--- a/lld/ELF/SyntheticSections.cpp
+++ b/lld/ELF/SyntheticSections.cpp
@@ -670,6 +670,10 @@ void GotSection::addEntry(const Symbol &sym) {
ctx.symAux.back().gotIdx = numEntries++;
}
+void GotSection::addAuthEntry(const Symbol &sym) {
+ authEntries.push_back({(numEntries - 1) * ctx.arg.wordsize, sym.isFunc()});
+}
+
bool GotSection::addTlsDescEntry(const Symbol &sym) {
assert(sym.auxIdx == ctx.symAux.size() - 1);
ctx.symAux.back().tlsDescIdx = numEntries;
@@ -732,6 +736,21 @@ void GotSection::writeTo(uint8_t *buf) {
return;
ctx.target->writeGotHeader(buf);
ctx.target->relocateAlloc(*this, buf);
+ for (const AuthEntryInfo &authEntry : authEntries) {
+ // https://github.com/ARM-software/abi-aa/blob/2024Q3/pauthabielf64/pauthabielf64.rst#default-signing-schema
+ // Signed GOT entries use the IA key for symbols of type STT_FUNC and the
+ // DA key for all other symbol types, with the address of the GOT entry as
+ // the modifier. The static linker must encode the signing schema into the
+ // GOT slot.
+ //
+ // https://github.com/ARM-software/abi-aa/blob/2024Q3/pauthabielf64/pauthabielf64.rst#encoding-the-signing-schema
+ // If address diversity is set and the discriminator
+ // is 0 then modifier = Place
+ uint8_t *dest = buf + authEntry.offset;
+ uint64_t key = authEntry.isSymbolFunc ? /*IA=*/0b00 : /*DA=*/0b10;
+ uint64_t addrDiversity = 1;
+ write64(ctx, dest, (addrDiversity << 63) | (key << 60));
+ }
}
static uint64_t getMipsPageAddr(uint64_t addr) {
diff --git a/lld/ELF/SyntheticSections.h b/lld/ELF/SyntheticSections.h
index 132513cbd3b796..9fcee3b481af08 100644
--- a/lld/ELF/SyntheticSections.h
+++ b/lld/ELF/SyntheticSections.h
@@ -112,6 +112,7 @@ class GotSection final : public SyntheticSection {
void addConstant(const Relocation &r);
void addEntry(const Symbol &sym);
+ void addAuthEntry(const Symbol &sym);
bool addTlsDescEntry(const Symbol &sym);
bool addDynTlsEntry(const Symbol &sym);
bool addTlsIndex();
@@ -131,6 +132,11 @@ class GotSection final : public SyntheticSection {
size_t numEntries = 0;
uint32_t tlsIndexOff = -1;
uint64_t size = 0;
+ struct AuthEntryInfo {
+ size_t offset;
+ bool isSymbolFunc;
+ };
+ SmallVector<AuthEntryInfo, 0> authEntries;
};
// .note.GNU-stack section.
diff --git a/lld/test/ELF/aarch64-got-relocations-pauth.s b/lld/test/ELF/aarch64-got-relocations-pauth.s
new file mode 100644
index 00000000000000..4456fe3ad7714b
--- /dev/null
+++ b/lld/test/ELF/aarch64-got-relocations-pauth.s
@@ -0,0 +1,90 @@
+# REQUIRES: aarch64
+
+# RUN: rm -rf %t && split-file %s %t && cd %t
+
+# RUN: llvm-mc -filetype=obj -triple=aarch64 %p/Inputs/shared.s -o a.o
+# RUN: ld.lld -shared a.o -o a.so
+
+#--- ok.s
+# RUN: llvm-mc -filetype=obj -triple=aarch64 ok.s -o ok.o
+
+# RUN: ld.lld ok.o a.so -pie -o ok1
+# RUN: llvm-readelf -r -S -x .got ok1 | FileCheck %s --check-prefix=OK1
+
+# RUN: ld.lld ok.o a.o -pie -o ok2
+# RUN: llvm-readelf -r -S -x .got -s ok2 | FileCheck %s --check-prefix=OK2
+
+# OK1: Offset Info Type Symbol's Value Symbol's Name + Addend
+# OK1-NEXT: 0000000000020380 0000000100000412 R_AARCH64_AUTH_GLOB_DAT 0000000000000000 bar + 0
+# OK1-NEXT: 0000000000020388 0000000200000412 R_AARCH64_AUTH_GLOB_DAT 0000000000000000 zed + 0
+
+## Symbol's values for bar and zed are equal since they contain no content (see Inputs/shared.s)
+# OK2: Offset Info Type Symbol's Value Symbol's Name + Addend
+# OK2-NEXT: 0000000000020320 0000000000000411 R_AARCH64_AUTH_RELATIVE 10260
+# OK2-NEXT: 0000000000020328 0000000000000411 R_AARCH64_AUTH_RELATIVE 10260
+
+# OK1: Hex dump of section '.got':
+# OK1-NEXT: 0x00020380 00000000 00000080 00000000 000000a0
+## ^^
+## 0b10000000 bit 63 address diversity = true, bits 61..60 key = IA
+## ^^
+## 0b10100000 bit 63 address diversity = true, bits 61..60 key = DA
+
+# OK2: Symbol table '.symtab' contains {{.*}} entries:
+# OK2: Num: Value Size Type Bind Vis Ndx Name
+# OK2: 0000000000010260 0 FUNC GLOBAL DEFAULT 6 bar
+# OK2: 0000000000010260 0 NOTYPE GLOBAL DEFAULT 6 zed
+
+# OK2: Hex dump of section '.got':
+# OK2-NEXT: 0x00020320 00000000 00000080 00000000 000000a0
+## ^^
+## 0b10000000 bit 63 address diversity = true, bits 61..60 key = IA
+## ^^
+## 0b10100000 bit 63 address diversity = true, bits 61..60 key = DA
+
+# RUN: llvm-objdump -d ok1 | FileCheck %s --check-prefix=OK1-ASM
+
+# OK1-ASM: <_start>:
+# OK1-ASM-NEXT: adrp x0, 0x20000
+# OK1-ASM-NEXT: ldr x0, [x0, #0x380]
+# OK1-ASM-NEXT: adrp x1, 0x20000
+# OK1-ASM-NEXT: add x1, x1, #0x380
+# OK1-ASM-NEXT: adrp x0, 0x20000
+# OK1-ASM-NEXT: ldr x0, [x0, #0x388]
+# OK1-ASM-NEXT: adrp x1, 0x20000
+# OK1-ASM-NEXT: add x1, x1, #0x388
+
+# RUN: llvm-objdump -d ok2 | FileCheck %s --check-prefix=OK2-ASM
+
+# OK2-ASM: <_start>:
+# OK2-ASM-NEXT: adrp x0, 0x20000
+# OK2-ASM-NEXT: ldr x0, [x0, #0x320]
+# OK2-ASM-NEXT: adrp x1, 0x20000
+# OK2-ASM-NEXT: add x1, x1, #0x320
+# OK2-ASM-NEXT: adrp x0, 0x20000
+# OK2-ASM-NEXT: ldr x0, [x0, #0x328]
+# OK2-ASM-NEXT: adrp x1, 0x20000
+# OK2-ASM-NEXT: add x1, x1, #0x328
+
+.globl _start
+_start:
+ adrp x0, :got_auth:bar
+ ldr x0, [x0, :got_auth_lo12:bar]
+ adrp x1, :got_auth:bar
+ add x1, x1, :got_auth_lo12:bar
+ adrp x0, :got_auth:zed
+ ldr x0, [x0, :got_auth_lo12:zed]
+ adrp x1, :got_auth:zed
+ add x1, x1, :got_auth_lo12:zed
+
+#--- err.s
+# RUN: llvm-mc -filetype=obj -triple=aarch64 err.s -o err.o
+# RUN: not ld.lld err.o a.so -pie 2>&1 | FileCheck %s --check-prefix=ERR --implicit-check-not=error:
+# ERR: error: both AUTH and non-AUTH GOT entries for 'bar' requested, but only one type of GOT entry per symbol is supported
+
+.globl _start
+_start:
+ adrp x0, :got_auth:bar
+ ldr x0, [x0, :got_auth_lo12:bar]
+ adrp x0, :got:bar
+ ldr x0, [x0, :got_lo12:bar]
More information about the llvm-commits
mailing list