Skip to content

[PAC][lld][AArch64][ELF] Support signed TLSDESC #113817

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 13 commits into from
Jan 22, 2025
Merged
8 changes: 8 additions & 0 deletions lld/ELF/Arch/AArch64.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -157,9 +157,14 @@ RelExpr AArch64::getRelExpr(RelType type, const Symbol &s,
return RE_AARCH64_AUTH;
case R_AARCH64_TLSDESC_ADR_PAGE21:
return RE_AARCH64_TLSDESC_PAGE;
case R_AARCH64_AUTH_TLSDESC_ADR_PAGE21:
return RE_AARCH64_AUTH_TLSDESC_PAGE;
case R_AARCH64_TLSDESC_LD64_LO12:
case R_AARCH64_TLSDESC_ADD_LO12:
return R_TLSDESC;
case R_AARCH64_AUTH_TLSDESC_LD64_LO12:
case R_AARCH64_AUTH_TLSDESC_ADD_LO12:
return RE_AARCH64_AUTH_TLSDESC;
case R_AARCH64_TLSDESC_CALL:
return R_TLSDESC_CALL;
case R_AARCH64_TLSLE_ADD_TPREL_HI12:
Expand Down Expand Up @@ -545,6 +550,7 @@ void AArch64::relocate(uint8_t *loc, const Relocation &rel,
case R_AARCH64_ADR_PREL_PG_HI21:
case R_AARCH64_TLSIE_ADR_GOTTPREL_PAGE21:
case R_AARCH64_TLSDESC_ADR_PAGE21:
case R_AARCH64_AUTH_TLSDESC_ADR_PAGE21:
checkInt(ctx, loc, val, 33, rel);
[[fallthrough]];
case R_AARCH64_ADR_PREL_PG_HI21_NC:
Expand Down Expand Up @@ -597,6 +603,7 @@ void AArch64::relocate(uint8_t *loc, const Relocation &rel,
case R_AARCH64_TLSIE_LD64_GOTTPREL_LO12_NC:
case R_AARCH64_TLSLE_LDST64_TPREL_LO12_NC:
case R_AARCH64_TLSDESC_LD64_LO12:
case R_AARCH64_AUTH_TLSDESC_LD64_LO12:
checkAlignment(ctx, loc, val, 8, rel);
write32Imm12(loc, getBits(val, 3, 11));
break;
Expand Down Expand Up @@ -671,6 +678,7 @@ void AArch64::relocate(uint8_t *loc, const Relocation &rel,
break;
case R_AARCH64_TLSLE_ADD_TPREL_LO12_NC:
case R_AARCH64_TLSDESC_ADD_LO12:
case R_AARCH64_AUTH_TLSDESC_ADD_LO12:
write32Imm12(loc, val);
break;
case R_AARCH64_TLSDESC:
Expand Down
2 changes: 2 additions & 0 deletions lld/ELF/InputSection.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -966,12 +966,14 @@ uint64_t InputSectionBase::getRelocTargetVA(Ctx &ctx, const Relocation &r,
case R_SIZE:
return r.sym->getSize() + a;
case R_TLSDESC:
case RE_AARCH64_AUTH_TLSDESC:
return ctx.in.got->getTlsDescAddr(*r.sym) + a;
case R_TLSDESC_PC:
return ctx.in.got->getTlsDescAddr(*r.sym) + a - p;
case R_TLSDESC_GOTPLT:
return ctx.in.got->getTlsDescAddr(*r.sym) + a - ctx.in.gotPlt->getVA();
case RE_AARCH64_TLSDESC_PAGE:
case RE_AARCH64_AUTH_TLSDESC_PAGE:
return getAArch64Page(ctx.in.got->getTlsDescAddr(*r.sym) + a) -
getAArch64Page(p);
case RE_LOONGARCH_TLSDESC_PAGE_PC:
Expand Down
47 changes: 44 additions & 3 deletions lld/ELF/Relocations.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1292,6 +1292,27 @@ static unsigned handleMipsTlsRelocation(Ctx &ctx, RelType type, Symbol &sym,
return 0;
}

static unsigned handleAArch64PAuthTlsRelocation(InputSectionBase *sec,
RelExpr expr, RelType type,
uint64_t offset, Symbol &sym,
int64_t addend) {
// Do not optimize signed TLSDESC to LE/IE (as described in pauthabielf64).
// https://github.com/ARM-software/abi-aa/blob/main/pauthabielf64/pauthabielf64.rst#general-restrictions
// > PAUTHELF64 only supports the descriptor based TLS (TLSDESC).
if (oneof<RE_AARCH64_AUTH_TLSDESC_PAGE, RE_AARCH64_AUTH_TLSDESC>(expr)) {
sym.setFlags(NEEDS_TLSDESC | NEEDS_TLSDESC_AUTH);
sec->addReloc({expr, type, offset, addend, &sym});
return 1;
}

// TLSDESC_CALL hint relocation should not be emitted by compiler with signed
// TLSDESC enabled.
if (expr == R_TLSDESC_CALL)
sym.setFlags(NEEDS_TLSDESC_NONAUTH);

return 0;
}

// Notes about General Dynamic and Local Dynamic TLS models below. They may
// require the generation of a pair of GOT entries that have associated dynamic
// relocations. The pair of GOT entries created are of the form GOT[e0] Module
Expand All @@ -1302,6 +1323,13 @@ static unsigned handleMipsTlsRelocation(Ctx &ctx, RelType type, Symbol &sym,
unsigned RelocationScanner::handleTlsRelocation(RelExpr expr, RelType type,
uint64_t offset, Symbol &sym,
int64_t addend) {
bool isAArch64 = ctx.arg.emachine == EM_AARCH64;

if (isAArch64)
if (unsigned processed = handleAArch64PAuthTlsRelocation(
sec, expr, type, offset, sym, addend))
return processed;

if (expr == R_TPREL || expr == R_TPREL_NEG) {
if (ctx.arg.shared) {
auto diag = Err(ctx);
Expand Down Expand Up @@ -1336,7 +1364,9 @@ unsigned RelocationScanner::handleTlsRelocation(RelExpr expr, RelType type,
// R_RISCV_TLSDESC_{LOAD_LO12,ADD_LO12_I,CALL} reference a label. Do not
// set NEEDS_TLSDESC on the label.
if (expr != R_TLSDESC_CALL) {
if (!isRISCV || type == R_RISCV_TLSDESC_HI20)
if (isAArch64)
sym.setFlags(NEEDS_TLSDESC | NEEDS_TLSDESC_NONAUTH);
else if (!isRISCV || type == R_RISCV_TLSDESC_HI20)
sym.setFlags(NEEDS_TLSDESC);
sec->addReloc({expr, type, offset, addend, &sym});
}
Expand Down Expand Up @@ -1847,10 +1877,21 @@ void elf::postScanRelocations(Ctx &ctx) {
GotSection *got = ctx.in.got.get();

if (flags & NEEDS_TLSDESC) {
if ((flags & NEEDS_TLSDESC_AUTH) && (flags & NEEDS_TLSDESC_NONAUTH)) {
Err(ctx)
<< "both AUTH and non-AUTH TLSDESC entries for '" << sym.getName()
<< "' requested, but only one type of TLSDESC entry per symbol is "
"supported";
return;
}
got->addTlsDescEntry(sym);
RelType tlsDescRel = ctx.target->tlsDescRel;
if (flags & NEEDS_TLSDESC_AUTH) {
got->addTlsDescAuthEntry();
tlsDescRel = ELF::R_AARCH64_AUTH_TLSDESC;
}
ctx.mainPart->relaDyn->addAddendOnlyRelocIfNonPreemptible(
ctx.target->tlsDescRel, *got, got->getTlsDescOffset(sym), sym,
ctx.target->tlsDescRel);
tlsDescRel, *got, got->getTlsDescOffset(sym), sym, tlsDescRel);
}
if (flags & NEEDS_TLSGD) {
got->addDynTlsEntry(sym);
Expand Down
2 changes: 2 additions & 0 deletions lld/ELF/Relocations.h
Original file line number Diff line number Diff line change
Expand Up @@ -99,6 +99,8 @@ enum RelExpr {
RE_AARCH64_PAGE_PC,
RE_AARCH64_RELAX_TLS_GD_TO_IE_PAGE_PC,
RE_AARCH64_TLSDESC_PAGE,
RE_AARCH64_AUTH_TLSDESC_PAGE,
RE_AARCH64_AUTH_TLSDESC,
RE_AARCH64_AUTH,
RE_ARM_PCA,
RE_ARM_SBREL,
Expand Down
2 changes: 2 additions & 0 deletions lld/ELF/Symbols.h
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,8 @@ enum {
NEEDS_TLSIE = 1 << 8,
NEEDS_GOT_AUTH = 1 << 9,
NEEDS_GOT_NONAUTH = 1 << 10,
NEEDS_TLSDESC_AUTH = 1 << 11,
NEEDS_TLSDESC_NONAUTH = 1 << 12,
};

// The base class for real symbol classes.
Expand Down
5 changes: 5 additions & 0 deletions lld/ELF/SyntheticSections.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -681,6 +681,11 @@ bool GotSection::addTlsDescEntry(const Symbol &sym) {
return true;
}

void GotSection::addTlsDescAuthEntry() {
authEntries.push_back({(numEntries - 2) * ctx.arg.wordsize, true});
authEntries.push_back({(numEntries - 1) * ctx.arg.wordsize, false});
}

bool GotSection::addDynTlsEntry(const Symbol &sym) {
assert(sym.auxIdx == ctx.symAux.size() - 1);
ctx.symAux.back().tlsGdIdx = numEntries;
Expand Down
1 change: 1 addition & 0 deletions lld/ELF/SyntheticSections.h
Original file line number Diff line number Diff line change
Expand Up @@ -114,6 +114,7 @@ class GotSection final : public SyntheticSection {
void addEntry(const Symbol &sym);
void addAuthEntry(const Symbol &sym);
bool addTlsDescEntry(const Symbol &sym);
void addTlsDescAuthEntry();
bool addDynTlsEntry(const Symbol &sym);
bool addTlsIndex();
uint32_t getTlsDescOffset(const Symbol &sym) const;
Expand Down
134 changes: 134 additions & 0 deletions lld/test/ELF/aarch64-tlsdesc-pauth.s
Original file line number Diff line number Diff line change
@@ -0,0 +1,134 @@
// REQUIRES: aarch64
// RUN: rm -rf %t && split-file %s %t && cd %t

//--- a.s
.section .tbss,"awT",@nobits
.global a
a:
.xword 0

//--- ok.s
// RUN: llvm-mc -filetype=obj -triple=aarch64-pc-linux -mattr=+pauth ok.s -o ok.o
// RUN: ld.lld -shared ok.o -o ok.so
// RUN: llvm-objdump --no-print-imm-hex -d --no-show-raw-insn ok.so | \
// RUN: FileCheck -DP=20 -DA=896 -DB=912 -DC=928 %s
// RUN: llvm-readobj -r -x .got ok.so | FileCheck --check-prefix=REL \
// RUN: -DP1=20 -DA1=380 -DB1=390 -DC1=3A0 -DP2=020 -DA2=380 -DB2=390 -DC2=3a0 %s

// RUN: llvm-mc -filetype=obj -triple=aarch64-pc-linux -mattr=+pauth a.s -o a.so.o
// RUN: ld.lld -shared a.so.o -soname=so -o a.so
// RUN: ld.lld ok.o a.so -o ok
// RUN: llvm-objdump --no-print-imm-hex -d --no-show-raw-insn ok | \
// RUN: FileCheck -DP=220 -DA=936 -DB=952 -DC=968 %s
// RUN: llvm-readobj -r -x .got ok | FileCheck --check-prefix=REL \
// RUN: -DP1=220 -DA1=3A8 -DB1=3B8 -DC1=3C8 -DP2=220 -DA2=3a8 -DB2=3b8 -DC2=3c8 %s

.text
adrp x0, :tlsdesc_auth:a
ldr x16, [x0, :tlsdesc_auth_lo12:a]
add x0, x0, :tlsdesc_auth_lo12:a
blraa x16, x0

// CHECK: adrp x0, 0x[[P]]000
// CHECK-NEXT: ldr x16, [x0, #[[A]]]
// CHECK-NEXT: add x0, x0, #[[A]]
// CHECK-NEXT: blraa x16, x0

/// Create relocation against local TLS symbols where linker should
/// create target specific dynamic TLSDESC relocation where addend is
/// the symbol VMA in tls block.

adrp x0, :tlsdesc_auth:local1
ldr x16, [x0, :tlsdesc_auth_lo12:local1]
add x0, x0, :tlsdesc_auth_lo12:local1
blraa x16, x0

// CHECK: adrp x0, 0x[[P]]000
// CHECK-NEXT: ldr x16, [x0, #[[B]]]
// CHECK-NEXT: add x0, x0, #[[B]]
// CHECK-NEXT: blraa x16, x0

adrp x0, :tlsdesc_auth:local2
ldr x16, [x0, :tlsdesc_auth_lo12:local2]
add x0, x0, :tlsdesc_auth_lo12:local2
blraa x16, x0

// CHECK: adrp x0, 0x[[P]]000
// CHECK-NEXT: ldr x16, [x0, #[[C]]]
// CHECK-NEXT: add x0, x0, #[[C]]
// CHECK-NEXT: blraa x16, x0

.section .tbss,"awT",@nobits
.type local1,@object
.p2align 2
local1:
.word 0
.size local1, 4

.type local2,@object
.p2align 3
local2:
.xword 0
.size local2, 8


// R_AARCH64_AUTH_TLSDESC - 0x0 -> start of tls block
// R_AARCH64_AUTH_TLSDESC - 0x8 -> align (sizeof (local1), 8)

// REL: Relocations [
// REL-NEXT: Section (5) .rela.dyn {
// REL-NEXT: 0x[[P1]][[B1]] R_AARCH64_AUTH_TLSDESC - 0x0
// REL-NEXT: 0x[[P1]][[C1]] R_AARCH64_AUTH_TLSDESC - 0x8
// REL-NEXT: 0x[[P1]][[A1]] R_AARCH64_AUTH_TLSDESC a 0x0
// REL-NEXT: }
// REL-NEXT: ]

// REL: Hex dump of section '.got':
// REL-NEXT: 0x00[[P2]][[A2]] 00000000 00000080 00000000 000000a0
// REL-NEXT: 0x00[[P2]][[B2]] 00000000 00000080 00000000 000000a0
// REL-NEXT: 0x00[[P2]][[C2]] 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

//--- err1.s
// RUN: llvm-mc -filetype=obj -triple=aarch64-pc-linux -mattr=+pauth err1.s -o err1.o
// RUN: not ld.lld -shared err1.o 2>&1 | FileCheck --check-prefix=ERR1 --implicit-check-not=error: %s
// ERR1: error: both AUTH and non-AUTH TLSDESC entries for 'a' requested, but only one type of TLSDESC entry per symbol is supported
.text
adrp x0, :tlsdesc_auth:a
ldr x16, [x0, :tlsdesc_auth_lo12:a]
add x0, x0, :tlsdesc_auth_lo12:a
blraa x16, x0

adrp x0, :tlsdesc:a
ldr x1, [x0, :tlsdesc_lo12:a]
add x0, x0, :tlsdesc_lo12:a
blr x1

//--- err2.s
// RUN: llvm-mc -filetype=obj -triple=aarch64-pc-linux -mattr=+pauth err2.s -o err2.o
// RUN: not ld.lld -shared err2.o 2>&1 | FileCheck --check-prefix=ERR2 --implicit-check-not=error: %s
// ERR2: error: both AUTH and non-AUTH TLSDESC entries for 'a' requested, but only one type of TLSDESC entry per symbol is supported
.text
adrp x0, :tlsdesc:a
ldr x1, [x0, :tlsdesc_lo12:a]
add x0, x0, :tlsdesc_lo12:a
blr x1

adrp x0, :tlsdesc_auth:a
ldr x16, [x0, :tlsdesc_auth_lo12:a]
add x0, x0, :tlsdesc_auth_lo12:a
blraa x16, x0

//--- err3.s
// RUN: llvm-mc -filetype=obj -triple=aarch64-pc-linux -mattr=+pauth err3.s -o err3.o
// RUN: not ld.lld -shared err3.o 2>&1 | FileCheck --check-prefix=ERR3 --implicit-check-not=error: %s
// ERR3: error: both AUTH and non-AUTH TLSDESC entries for 'a' requested, but only one type of TLSDESC entry per symbol is supported
.text
adrp x0, :tlsdesc_auth:a
ldr x16, [x0, :tlsdesc_auth_lo12:a]
add x0, x0, :tlsdesc_auth_lo12:a
.tlsdesccall a
blraa x16, x0
Loading