Skip to content

Commit

Permalink
[PAC][lld][AArch64][ELF] Support signed TLSDESC
Browse files Browse the repository at this point in the history
Support `R_AARCH64_AUTH_TLSDESC_ADR_PAGE21`, `R_AARCH64_AUTH_TLSDESC_LD64_LO12`
and `R_AARCH64_AUTH_TLSDESC_LD64_LO12` static TLSDESC relocations.
  • Loading branch information
kovdan01 committed May 3, 2024
1 parent 80ad0bc commit 7c1225e
Show file tree
Hide file tree
Showing 7 changed files with 146 additions and 5 deletions.
8 changes: 8 additions & 0 deletions lld/ELF/Arch/AArch64.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -124,9 +124,14 @@ RelExpr AArch64::getRelExpr(RelType type, const Symbol &s,
return R_AARCH64_AUTH;
case R_AARCH64_TLSDESC_ADR_PAGE21:
return R_AARCH64_TLSDESC_PAGE;
case R_AARCH64_AUTH_TLSDESC_ADR_PAGE21:
return R_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 RelExpr::R_AARCH64_AUTH_TLSDESC;
case R_AARCH64_TLSDESC_CALL:
return R_TLSDESC_CALL;
case R_AARCH64_TLSLE_ADD_TPREL_HI12:
Expand Down Expand Up @@ -446,6 +451,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(loc, val, 33, rel);
[[fallthrough]];
case R_AARCH64_ADR_PREL_PG_HI21_NC:
Expand Down Expand Up @@ -497,6 +503,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(loc, val, 8, rel);
or32AArch64Imm(loc, getBits(val, 3, 11));
break;
Expand Down Expand Up @@ -569,6 +576,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:
or32AArch64Imm(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 @@ -870,12 +870,14 @@ uint64_t InputSectionBase::getRelocTargetVA(const InputFile *file, RelType type,
case R_SIZE:
return sym.getSize() + a;
case R_TLSDESC:
case RelExpr::R_AARCH64_AUTH_TLSDESC:
return in.got->getTlsDescAddr(sym) + a;
case R_TLSDESC_PC:
return in.got->getTlsDescAddr(sym) + a - p;
case R_TLSDESC_GOTPLT:
return in.got->getTlsDescAddr(sym) + a - in.gotPlt->getVA();
case R_AARCH64_TLSDESC_PAGE:
case R_AARCH64_AUTH_TLSDESC_PAGE:
return getAArch64Page(in.got->getTlsDescAddr(sym) + a) - getAArch64Page(p);
case R_TLSGD_GOT:
return in.got->getGlobalDynOffset(sym) + a;
Expand Down
25 changes: 20 additions & 5 deletions lld/ELF/Relocations.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1324,14 +1324,25 @@ static unsigned handleTlsRelocation(RelType type, Symbol &sym,
return handleMipsTlsRelocation(type, sym, c, offset, addend, expr);
bool isRISCV = config->emachine == EM_RISCV;

if (oneof<R_AARCH64_TLSDESC_PAGE, R_TLSDESC, R_TLSDESC_CALL, R_TLSDESC_PC,
if (oneof<R_AARCH64_TLSDESC_PAGE, R_AARCH64_AUTH_TLSDESC_PAGE, R_TLSDESC,
RelExpr::R_AARCH64_AUTH_TLSDESC, R_TLSDESC_CALL, R_TLSDESC_PC,
R_TLSDESC_GOTPLT>(expr) &&
config->shared) {
// 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)
sym.setFlags(NEEDS_TLSDESC);
bool needsTlsDescAuth =
(expr == R_AARCH64_AUTH_TLSDESC_PAGE || expr == RelExpr::R_AARCH64_AUTH_TLSDESC);
if (!sym.hasFlag(NEEDS_TLSDESC)) {
if (!isRISCV || type == R_RISCV_TLSDESC_HI20)
sym.setFlags(NEEDS_TLSDESC);
if (needsTlsDescAuth)
sym.setFlags(NEEDS_TLSDESC_AUTH);
} else if (needsTlsDescAuth != sym.hasFlag(NEEDS_TLSDESC_AUTH)) {
fatal("both AUTH and non-AUTH TLSDESC entries for '" + sym.getName() +
"' requested, but only one type of TLSDESC entry per symbol is "
"supported");
}
c.addReloc({expr, type, offset, addend, &sym});
}
return 1;
Expand Down Expand Up @@ -1788,9 +1799,13 @@ void elf::postScanRelocations() {

if (flags & NEEDS_TLSDESC) {
got->addTlsDescEntry(sym);
RelType tlsDescRel = target->tlsDescRel;
if (flags & NEEDS_TLSDESC_AUTH) {
assert(config->emachine == EM_AARCH64);
tlsDescRel = ELF::R_AARCH64_AUTH_TLSDESC;
}
mainPart->relaDyn->addAddendOnlyRelocIfNonPreemptible(
target->tlsDescRel, *got, got->getTlsDescOffset(sym), sym,
target->tlsDescRel);
tlsDescRel, *got, got->getTlsDescOffset(sym), sym, tlsDescRel);
}
if (flags & NEEDS_TLSGD) {
got->addDynTlsEntry(sym);
Expand Down
4 changes: 4 additions & 0 deletions lld/ELF/Relocations.h
Original file line number Diff line number Diff line change
Expand Up @@ -90,6 +90,10 @@ enum RelExpr {
R_AARCH64_PAGE_PC,
R_AARCH64_RELAX_TLS_GD_TO_IE_PAGE_PC,
R_AARCH64_TLSDESC_PAGE,
R_AARCH64_AUTH_TLSDESC_PAGE,
// TODO: maybe it's better to rename this expression
// to avoid name conflict with dynamic reloc
R_AARCH64_AUTH_TLSDESC,
R_AARCH64_AUTH,
R_ARM_PCA,
R_ARM_SBREL,
Expand Down
1 change: 1 addition & 0 deletions lld/ELF/Symbols.h
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,7 @@ enum {
NEEDS_GOT_DTPREL = 1 << 7,
NEEDS_TLSIE = 1 << 8,
NEEDS_GOT_AUTH = 1 << 9,
NEEDS_TLSDESC_AUTH = 1 << 10,
};

// Some index properties of a symbol are stored separately in this auxiliary
Expand Down
5 changes: 5 additions & 0 deletions lld/ELF/SyntheticSections.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -665,6 +665,11 @@ bool GotSection::addTlsDescEntry(const Symbol &sym) {
assert(sym.auxIdx == symAux.size() - 1);
symAux.back().tlsDescIdx = numEntries;
numEntries += 2;
if (sym.hasFlag(NEEDS_TLSDESC_AUTH)) {
assert(config->emachine == EM_AARCH64);
authEntries.push_back({(numEntries - 2) * config->wordsize, true});
authEntries.push_back({(numEntries - 1) * config->wordsize, false});
}
return true;
}

Expand Down
106 changes: 106 additions & 0 deletions lld/test/ELF/aarch64-tlsdesc-auth.s
Original file line number Diff line number Diff line change
@@ -0,0 +1,106 @@
// REQUIRES: aarch64
// RUN: rm -rf %t && split-file %s %t && cd %t

//--- ok.s

// RUN: llvm-mc -filetype=obj -triple=aarch64-pc-linux -mattr=+pauth ok.s -o ok.o
// RUN: ld.lld --hash-style=sysv -shared ok.o -o ok.so
// RUN: llvm-objdump --no-print-imm-hex -d --no-show-raw-insn ok.so | FileCheck %s
// RUN: llvm-readobj -r -x .got ok.so | FileCheck --check-prefix=REL %s

.text
adrp x0, :tlsdesc_auth:a
ldr x16, [x0, :tlsdesc_auth_lo12:a]
add x0, x0, :tlsdesc_auth_lo12:a
autia x16, x0
.tlsdesccall a
blr x16

// CHECK: 10298: adrp x0, 0x20000
// CHECK-NEXT: 1029c: ldr x16, [x0, #872]
// CHECK-NEXT: 102a0: add x0, x0, #872
// CHECK-NEXT: 102a4: autia x16, x0
// CHECK-NEXT: 102a8: blr x16

// 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
autia x16, x0
.tlsdesccall a
blr x16

// CHECK: 102ac: adrp x0, 0x20000
// CHECK-NEXT: 102b0: ldr x16, [x0, #888]
// CHECK-NEXT: 102b4: add x0, x0, #888
// CHECK-NEXT: 102b8: autia x16, x0
// CHECK-NEXT: 102bc: blr x16

adrp x0, :tlsdesc_auth:local2
ldr x16, [x0, :tlsdesc_auth_lo12:local2]
add x0, x0, :tlsdesc_auth_lo12:local2
autia x16, x0
.tlsdesccall a
blr x16

// CHECK: 102c0: adrp x0, 0x20000
// CHECK-NEXT: 102c4: ldr x16, [x0, #904]
// CHECK-NEXT: 102c8: add x0, x0, #904
// CHECK-NEXT: 102cc: autia x16, x0
// CHECK-NEXT: 102d0: blr x16

.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 (4) .rela.dyn {
// REL-NEXT: 0x20378 R_AARCH64_AUTH_TLSDESC - 0x0
// REL-NEXT: 0x20388 R_AARCH64_AUTH_TLSDESC - 0x8
// REL-NEXT: 0x20368 R_AARCH64_AUTH_TLSDESC a 0x0
// REL-NEXT: }
// REL-NEXT: ]

// REL: Hex dump of section '.got':
// REL-NEXT: 0x00020368 00000000 00000080 00000000 000000a0
// REL-NEXT: 0x00020378 00000000 00000080 00000000 000000a0
// REL-NEXT: 0x00020388 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

//--- err.s

// RUN: llvm-mc -filetype=obj -triple=aarch64-pc-linux -mattr=+pauth err.s -o err.o
// RUN: not ld.lld --hash-style=sysv -shared err.o -o err.so 2>&1 | FileCheck --check-prefix=ERR %s
// ERR: 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
autia x16, x0
.tlsdesccall a
blr x16

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

0 comments on commit 7c1225e

Please sign in to comment.