From 7c1225eed3f6a20b0e9ccf8f2f645676b3e0231d Mon Sep 17 00:00:00 2001 From: Daniil Kovalev Date: Fri, 3 May 2024 15:19:25 +0300 Subject: [PATCH] [PAC][lld][AArch64][ELF] Support signed TLSDESC Support `R_AARCH64_AUTH_TLSDESC_ADR_PAGE21`, `R_AARCH64_AUTH_TLSDESC_LD64_LO12` and `R_AARCH64_AUTH_TLSDESC_LD64_LO12` static TLSDESC relocations. --- lld/ELF/Arch/AArch64.cpp | 8 +++ lld/ELF/InputSection.cpp | 2 + lld/ELF/Relocations.cpp | 25 +++++-- lld/ELF/Relocations.h | 4 ++ lld/ELF/Symbols.h | 1 + lld/ELF/SyntheticSections.cpp | 5 ++ lld/test/ELF/aarch64-tlsdesc-auth.s | 106 ++++++++++++++++++++++++++++ 7 files changed, 146 insertions(+), 5 deletions(-) create mode 100644 lld/test/ELF/aarch64-tlsdesc-auth.s diff --git a/lld/ELF/Arch/AArch64.cpp b/lld/ELF/Arch/AArch64.cpp index d10f8177c60d..1310a0f3b91e 100644 --- a/lld/ELF/Arch/AArch64.cpp +++ b/lld/ELF/Arch/AArch64.cpp @@ -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: @@ -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: @@ -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; @@ -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: diff --git a/lld/ELF/InputSection.cpp b/lld/ELF/InputSection.cpp index 0ecbc928bff8..c1c6fa64355e 100644 --- a/lld/ELF/InputSection.cpp +++ b/lld/ELF/InputSection.cpp @@ -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; diff --git a/lld/ELF/Relocations.cpp b/lld/ELF/Relocations.cpp index 550d1a538281..d32da4df10de 100644 --- a/lld/ELF/Relocations.cpp +++ b/lld/ELF/Relocations.cpp @@ -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(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; @@ -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); diff --git a/lld/ELF/Relocations.h b/lld/ELF/Relocations.h index 692476a98d78..dc0784f9288b 100644 --- a/lld/ELF/Relocations.h +++ b/lld/ELF/Relocations.h @@ -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, diff --git a/lld/ELF/Symbols.h b/lld/ELF/Symbols.h index c8aa3d937af0..67affa3cdf9a 100644 --- a/lld/ELF/Symbols.h +++ b/lld/ELF/Symbols.h @@ -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 diff --git a/lld/ELF/SyntheticSections.cpp b/lld/ELF/SyntheticSections.cpp index 2b4219344081..3f1573ca3ecd 100644 --- a/lld/ELF/SyntheticSections.cpp +++ b/lld/ELF/SyntheticSections.cpp @@ -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; } diff --git a/lld/test/ELF/aarch64-tlsdesc-auth.s b/lld/test/ELF/aarch64-tlsdesc-auth.s new file mode 100644 index 000000000000..34c1bd2e86b5 --- /dev/null +++ b/lld/test/ELF/aarch64-tlsdesc-auth.s @@ -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