[lld] [PAC][lld][AArch64][ELF] Support signed GOT (PR #113815)
via llvm-commits
llvm-commits at lists.llvm.org
Sun Oct 27 08:20:29 PDT 2024
llvmbot wrote:
<!--LLVM PR SUMMARY COMMENT-->
@llvm/pr-subscribers-lld
Author: Daniil Kovalev (kovdan01)
<details>
<summary>Changes</summary>
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.
---
Full diff: https://github.com/llvm/llvm-project/pull/113815.diff
8 Files Affected:
- (modified) lld/ELF/Arch/AArch64.cpp (+9)
- (modified) lld/ELF/InputSection.cpp (+2)
- (modified) lld/ELF/Relocations.cpp (+35-9)
- (modified) lld/ELF/Relocations.h (+2)
- (modified) lld/ELF/Symbols.h (+1)
- (modified) lld/ELF/SyntheticSections.cpp (+17)
- (modified) lld/ELF/SyntheticSections.h (+5)
- (added) lld/test/ELF/aarch64-got-relocations-pauth.s (+94)
``````````diff
diff --git a/lld/ELF/Arch/AArch64.cpp b/lld/ELF/Arch/AArch64.cpp
index 28e0fce6a6f499..86f509f3fd78a7 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 R_AARCH64_AUTH_GOT;
case R_AARCH64_LD64_GOTPAGE_LO15:
return R_AARCH64_GOT_PAGE;
case R_AARCH64_ADR_GOT_PAGE:
case R_AARCH64_TLSIE_ADR_GOTTPREL_PAGE21:
return R_AARCH64_GOT_PAGE_PC;
+ case R_AARCH64_AUTH_ADR_GOT_PAGE:
+ return R_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:
@@ -529,9 +535,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:
@@ -581,6 +589,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 3b48fbe07bb082..ccc7cf8c6e2de9 100644
--- a/lld/ELF/InputSection.cpp
+++ b/lld/ELF/InputSection.cpp
@@ -754,6 +754,7 @@ uint64_t InputSectionBase::getRelocTargetVA(Ctx &ctx, const Relocation &r,
case R_ARM_SBREL:
return r.sym->getVA(ctx, a) - getARMStaticBase(*r.sym);
case R_GOT:
+ case R_AARCH64_AUTH_GOT:
case R_RELAX_TLS_GD_TO_IE_ABS:
return r.sym->getGotVA(ctx) + a;
case R_LOONGARCH_GOT:
@@ -781,6 +782,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 R_AARCH64_GOT_PAGE_PC:
+ case R_AARCH64_AUTH_GOT_PAGE_PC:
case R_AARCH64_RELAX_TLS_GD_TO_IE_PAGE_PC:
return getAArch64Page(r.sym->getGotVA(ctx) + a) - getAArch64Page(p);
case R_AARCH64_GOT_PAGE:
diff --git a/lld/ELF/Relocations.cpp b/lld/ELF/Relocations.cpp
index d40348a7b30d8f..2d3815e58b5f67 100644
--- a/lld/ELF/Relocations.cpp
+++ b/lld/ELF/Relocations.cpp
@@ -210,8 +210,9 @@ static bool needsPlt(RelExpr expr) {
}
bool lld::elf::needsGot(RelExpr expr) {
- return oneof<R_GOT, R_GOT_OFF, R_MIPS_GOT_LOCAL_PAGE, R_MIPS_GOT_OFF,
- R_MIPS_GOT_OFF32, R_AARCH64_GOT_PAGE_PC, R_GOT_PC, R_GOTPLT,
+ return oneof<R_GOT, R_AARCH64_AUTH_GOT, R_GOT_OFF, R_MIPS_GOT_LOCAL_PAGE,
+ R_MIPS_GOT_OFF, R_MIPS_GOT_OFF32, R_AARCH64_GOT_PAGE_PC,
+ R_AARCH64_AUTH_GOT_PAGE_PC, R_GOT_PC, R_GOTPLT,
R_AARCH64_GOT_PAGE, R_LOONGARCH_GOT, R_LOONGARCH_GOT_PAGE_PC>(
expr);
}
@@ -933,14 +934,26 @@ void elf::addGotEntry(Ctx &ctx, Symbol &sym) {
// If preemptible, emit a GLOB_DAT relocation.
if (sym.isPreemptible) {
- ctx.mainPart->relaDyn->addReloc({ctx.target->gotRel, ctx.in.got.get(), off,
+ RelType gotRel = ctx.target->gotRel;
+ if (sym.hasFlag(NEEDS_GOT_AUTH)) {
+ assert(ctx.arg.emachine == EM_AARCH64);
+ gotRel = R_AARCH64_AUTH_GLOB_DAT;
+ }
+ ctx.mainPart->relaDyn->addReloc({gotRel, ctx.in.got.get(), off,
DynamicReloc::AgainstSymbol, sym, 0,
R_ABS});
return;
}
// Otherwise, the value is either a link-time constant or the load base
- // plus a constant.
+ // plus a constant. Signed GOT requires dynamic relocation.
+ if (sym.hasFlag(NEEDS_GOT_AUTH)) {
+ ctx.in.got->getPartition(ctx).relaDyn->addReloc(
+ {R_AARCH64_AUTH_RELATIVE, ctx.in.got.get(), off,
+ DynamicReloc::AddendOnlyWithTargetVA, sym, 0, R_ABS});
+ return;
+ }
+
if (!ctx.arg.isPic || isAbsolute(sym))
ctx.in.got->addConstant({R_ABS, ctx.target->symbolicRel, off, 0, &sym});
else
@@ -994,10 +1007,11 @@ bool RelocationScanner::isStaticLinkTimeConstant(RelExpr e, RelType type,
// These expressions always compute a constant
if (oneof<R_GOTPLT, R_GOT_OFF, R_RELAX_HINT, R_MIPS_GOT_LOCAL_PAGE,
R_MIPS_GOTREL, R_MIPS_GOT_OFF, R_MIPS_GOT_OFF32, R_MIPS_GOT_GP_PC,
- R_AARCH64_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,
- R_PPC32_PLTREL, R_PPC64_CALL_PLT, R_PPC64_RELAX_TOC, R_RISCV_ADD,
- R_AARCH64_GOT_PAGE, R_LOONGARCH_PLT_PAGE_PC, R_LOONGARCH_GOT,
+ R_AARCH64_GOT_PAGE_PC, R_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, R_PPC32_PLTREL, R_PPC64_CALL_PLT,
+ R_PPC64_RELAX_TOC, R_RISCV_ADD, R_AARCH64_GOT_PAGE,
+ R_AARCH64_AUTH_GOT, R_LOONGARCH_PLT_PAGE_PC, R_LOONGARCH_GOT,
R_LOONGARCH_GOT_PAGE_PC>(e))
return true;
@@ -1111,7 +1125,19 @@ 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 R_LOONGARCH_GOT type, in which
// case the NEEDS_GOT flag shouldn't get set.
- sym.setFlags(NEEDS_GOT);
+ bool needsGotAuth =
+ (expr == R_AARCH64_AUTH_GOT || expr == R_AARCH64_AUTH_GOT_PAGE_PC);
+ uint16_t flags = sym.flags.load(std::memory_order_relaxed);
+ if (!(flags & NEEDS_GOT)) {
+ if (needsGotAuth)
+ sym.setFlags(NEEDS_GOT | NEEDS_GOT_AUTH);
+ else
+ sym.setFlags(NEEDS_GOT);
+ } else if (needsGotAuth != static_cast<bool>(flags & NEEDS_GOT_AUTH)) {
+ fatal("both AUTH and non-AUTH GOT entries for '" + sym.getName() +
+ "' requested, but only one type of GOT entry per symbol is "
+ "supported");
+ }
}
} else if (needsPlt(expr)) {
sym.setFlags(NEEDS_PLT);
diff --git a/lld/ELF/Relocations.h b/lld/ELF/Relocations.h
index 64e67c2c968207..20d88de402ac18 100644
--- a/lld/ELF/Relocations.h
+++ b/lld/ELF/Relocations.h
@@ -86,7 +86,9 @@ enum RelExpr {
// of a relocation type, there are some relocations whose semantics are
// unique to a target. Such relocation are marked with R_<TARGET_NAME>.
R_AARCH64_GOT_PAGE_PC,
+ R_AARCH64_AUTH_GOT_PAGE_PC,
R_AARCH64_GOT_PAGE,
+ R_AARCH64_AUTH_GOT,
R_AARCH64_PAGE_PC,
R_AARCH64_RELAX_TLS_GD_TO_IE_PAGE_PC,
R_AARCH64_TLSDESC_PAGE,
diff --git a/lld/ELF/Symbols.h b/lld/ELF/Symbols.h
index 339f32e05f1625..470bae23832d7d 100644
--- a/lld/ELF/Symbols.h
+++ b/lld/ELF/Symbols.h
@@ -54,6 +54,7 @@ enum {
NEEDS_TLSGD_TO_IE = 1 << 6,
NEEDS_GOT_DTPREL = 1 << 7,
NEEDS_TLSIE = 1 << 8,
+ NEEDS_GOT_AUTH = 1 << 9,
};
// The base class for real symbol classes.
diff --git a/lld/ELF/SyntheticSections.cpp b/lld/ELF/SyntheticSections.cpp
index 7a344635a1cb53..0cf45e51bc58a8 100644
--- a/lld/ELF/SyntheticSections.cpp
+++ b/lld/ELF/SyntheticSections.cpp
@@ -664,6 +664,8 @@ void GotSection::addConstant(const Relocation &r) { relocations.push_back(r); }
void GotSection::addEntry(const Symbol &sym) {
assert(sym.auxIdx == ctx.symAux.size() - 1);
ctx.symAux.back().gotIdx = numEntries++;
+ if (sym.hasFlag(NEEDS_GOT_AUTH))
+ authEntries.push_back({(numEntries - 1) * ctx.arg.wordsize, sym.isFunc()});
}
bool GotSection::addTlsDescEntry(const Symbol &sym) {
@@ -728,6 +730,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/main/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/main/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 3573767671feb1..79af4e3971df51 100644
--- a/lld/ELF/SyntheticSections.h
+++ b/lld/ELF/SyntheticSections.h
@@ -131,6 +131,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..f04e3d953388ce
--- /dev/null
+++ b/lld/test/ELF/aarch64-got-relocations-pauth.s
@@ -0,0 +1,94 @@
+# REQUIRES: aarch64
+
+# RUN: rm -rf %t && split-file %s %t && cd %t
+
+# RUN: llvm-mc -filetype=obj -triple=aarch64-none-linux %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-none-linux ok.s -o ok.o
+
+# RUN: ld.lld ok.o a.so -pie -o external
+# RUN: llvm-readelf -r -S -x .got external | FileCheck %s --check-prefix=EXTERNAL
+
+# RUN: ld.lld ok.o a.o -pie -o local
+# RUN: llvm-readelf -r -S -x .got -s local | FileCheck %s --check-prefix=LOCAL
+
+# EXTERNAL: Offset Info Type Symbol's Value Symbol's Name + Addend
+# EXTERNAL-NEXT: 0000000000020380 000000010000e201 R_AARCH64_AUTH_GLOB_DAT 0000000000000000 bar + 0
+# EXTERNAL-NEXT: 0000000000020388 000000020000e201 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)
+# LOCAL: Offset Info Type Symbol's Value Symbol's Name + Addend
+# LOCAL-NEXT: 0000000000020320 0000000000000411 R_AARCH64_AUTH_RELATIVE 10260
+# LOCAL-NEXT: 0000000000020328 0000000000000411 R_AARCH64_AUTH_RELATIVE 10260
+
+# EXTERNAL: Hex dump of section '.got':
+# EXTERNAL-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
+
+# LOCAL: Symbol table '.symtab' contains {{.*}} entries:
+# LOCAL: Num: Value Size Type Bind Vis Ndx Name
+# LOCAL: 0000000000010260 0 FUNC GLOBAL DEFAULT 6 bar
+# LOCAL: 0000000000010260 0 NOTYPE GLOBAL DEFAULT 6 zed
+
+# LOCAL: Hex dump of section '.got':
+# LOCAL-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 external | FileCheck %s --check-prefix=EXTERNAL-ASM
+
+# EXTERNAL-ASM: <_start>:
+# EXTERNAL-ASM-NEXT: adrp x0, 0x20000
+# EXTERNAL-ASM-NEXT: ldr x0, [x0, #0x380]
+# EXTERNAL-ASM-NEXT: adrp x1, 0x20000
+# EXTERNAL-ASM-NEXT: add x1, x1, #0x380
+# EXTERNAL-ASM-NEXT: adrp x0, 0x20000
+# EXTERNAL-ASM-NEXT: ldr x0, [x0, #0x388]
+# EXTERNAL-ASM-NEXT: adrp x1, 0x20000
+# EXTERNAL-ASM-NEXT: add x1, x1, #0x388
+
+# RUN: llvm-objdump -d local | FileCheck %s --check-prefix=LOCAL-ASM
+
+# LOCAL-ASM: <_start>:
+# LOCAL-ASM-NEXT: adrp x0, 0x20000
+# LOCAL-ASM-NEXT: ldr x0, [x0, #0x320]
+# LOCAL-ASM-NEXT: adrp x1, 0x20000
+# LOCAL-ASM-NEXT: add x1, x1, #0x320
+# LOCAL-ASM-NEXT: adrp x0, 0x20000
+# LOCAL-ASM-NEXT: ldr x0, [x0, #0x328]
+# LOCAL-ASM-NEXT: adrp x1, 0x20000
+# LOCAL-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-none-linux err.s -o err.o
+
+# RUN: not ld.lld err.o a.so -pie -o /dev/null 2>&1 | FileCheck %s --check-prefix=ERR
+
+# 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]
``````````
</details>
https://github.com/llvm/llvm-project/pull/113815
More information about the llvm-commits
mailing list