https://github.com/kovdan01 updated https://github.com/llvm/llvm-project/pull/194636
>From 4bd87749d2236a469499ee6e6c56a78d864707f9 Mon Sep 17 00:00:00 2001 From: Daniil Kovalev <[email protected]> Date: Tue, 28 Apr 2026 15:54:49 +0300 Subject: [PATCH 1/2] [PAC][lld] Do not emit AUTH relocs against undef weak non-preemptible symbols Undefined weak non-preemptible symbols should be statically resolved to the addend value and not signed. Previously, a dynamic relocation against such symbols was emitted, which is not a correct behavior. See also docs: https://github.com/ARM-software/abi-aa/pull/391 Resolves #173296 --- lld/ELF/Arch/AArch64.cpp | 135 +++++++++++++++--- lld/ELF/RelocScan.h | 4 +- lld/ELF/Relocations.cpp | 19 ++- lld/ELF/SyntheticSections.cpp | 20 ++- lld/ELF/SyntheticSections.h | 3 +- .../ELF/aarch64-reloc-pauth-undef-weak-dso.s | 48 +++++++ .../ELF/aarch64-reloc-pauth-undef-weak-pie.s | 47 ++++++ lld/test/ELF/aarch64-reloc-pauth-undef-weak.s | 48 +++++++ lld/test/ELF/aarch64-tlsdesc-pauth.s | 12 +- 9 files changed, 300 insertions(+), 36 deletions(-) create mode 100644 lld/test/ELF/aarch64-reloc-pauth-undef-weak-dso.s create mode 100644 lld/test/ELF/aarch64-reloc-pauth-undef-weak-pie.s create mode 100644 lld/test/ELF/aarch64-reloc-pauth-undef-weak.s diff --git a/lld/ELF/Arch/AArch64.cpp b/lld/ELF/Arch/AArch64.cpp index 99b3085852df7..9f72ce14c80ec 100644 --- a/lld/ELF/Arch/AArch64.cpp +++ b/lld/ELF/Arch/AArch64.cpp @@ -102,6 +102,8 @@ class AArch64 : public TargetInfo { void relaxTlsGdToLe(uint8_t *loc, const Relocation &rel, uint64_t val) const; void relaxTlsGdToIe(uint8_t *loc, const Relocation &rel, uint64_t val) const; void relaxTlsIeToLe(uint8_t *loc, const Relocation &rel, uint64_t val) const; + void relaxAuthTlsDescForNonPreemptibleUndefWeak(uint8_t *loc, + const Relocation &rel) const; }; struct AArch64Relaxer { @@ -191,6 +193,7 @@ template <class ELFT, class RelTy> void AArch64::scanSectionImpl(InputSectionBase &sec, Relocs<RelTy> rels) { RelocScan rs(ctx, &sec); sec.relocations.reserve(rels.size()); + SmallVector<Relocation, 0> tlsdescCallRels; for (auto it = rels.begin(); it != rels.end(); ++it) { const RelTy &rel = *it; @@ -206,6 +209,20 @@ void AArch64::scanSectionImpl(InputSectionBase &sec, Relocs<RelTy> rels) { // Relocation types that only need a RelExpr set `expr` and break out of // the switch to reach rs.process(). Types that need special handling // (fast-path helpers, TLS) call a handler and use `continue`. + + auto handleTlsDescAuth = [&sym, &sec, type, offset, + addend](RelExpr tlsdescExpr) { + sym.setFlags(NEEDS_TLSDESC_AUTH); + if (sym.isUndefWeak() && !sym.isPreemptible) { + // Resolves statically to null. Handle in + // relaxAuthTlsDescForNonPreemptibleUndefWeak + sec.addReloc({R_TPREL, type, offset, addend, &sym}); + } else { + sym.setFlags(NEEDS_TLSDESC); + sec.addReloc({tlsdescExpr, type, offset, addend, &sym}); + } + }; + switch (type) { case R_AARCH64_NONE: continue; @@ -340,30 +357,28 @@ void AArch64::scanSectionImpl(InputSectionBase &sec, Relocs<RelTy> rels) { // TLSDESC relocations: case R_AARCH64_TLSDESC_ADR_PAGE21: + sym.setFlags(NEEDS_TLSDESC_NONAUTH); rs.handleTlsDesc(RE_AARCH64_TLSDESC_PAGE, RE_AARCH64_GOT_PAGE_PC, type, offset, addend, sym); continue; case R_AARCH64_TLSDESC_LD64_LO12: case R_AARCH64_TLSDESC_ADD_LO12: + sym.setFlags(NEEDS_TLSDESC_NONAUTH); rs.handleTlsDesc(R_TLSDESC, R_GOT, type, offset, addend, sym); continue; case R_AARCH64_TLSDESC_CALL: - sym.setFlags(NEEDS_TLSDESC_NONAUTH); - if (!ctx.arg.shared) - sec.addReloc({R_TPREL, type, offset, addend, &sym}); + tlsdescCallRels.push_back({R_TPREL, type, offset, addend, &sym}); continue; // AUTH TLSDESC relocations. Do not optimize to LE/IE because PAUTHELF64 // only supports the descriptor based TLS (TLSDESC). // https://github.com/ARM-software/abi-aa/blob/main/pauthabielf64/pauthabielf64.rst#general-restrictions case R_AARCH64_AUTH_TLSDESC_ADR_PAGE21: - sym.setFlags(NEEDS_TLSDESC | NEEDS_TLSDESC_AUTH); - sec.addReloc({RE_AARCH64_TLSDESC_PAGE, type, offset, addend, &sym}); + handleTlsDescAuth(RE_AARCH64_TLSDESC_PAGE); continue; case R_AARCH64_AUTH_TLSDESC_LD64_LO12: case R_AARCH64_AUTH_TLSDESC_ADD_LO12: - sym.setFlags(NEEDS_TLSDESC | NEEDS_TLSDESC_AUTH); - sec.addReloc({R_TLSDESC, type, offset, addend, &sym}); + handleTlsDescAuth(R_TLSDESC); continue; default: @@ -375,6 +390,27 @@ void AArch64::scanSectionImpl(InputSectionBase &sec, Relocs<RelTy> rels) { rs.process(expr, type, offset, sym, addend); } + for (const auto &tlsdescCallRel : tlsdescCallRels) { + const Symbol *sym = tlsdescCallRel.sym; + auto flags = sym->flags.load(std::memory_order_relaxed); + + if (flags & NEEDS_TLSDESC_AUTH) { + if (sym->isUndefWeak() && !sym->isPreemptible) + sec.addReloc(tlsdescCallRel); + continue; + } + if (flags & NEEDS_TLSDESC_NONAUTH) { + if (!ctx.arg.shared) + sec.addReloc(tlsdescCallRel); + continue; + } + + Err(ctx) << getErrorLoc(ctx, sec.content().data() + tlsdescCallRel.offset) + << "relocation R_AARCH64_TLSDESC_CALL against '" << sym + << "' requires other TLSDESC or AUTH TLSDESC relocations present " + "against this symbol"; + } + if (ctx.arg.branchToBranch) llvm::stable_sort(sec.relocs(), [](auto &l, auto &r) { return l.offset < r.offset; }); @@ -645,11 +681,22 @@ void AArch64::relocate(uint8_t *loc, const Relocation &rel, write64(ctx, loc, val); break; case R_AARCH64_AUTH_ABS64: - // This is used for the addend of a .relr.auth.dyn entry, - // which is a 32-bit value; the upper 32 bits are used to - // encode the schema. - checkInt(ctx, loc, val, 32, rel); - write32(ctx, loc, val); + if (rel.sym->isUndefined() && !rel.sym->isPreemptible) { + // Undefined weak non-preemptible symbols are statically resolved to the + // addend. No dynamic relocation and corresponding signing schema encoding + // is needed. + // + // Note: at this point, binding of undefined weak non-preemptible symbols + // has already been changed from weak to local by computeBinding call, so + // just check against isUndefined(). + write64(ctx, loc, val); + } else { + // This is used for the addend of a .relr.auth.dyn entry, + // which is a 32-bit value; the upper 32 bits are used to + // encode the schema. + checkInt(ctx, loc, val, 32, rel); + write32(ctx, loc, val); + } break; case R_AARCH64_TLS_DTPREL64: write64(ctx, loc, val); @@ -803,6 +850,35 @@ void AArch64::relocate(uint8_t *loc, const Relocation &rel, } } +void AArch64::relaxAuthTlsDescForNonPreemptibleUndefWeak( + uint8_t *loc, const Relocation &rel) const { + // AUTH TLSDESC relocations are in the form: + // adrp x0, :tlsdesc_auth:v [R_AARCH64_AUTH_TLSDESC_ADR_PAGE21] + // ldr x16, [x0, :tlsdesc_auth_lo12:v] [R_AARCH64_AUTH_TLSDESC_LD64_LO12] + // add x0, x0, :tlsdesc_auth_lo12:v [R_AARCH64_AUTH_TLSDESC_ADD_LO12] + // .tlsdesccall v [R_AARCH64_TLSDESC_CALL] + // blraa x16, x0 + // And it can optimized to: + // mov x0, #0x0 + // nop + // nop + // nop + + switch (rel.type) { + case R_AARCH64_AUTH_TLSDESC_ADD_LO12: + case R_AARCH64_AUTH_TLSDESC_LD64_LO12: + case R_AARCH64_TLSDESC_CALL: + write32le(loc, 0xd503201f); // nop + return; + case R_AARCH64_AUTH_TLSDESC_ADR_PAGE21: + write32le(loc, 0xd2800000); // mov x0, #0x0 + return; + default: + llvm_unreachable("unsupported relocation for non-preemptible undefined " + "weak AUTH TLSDESC relaxation"); + } +} + void AArch64::relaxTlsGdToLe(uint8_t *loc, const Relocation &rel, uint64_t val) const { // TLSDESC Global-Dynamic relocation are in the form: @@ -1054,6 +1130,26 @@ void AArch64::relocateAlloc(InputSection &sec, uint8_t *buf) const { continue; } + auto tryRelaxTlsDesc = [this, &rel, loc, val]() { + assert(rel.sym->hasFlag(NEEDS_TLSDESC_NONAUTH)); + assert(!rel.sym->hasFlag(NEEDS_TLSDESC_AUTH)); + if (rel.expr == R_TPREL) + relaxTlsGdToLe(loc, rel, val); + else if (rel.expr == RE_AARCH64_GOT_PAGE_PC || rel.expr == R_GOT) + relaxTlsGdToIe(loc, rel, val); + else + relocate(loc, rel, val); + }; + + auto tryRelaxTlsDescAuth = [this, &rel, loc, val]() { + assert(!rel.sym->hasFlag(NEEDS_TLSDESC_NONAUTH)); + assert(rel.sym->hasFlag(NEEDS_TLSDESC_AUTH)); + if (rel.expr == R_TPREL) + relaxAuthTlsDescForNonPreemptibleUndefWeak(loc, rel); + else + relocate(loc, rel, val); + }; + switch (rel.type) { case R_AARCH64_ADR_GOT_PAGE: if (i + 1 < size && @@ -1073,13 +1169,18 @@ void AArch64::relocateAlloc(InputSection &sec, uint8_t *buf) const { case R_AARCH64_TLSDESC_ADR_PAGE21: case R_AARCH64_TLSDESC_LD64_LO12: case R_AARCH64_TLSDESC_ADD_LO12: + tryRelaxTlsDesc(); + continue; case R_AARCH64_TLSDESC_CALL: - if (rel.expr == R_TPREL) - relaxTlsGdToLe(loc, rel, val); - else if (rel.expr == RE_AARCH64_GOT_PAGE_PC || rel.expr == R_GOT) - relaxTlsGdToIe(loc, rel, val); + if (rel.sym->hasFlag(NEEDS_TLSDESC_AUTH)) + tryRelaxTlsDescAuth(); else - relocate(loc, rel, val); + tryRelaxTlsDesc(); + continue; + case R_AARCH64_AUTH_TLSDESC_ADR_PAGE21: + case R_AARCH64_AUTH_TLSDESC_LD64_LO12: + case R_AARCH64_AUTH_TLSDESC_ADD_LO12: + tryRelaxTlsDescAuth(); continue; case R_AARCH64_TLSIE_ADR_GOTTPREL_PAGE21: case R_AARCH64_TLSIE_LD64_GOTTPREL_LO12_NC: diff --git a/lld/ELF/RelocScan.h b/lld/ELF/RelocScan.h index 526482a156ccc..9829cec203261 100644 --- a/lld/ELF/RelocScan.h +++ b/lld/ELF/RelocScan.h @@ -159,9 +159,7 @@ class RelocScan { void handleTlsDesc(RelExpr sharedExpr, RelExpr ieExpr, RelType type, uint64_t offset, int64_t addend, Symbol &sym) { if (ctx.arg.shared) { - // NEEDS_TLSDESC_NONAUTH is a no-op for non-AArch64 targets and detects - // incompatibility with NEEDS_TLSDESC_AUTH. - sym.setFlags(NEEDS_TLSDESC | NEEDS_TLSDESC_NONAUTH); + sym.setFlags(NEEDS_TLSDESC); sec->addReloc({sharedExpr, type, offset, addend, &sym}); } else if (sym.isPreemptible) { // Optimize to Initial Exec. diff --git a/lld/ELF/Relocations.cpp b/lld/ELF/Relocations.cpp index ac7752a423440..abac5d9ea4c22 100644 --- a/lld/ELF/Relocations.cpp +++ b/lld/ELF/Relocations.cpp @@ -789,9 +789,12 @@ static void addGotAuthEntry(Ctx &ctx, Symbol &sym) { return; } - // Signed GOT requires dynamic relocation. - ctx.in.relaDyn->addReloc( - {R_AARCH64_AUTH_RELATIVE, ctx.in.got.get(), off, false, sym, 0, R_ABS}); + // Signed GOT requires dynamic relocation unless the symbol is + // non-preemptible and undefined weak. + if (!sym.isUndefWeak()) { + ctx.in.relaDyn->addReloc( + {R_AARCH64_AUTH_RELATIVE, ctx.in.got.get(), off, false, sym, 0, R_ABS}); + } } static void addTpOffsetGotEntry(Ctx &ctx, Symbol &sym) { @@ -851,8 +854,12 @@ bool RelocScan::isStaticLinkTimeConstant(RelExpr e, RelType type, // only the low bits are used. if (e == R_GOT || e == R_PLT) return ctx.target->usesOnlyLowPageBits(type) || !ctx.arg.isPic; - // R_AARCH64_AUTH_ABS64 and iRelSymbolicRel require a dynamic relocation. - if (e == RE_AARCH64_AUTH || type == ctx.target->iRelSymbolicRel) + // R_AARCH64_AUTH_ABS64 requires a dynamic relocation unless the symbol is + // non-preemptible and undefined weak. + if (e == RE_AARCH64_AUTH && (!sym.isUndefWeak() || sym.isPreemptible)) + return false; + // iRelSymbolicRel requires a dynamic relocation. + if (type == ctx.target->iRelSymbolicRel) return false; // The behavior of an undefined weak reference is implementation defined. @@ -1354,7 +1361,7 @@ void elf::postScanRelocations(Ctx &ctx) { got->addTlsDescEntry(sym); RelType tlsDescRel = ctx.target->tlsDescRel; if (flags & NEEDS_TLSDESC_AUTH) { - got->addTlsDescAuthEntry(); + got->addTlsDescAuthEntry(sym); tlsDescRel = ELF::R_AARCH64_AUTH_TLSDESC; } ctx.in.relaDyn->addAddendOnlyRelocIfNonPreemptible( diff --git a/lld/ELF/SyntheticSections.cpp b/lld/ELF/SyntheticSections.cpp index b9a42590dc8e7..476797d4f5f0c 100644 --- a/lld/ELF/SyntheticSections.cpp +++ b/lld/ELF/SyntheticSections.cpp @@ -507,7 +507,9 @@ void GotSection::addEntry(const Symbol &sym) { void GotSection::addAuthEntry(const Symbol &sym) { authEntries.push_back( - {(numEntries - 1) * ctx.target->gotEntrySize, sym.isFunc()}); + {/*offset=*/(numEntries - 1) * ctx.target->gotEntrySize, + /*isSymbolFunc=*/sym.isFunc(), + /*isUndefWeakNonPreemptible=*/sym.isUndefWeak() && !sym.isPreemptible}); } bool GotSection::addTlsDescEntry(const Symbol &sym) { @@ -517,9 +519,12 @@ bool GotSection::addTlsDescEntry(const Symbol &sym) { return true; } -void GotSection::addTlsDescAuthEntry() { - authEntries.push_back({(numEntries - 2) * ctx.target->gotEntrySize, true}); - authEntries.push_back({(numEntries - 1) * ctx.target->gotEntrySize, false}); +void GotSection::addTlsDescAuthEntry(const Symbol &sym) { + authEntries.push_back({/*offset=*/(numEntries - 2) * ctx.target->gotEntrySize, + /*isSymbolFunc=*/true, + /*isUndefWeakNonPreemptible=*/false}); + assert(!sym.isFunc()); + addAuthEntry(sym); } bool GotSection::addDynTlsEntry(const Symbol &sym) { @@ -578,6 +583,12 @@ void GotSection::writeTo(uint8_t *buf) { ctx.target->writeGotHeader(buf); ctx.target->relocateAlloc(*this, buf); for (const AuthEntryInfo &authEntry : authEntries) { + uint8_t *dest = buf + authEntry.offset; + + if (authEntry.isUndefWeakNonPreemptible) { + write64(ctx, dest, 0); + continue; + } // 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 @@ -587,7 +598,6 @@ void GotSection::writeTo(uint8_t *buf) { // 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)); diff --git a/lld/ELF/SyntheticSections.h b/lld/ELF/SyntheticSections.h index 38a8bb9b320f4..e9dcd8f1c7a30 100644 --- a/lld/ELF/SyntheticSections.h +++ b/lld/ELF/SyntheticSections.h @@ -123,7 +123,7 @@ class GotSection final : public SyntheticSection { void addEntry(const Symbol &sym); void addAuthEntry(const Symbol &sym); bool addTlsDescEntry(const Symbol &sym); - void addTlsDescAuthEntry(); + void addTlsDescAuthEntry(const Symbol &sym); bool addDynTlsEntry(const Symbol &sym); bool addTlsIndex(); uint32_t getTlsDescOffset(const Symbol &sym) const; @@ -144,6 +144,7 @@ class GotSection final : public SyntheticSection { struct AuthEntryInfo { size_t offset; bool isSymbolFunc; + bool isUndefWeakNonPreemptible; }; SmallVector<AuthEntryInfo, 0> authEntries; }; diff --git a/lld/test/ELF/aarch64-reloc-pauth-undef-weak-dso.s b/lld/test/ELF/aarch64-reloc-pauth-undef-weak-dso.s new file mode 100644 index 0000000000000..3080d5cef9eca --- /dev/null +++ b/lld/test/ELF/aarch64-reloc-pauth-undef-weak-dso.s @@ -0,0 +1,48 @@ +# REQUIRES: aarch64 +# RUN: llvm-mc -filetype=obj -triple=aarch64 -mattr=+pauth %s -o %t.o +# RUN: ld.lld -shared %t.o -o %t +# RUN: llvm-readobj -r %t | FileCheck %s --check-prefix=RELA +# RUN: llvm-readelf -x.data %t | FileCheck %s --check-prefix=DATA +# RUN: llvm-readelf -x.got %t | FileCheck %s --check-prefix=GOT +# RUN: llvm-objdump -d --no-show-raw-insn %t | FileCheck %s --check-prefix=DIS + +## Verify that R_AARCH64_AUTH_ABS64 against a weak undefined symbol is resolved +## to NULL (plus addend). + +# RELA-LABEL: Relocations [ +# RELA-NEXT: ] + +# DATA-LABEL: Hex dump of section '.data': +# DATA-NEXT: 0x00030300 00000000 00000000 25000000 00000000 +# DATA-NEXT: 0x00030310 00000000 00000000 25000000 00000000 + +# GOT-LABEL: Hex dump of section '.got': +# GOT-NEXT: 0x000202f8 00000000 00000000 + +# DIS-LABEL: <_start>: +# DIS-NEXT: adrp x0, 0x20000 +# DIS-NEXT: ldr x0, [x0, #0x2f8] +# DIS-NEXT: mov x0, #0x0 +# DIS-NEXT: nop +# DIS-NEXT: nop +# DIS-NEXT: nop + +.weak undef +.hidden undef + +.globl _start +_start: + adrp x0, :got_auth:undef + ldr x0, [x0, :got_auth_lo12:undef] + adrp x0, :tlsdesc_auth:undef + ldr x16, [x0, :tlsdesc_auth_lo12:undef] + add x0, x0, :tlsdesc_auth_lo12:undef + .tlsdesccall undef + blraa x16, x0 + +.data +foo: +.quad undef@AUTH(da,42) +.quad (undef + 37)@AUTH(da,42) +.quad undef +.quad (undef + 37) diff --git a/lld/test/ELF/aarch64-reloc-pauth-undef-weak-pie.s b/lld/test/ELF/aarch64-reloc-pauth-undef-weak-pie.s new file mode 100644 index 0000000000000..bec858d2ea7c9 --- /dev/null +++ b/lld/test/ELF/aarch64-reloc-pauth-undef-weak-pie.s @@ -0,0 +1,47 @@ +# REQUIRES: aarch64 +# RUN: llvm-mc -filetype=obj -triple=aarch64 -mattr=+pauth %s -o %t.o +# RUN: ld.lld -pie %t.o -o %t +# RUN: llvm-readobj -r %t | FileCheck %s --check-prefix=RELA +# RUN: llvm-readelf -x.data %t | FileCheck %s --check-prefix=DATA +# RUN: llvm-readelf -x.got %t | FileCheck %s --check-prefix=GOT +# RUN: llvm-objdump -d --no-show-raw-insn %t | FileCheck %s --check-prefix=DIS + +## Verify that R_AARCH64_AUTH_ABS64 against a weak undefined symbol is resolved +## to NULL (plus addend). + +# RELA-LABEL: Relocations [ +# RELA-NEXT: ] + +# DATA-LABEL: Hex dump of section '.data': +# DATA-NEXT: 0x000302f8 00000000 00000000 25000000 00000000 +# DATA-NEXT: 0x00030308 00000000 00000000 25000000 00000000 + +# GOT-LABEL: Hex dump of section '.got': +# GOT-NEXT: 0x000202f0 00000000 00000000 + +# DIS-LABEL: <_start>: +# DIS-NEXT: adrp x0, 0x20000 +# DIS-NEXT: ldr x0, [x0, #0x2f0] +# DIS-NEXT: mov x0, #0x0 +# DIS-NEXT: nop +# DIS-NEXT: nop +# DIS-NEXT: nop + +.weak undef + +.globl _start +_start: + adrp x0, :got_auth:undef + ldr x0, [x0, :got_auth_lo12:undef] + adrp x0, :tlsdesc_auth:undef + ldr x16, [x0, :tlsdesc_auth_lo12:undef] + add x0, x0, :tlsdesc_auth_lo12:undef + .tlsdesccall undef + blraa x16, x0 + +.data +foo: +.quad undef@AUTH(da,42) +.quad (undef + 37)@AUTH(da,42) +.quad undef +.quad (undef + 37) diff --git a/lld/test/ELF/aarch64-reloc-pauth-undef-weak.s b/lld/test/ELF/aarch64-reloc-pauth-undef-weak.s new file mode 100644 index 0000000000000..44995654909bf --- /dev/null +++ b/lld/test/ELF/aarch64-reloc-pauth-undef-weak.s @@ -0,0 +1,48 @@ +# REQUIRES: aarch64 +# RUN: llvm-mc -filetype=obj -triple=aarch64 -mattr=+pauth %s -o %t.o +# RUN: ld.lld --static %t.o -o %t +# RUN: llvm-readobj -r %t | FileCheck %s --check-prefix=RELA +# RUN: llvm-readelf -x.data %t | FileCheck %s --check-prefix=DATA +# RUN: llvm-readelf -x.got %t | FileCheck %s --check-prefix=GOT +# RUN: llvm-objdump -d --no-show-raw-insn %t | FileCheck %s --check-prefix=DIS + +## Verify that R_AARCH64_AUTH_ABS64 against a weak undefined symbol is resolved +## to NULL (plus addend). + +# RELA-LABEL: Relocations [ +# RELA-NEXT: ] + +# DATA-LABEL: Hex dump of section '.data': +# DATA-NEXT: 0x002301e8 00000000 00000000 25000000 00000000 +# DATA-NEXT: 0x002301f8 00000000 00000000 25000000 00000000 + +# GOT-LABEL: Hex dump of section '.got': +# GOT-NEXT: 0x002201e0 00000000 00000000 + +# DIS-LABEL: <_start>: + +# DIS-NEXT: adrp x0, 0x220000 +# DIS-NEXT: ldr x0, [x0, #0x1e0] +# DIS-NEXT: mov x0, #0x0 +# DIS-NEXT: nop +# DIS-NEXT: nop +# DIS-NEXT: nop + +.weak undef + +.globl _start +_start: + adrp x0, :got_auth:undef + ldr x0, [x0, :got_auth_lo12:undef] + adrp x0, :tlsdesc_auth:undef + ldr x16, [x0, :tlsdesc_auth_lo12:undef] + add x0, x0, :tlsdesc_auth_lo12:undef + .tlsdesccall undef + blraa x16, x0 + +.data +foo: +.quad undef@AUTH(da,42) +.quad (undef + 37)@AUTH(da,42) +.quad undef +.quad undef + 37 diff --git a/lld/test/ELF/aarch64-tlsdesc-pauth.s b/lld/test/ELF/aarch64-tlsdesc-pauth.s index bf0ae4a87f322..b5f818cf60567 100644 --- a/lld/test/ELF/aarch64-tlsdesc-pauth.s +++ b/lld/test/ELF/aarch64-tlsdesc-pauth.s @@ -27,6 +27,7 @@ a: adrp x0, :tlsdesc_auth:a ldr x16, [x0, :tlsdesc_auth_lo12:a] add x0, x0, :tlsdesc_auth_lo12:a + .tlsdesccall a blraa x16, x0 // CHECK: adrp x0, 0x[[P]]000 @@ -41,6 +42,7 @@ a: adrp x0, :tlsdesc_auth:local1 ldr x16, [x0, :tlsdesc_auth_lo12:local1] add x0, x0, :tlsdesc_auth_lo12:local1 + .tlsdesccall local1 blraa x16, x0 // CHECK: adrp x0, 0x[[P]]000 @@ -51,6 +53,7 @@ a: adrp x0, :tlsdesc_auth:local2 ldr x16, [x0, :tlsdesc_auth_lo12:local2] add x0, x0, :tlsdesc_auth_lo12:local2 + .tlsdesccall local2 blraa x16, x0 // CHECK: adrp x0, 0x[[P]]000 @@ -100,11 +103,13 @@ local2: adrp x0, :tlsdesc_auth:a ldr x16, [x0, :tlsdesc_auth_lo12:a] add x0, x0, :tlsdesc_auth_lo12:a + .tlsdesccall a blraa x16, x0 adrp x0, :tlsdesc:a ldr x1, [x0, :tlsdesc_lo12:a] add x0, x0, :tlsdesc_lo12:a + .tlsdesccall a blr x1 //--- err2.s @@ -115,20 +120,19 @@ local2: adrp x0, :tlsdesc:a ldr x1, [x0, :tlsdesc_lo12:a] add x0, x0, :tlsdesc_lo12:a + .tlsdesccall a blr x1 adrp x0, :tlsdesc_auth:a ldr x16, [x0, :tlsdesc_auth_lo12:a] add x0, x0, :tlsdesc_auth_lo12:a + .tlsdesccall 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 +// ERR3: error: err3.o:(.text+0x0): relocation R_AARCH64_TLSDESC_CALL against 'a' requires other TLSDESC or AUTH TLSDESC relocations present against this symbol .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 >From 727f78810bf1e38c633d9d35a290cd6291f8cb9e Mon Sep 17 00:00:00 2001 From: Daniil Kovalev <[email protected]> Date: Mon, 18 May 2026 18:40:51 +0300 Subject: [PATCH 2/2] Support R_AARCH64_AUTH_TLSDESC_CALL --- lld/ELF/Arch/AArch64.cpp | 73 +++++-------------- lld/ELF/RelocScan.h | 4 +- .../ELF/aarch64-reloc-pauth-undef-weak-dso.s | 2 +- .../ELF/aarch64-reloc-pauth-undef-weak-pie.s | 2 +- lld/test/ELF/aarch64-reloc-pauth-undef-weak.s | 2 +- lld/test/ELF/aarch64-tlsdesc-pauth.s | 15 ++-- 6 files changed, 35 insertions(+), 63 deletions(-) diff --git a/lld/ELF/Arch/AArch64.cpp b/lld/ELF/Arch/AArch64.cpp index 9f72ce14c80ec..0eeba27eefcdb 100644 --- a/lld/ELF/Arch/AArch64.cpp +++ b/lld/ELF/Arch/AArch64.cpp @@ -193,7 +193,6 @@ template <class ELFT, class RelTy> void AArch64::scanSectionImpl(InputSectionBase &sec, Relocs<RelTy> rels) { RelocScan rs(ctx, &sec); sec.relocations.reserve(rels.size()); - SmallVector<Relocation, 0> tlsdescCallRels; for (auto it = rels.begin(); it != rels.end(); ++it) { const RelTy &rel = *it; @@ -357,17 +356,17 @@ void AArch64::scanSectionImpl(InputSectionBase &sec, Relocs<RelTy> rels) { // TLSDESC relocations: case R_AARCH64_TLSDESC_ADR_PAGE21: - sym.setFlags(NEEDS_TLSDESC_NONAUTH); rs.handleTlsDesc(RE_AARCH64_TLSDESC_PAGE, RE_AARCH64_GOT_PAGE_PC, type, offset, addend, sym); continue; case R_AARCH64_TLSDESC_LD64_LO12: case R_AARCH64_TLSDESC_ADD_LO12: - sym.setFlags(NEEDS_TLSDESC_NONAUTH); rs.handleTlsDesc(R_TLSDESC, R_GOT, type, offset, addend, sym); continue; case R_AARCH64_TLSDESC_CALL: - tlsdescCallRels.push_back({R_TPREL, type, offset, addend, &sym}); + sym.setFlags(NEEDS_TLSDESC_NONAUTH); + if (!ctx.arg.shared) + sec.addReloc({R_TPREL, type, offset, addend, &sym}); continue; // AUTH TLSDESC relocations. Do not optimize to LE/IE because PAUTHELF64 @@ -380,6 +379,11 @@ void AArch64::scanSectionImpl(InputSectionBase &sec, Relocs<RelTy> rels) { case R_AARCH64_AUTH_TLSDESC_ADD_LO12: handleTlsDescAuth(R_TLSDESC); continue; + case R_AARCH64_AUTH_TLSDESC_CALL: + sym.setFlags(NEEDS_TLSDESC_AUTH); + if (sym.isUndefWeak() && !sym.isPreemptible) + sec.addReloc({R_TPREL, type, offset, addend, &sym}); + continue; default: Err(ctx) << getErrorLoc(ctx, sec.content().data() + offset) @@ -390,27 +394,6 @@ void AArch64::scanSectionImpl(InputSectionBase &sec, Relocs<RelTy> rels) { rs.process(expr, type, offset, sym, addend); } - for (const auto &tlsdescCallRel : tlsdescCallRels) { - const Symbol *sym = tlsdescCallRel.sym; - auto flags = sym->flags.load(std::memory_order_relaxed); - - if (flags & NEEDS_TLSDESC_AUTH) { - if (sym->isUndefWeak() && !sym->isPreemptible) - sec.addReloc(tlsdescCallRel); - continue; - } - if (flags & NEEDS_TLSDESC_NONAUTH) { - if (!ctx.arg.shared) - sec.addReloc(tlsdescCallRel); - continue; - } - - Err(ctx) << getErrorLoc(ctx, sec.content().data() + tlsdescCallRel.offset) - << "relocation R_AARCH64_TLSDESC_CALL against '" << sym - << "' requires other TLSDESC or AUTH TLSDESC relocations present " - "against this symbol"; - } - if (ctx.arg.branchToBranch) llvm::stable_sort(sec.relocs(), [](auto &l, auto &r) { return l.offset < r.offset; }); @@ -856,7 +839,7 @@ void AArch64::relaxAuthTlsDescForNonPreemptibleUndefWeak( // adrp x0, :tlsdesc_auth:v [R_AARCH64_AUTH_TLSDESC_ADR_PAGE21] // ldr x16, [x0, :tlsdesc_auth_lo12:v] [R_AARCH64_AUTH_TLSDESC_LD64_LO12] // add x0, x0, :tlsdesc_auth_lo12:v [R_AARCH64_AUTH_TLSDESC_ADD_LO12] - // .tlsdesccall v [R_AARCH64_TLSDESC_CALL] + // .tlsdescauthcall v [R_AARCH64_AUTH_TLSDESC_CALL] // blraa x16, x0 // And it can optimized to: // mov x0, #0x0 @@ -867,7 +850,7 @@ void AArch64::relaxAuthTlsDescForNonPreemptibleUndefWeak( switch (rel.type) { case R_AARCH64_AUTH_TLSDESC_ADD_LO12: case R_AARCH64_AUTH_TLSDESC_LD64_LO12: - case R_AARCH64_TLSDESC_CALL: + case R_AARCH64_AUTH_TLSDESC_CALL: write32le(loc, 0xd503201f); // nop return; case R_AARCH64_AUTH_TLSDESC_ADR_PAGE21: @@ -1130,26 +1113,6 @@ void AArch64::relocateAlloc(InputSection &sec, uint8_t *buf) const { continue; } - auto tryRelaxTlsDesc = [this, &rel, loc, val]() { - assert(rel.sym->hasFlag(NEEDS_TLSDESC_NONAUTH)); - assert(!rel.sym->hasFlag(NEEDS_TLSDESC_AUTH)); - if (rel.expr == R_TPREL) - relaxTlsGdToLe(loc, rel, val); - else if (rel.expr == RE_AARCH64_GOT_PAGE_PC || rel.expr == R_GOT) - relaxTlsGdToIe(loc, rel, val); - else - relocate(loc, rel, val); - }; - - auto tryRelaxTlsDescAuth = [this, &rel, loc, val]() { - assert(!rel.sym->hasFlag(NEEDS_TLSDESC_NONAUTH)); - assert(rel.sym->hasFlag(NEEDS_TLSDESC_AUTH)); - if (rel.expr == R_TPREL) - relaxAuthTlsDescForNonPreemptibleUndefWeak(loc, rel); - else - relocate(loc, rel, val); - }; - switch (rel.type) { case R_AARCH64_ADR_GOT_PAGE: if (i + 1 < size && @@ -1169,18 +1132,22 @@ void AArch64::relocateAlloc(InputSection &sec, uint8_t *buf) const { case R_AARCH64_TLSDESC_ADR_PAGE21: case R_AARCH64_TLSDESC_LD64_LO12: case R_AARCH64_TLSDESC_ADD_LO12: - tryRelaxTlsDesc(); - continue; case R_AARCH64_TLSDESC_CALL: - if (rel.sym->hasFlag(NEEDS_TLSDESC_AUTH)) - tryRelaxTlsDescAuth(); + if (rel.expr == R_TPREL) + relaxTlsGdToLe(loc, rel, val); + else if (rel.expr == RE_AARCH64_GOT_PAGE_PC || rel.expr == R_GOT) + relaxTlsGdToIe(loc, rel, val); else - tryRelaxTlsDesc(); + relocate(loc, rel, val); continue; case R_AARCH64_AUTH_TLSDESC_ADR_PAGE21: case R_AARCH64_AUTH_TLSDESC_LD64_LO12: case R_AARCH64_AUTH_TLSDESC_ADD_LO12: - tryRelaxTlsDescAuth(); + case R_AARCH64_AUTH_TLSDESC_CALL: + if (rel.expr == R_TPREL) + relaxAuthTlsDescForNonPreemptibleUndefWeak(loc, rel); + else + relocate(loc, rel, val); continue; case R_AARCH64_TLSIE_ADR_GOTTPREL_PAGE21: case R_AARCH64_TLSIE_LD64_GOTTPREL_LO12_NC: diff --git a/lld/ELF/RelocScan.h b/lld/ELF/RelocScan.h index 9829cec203261..526482a156ccc 100644 --- a/lld/ELF/RelocScan.h +++ b/lld/ELF/RelocScan.h @@ -159,7 +159,9 @@ class RelocScan { void handleTlsDesc(RelExpr sharedExpr, RelExpr ieExpr, RelType type, uint64_t offset, int64_t addend, Symbol &sym) { if (ctx.arg.shared) { - sym.setFlags(NEEDS_TLSDESC); + // NEEDS_TLSDESC_NONAUTH is a no-op for non-AArch64 targets and detects + // incompatibility with NEEDS_TLSDESC_AUTH. + sym.setFlags(NEEDS_TLSDESC | NEEDS_TLSDESC_NONAUTH); sec->addReloc({sharedExpr, type, offset, addend, &sym}); } else if (sym.isPreemptible) { // Optimize to Initial Exec. diff --git a/lld/test/ELF/aarch64-reloc-pauth-undef-weak-dso.s b/lld/test/ELF/aarch64-reloc-pauth-undef-weak-dso.s index 3080d5cef9eca..0346f45992381 100644 --- a/lld/test/ELF/aarch64-reloc-pauth-undef-weak-dso.s +++ b/lld/test/ELF/aarch64-reloc-pauth-undef-weak-dso.s @@ -37,7 +37,7 @@ _start: adrp x0, :tlsdesc_auth:undef ldr x16, [x0, :tlsdesc_auth_lo12:undef] add x0, x0, :tlsdesc_auth_lo12:undef - .tlsdesccall undef + .tlsdescauthcall undef blraa x16, x0 .data diff --git a/lld/test/ELF/aarch64-reloc-pauth-undef-weak-pie.s b/lld/test/ELF/aarch64-reloc-pauth-undef-weak-pie.s index bec858d2ea7c9..fa168317a50de 100644 --- a/lld/test/ELF/aarch64-reloc-pauth-undef-weak-pie.s +++ b/lld/test/ELF/aarch64-reloc-pauth-undef-weak-pie.s @@ -36,7 +36,7 @@ _start: adrp x0, :tlsdesc_auth:undef ldr x16, [x0, :tlsdesc_auth_lo12:undef] add x0, x0, :tlsdesc_auth_lo12:undef - .tlsdesccall undef + .tlsdescauthcall undef blraa x16, x0 .data diff --git a/lld/test/ELF/aarch64-reloc-pauth-undef-weak.s b/lld/test/ELF/aarch64-reloc-pauth-undef-weak.s index 44995654909bf..a5ae1e919e992 100644 --- a/lld/test/ELF/aarch64-reloc-pauth-undef-weak.s +++ b/lld/test/ELF/aarch64-reloc-pauth-undef-weak.s @@ -37,7 +37,7 @@ _start: adrp x0, :tlsdesc_auth:undef ldr x16, [x0, :tlsdesc_auth_lo12:undef] add x0, x0, :tlsdesc_auth_lo12:undef - .tlsdesccall undef + .tlsdescauthcall undef blraa x16, x0 .data diff --git a/lld/test/ELF/aarch64-tlsdesc-pauth.s b/lld/test/ELF/aarch64-tlsdesc-pauth.s index b5f818cf60567..41c7b31b5a7e6 100644 --- a/lld/test/ELF/aarch64-tlsdesc-pauth.s +++ b/lld/test/ELF/aarch64-tlsdesc-pauth.s @@ -27,7 +27,7 @@ a: adrp x0, :tlsdesc_auth:a ldr x16, [x0, :tlsdesc_auth_lo12:a] add x0, x0, :tlsdesc_auth_lo12:a - .tlsdesccall a + .tlsdescauthcall a blraa x16, x0 // CHECK: adrp x0, 0x[[P]]000 @@ -42,7 +42,7 @@ a: adrp x0, :tlsdesc_auth:local1 ldr x16, [x0, :tlsdesc_auth_lo12:local1] add x0, x0, :tlsdesc_auth_lo12:local1 - .tlsdesccall local1 + .tlsdescauthcall local1 blraa x16, x0 // CHECK: adrp x0, 0x[[P]]000 @@ -53,7 +53,7 @@ a: adrp x0, :tlsdesc_auth:local2 ldr x16, [x0, :tlsdesc_auth_lo12:local2] add x0, x0, :tlsdesc_auth_lo12:local2 - .tlsdesccall local2 + .tlsdescauthcall local2 blraa x16, x0 // CHECK: adrp x0, 0x[[P]]000 @@ -109,7 +109,7 @@ local2: adrp x0, :tlsdesc:a ldr x1, [x0, :tlsdesc_lo12:a] add x0, x0, :tlsdesc_lo12:a - .tlsdesccall a + .tlsdescauthcall a blr x1 //--- err2.s @@ -126,13 +126,16 @@ local2: adrp x0, :tlsdesc_auth:a ldr x16, [x0, :tlsdesc_auth_lo12:a] add x0, x0, :tlsdesc_auth_lo12:a - .tlsdesccall a + .tlsdescauthcall 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: err3.o:(.text+0x0): relocation R_AARCH64_TLSDESC_CALL against 'a' requires other TLSDESC or AUTH TLSDESC relocations present against this symbol +// 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 _______________________________________________ llvm-branch-commits mailing list [email protected] https://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-branch-commits
