[lld] [PAC][lld] Do not emit AUTH relocs against undef weak non-preemptible symbols (PR #194636)

Daniil Kovalev via llvm-commits llvm-commits at lists.llvm.org
Tue Apr 28 07:03:34 PDT 2026


https://github.com/kovdan01 created https://github.com/llvm/llvm-project/pull/194636

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

>From 56a1e5138e0d9c09467374189a3ac35eb649241c Mon Sep 17 00:00:00 2001
From: Daniil Kovalev <dkovalev at accesssoftek.com>
Date: Tue, 28 Apr 2026 15:54:49 +0300
Subject: [PATCH] [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                      | 21 +++++++---
 lld/ELF/Relocations.cpp                       | 19 ++++++---
 lld/ELF/SyntheticSections.cpp                 | 20 +++++++---
 lld/ELF/SyntheticSections.h                   |  3 +-
 .../ELF/aarch64-reloc-pauth-undef-weak-dso.s  | 39 +++++++++++++++++++
 .../ELF/aarch64-reloc-pauth-undef-weak-pie.s  | 38 ++++++++++++++++++
 lld/test/ELF/aarch64-reloc-pauth-undef-weak.s | 38 ++++++++++++++++++
 7 files changed, 161 insertions(+), 17 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..755a3e0513209 100644
--- a/lld/ELF/Arch/AArch64.cpp
+++ b/lld/ELF/Arch/AArch64.cpp
@@ -645,11 +645,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);
diff --git a/lld/ELF/Relocations.cpp b/lld/ELF/Relocations.cpp
index 7b4d7217e0452..1632446f472ba 100644
--- a/lld/ELF/Relocations.cpp
+++ b/lld/ELF/Relocations.cpp
@@ -790,9 +790,12 @@ static void addGotAuthEntry(Ctx &ctx, Symbol &sym) {
     return;
   }
 
-  // Signed GOT requires dynamic relocation.
-  ctx.in.got->getPartition(ctx).relaDyn->addReloc(
-      {R_AARCH64_AUTH_RELATIVE, ctx.in.got.get(), off, false, sym, 0, R_ABS});
+  // Signed GOT requires a dynamic relocation unless the symbol is
+  // non-preemptible and undefined weak.
+  if (!sym.isUndefWeak()) {
+    ctx.in.got->getPartition(ctx).relaDyn->addReloc(
+        {R_AARCH64_AUTH_RELATIVE, ctx.in.got.get(), off, false, sym, 0, R_ABS});
+  }
 }
 
 static void addTpOffsetGotEntry(Ctx &ctx, Symbol &sym) {
@@ -852,8 +855,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.
@@ -1367,7 +1374,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.mainPart->relaDyn->addAddendOnlyRelocIfNonPreemptible(
diff --git a/lld/ELF/SyntheticSections.cpp b/lld/ELF/SyntheticSections.cpp
index 3c08c392ff214..3c5b175735725 100644
--- a/lld/ELF/SyntheticSections.cpp
+++ b/lld/ELF/SyntheticSections.cpp
@@ -508,7 +508,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) {
@@ -518,9 +520,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) {
@@ -579,6 +584,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
@@ -588,7 +599,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 92dcbb922aa58..f9d561c494811 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..af1d4f0e9ee5d
--- /dev/null
+++ b/lld/test/ELF/aarch64-reloc-pauth-undef-weak-dso.s
@@ -0,0 +1,39 @@
+# REQUIRES: aarch64
+# RUN: llvm-mc -filetype=obj -triple=aarch64 %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:  0x000302f0 00000000 00000000 25000000 00000000
+# DATA-NEXT:  0x00030300 00000000 00000000 25000000 00000000
+
+# GOT-LABEL:  Hex dump of section '.got':
+# GOT-NEXT:   0x000202e8 00000000 00000000
+
+# DIS-LABEL:  <_start>:
+# DIS-NEXT:     adrp x0, 0x20000
+# DIS-NEXT:     ldr  x0, [x0, #0x2e8]
+
+.weak undef
+.hidden undef
+
+.globl _start
+_start:
+  adrp x0, :got_auth:undef
+  ldr x0, [x0, :got_auth_lo12:undef]
+
+.data
+foo:
+.quad undef at 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..f2d2cd37496ad
--- /dev/null
+++ b/lld/test/ELF/aarch64-reloc-pauth-undef-weak-pie.s
@@ -0,0 +1,38 @@
+# REQUIRES: aarch64
+# RUN: llvm-mc -filetype=obj -triple=aarch64 %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:  0x000302e8 00000000 00000000 25000000 00000000
+# DATA-NEXT:  0x000302f8 00000000 00000000 25000000 00000000
+
+# GOT-LABEL:  Hex dump of section '.got':
+# GOT-NEXT:   0x000202e0 00000000 00000000
+
+# DIS-LABEL:  <_start>:
+# DIS-NEXT:     adrp x0, 0x20000
+# DIS-NEXT:     ldr  x0, [x0, #0x2e0]
+
+.weak undef
+
+.globl _start
+_start:
+  adrp x0, :got_auth:undef
+  ldr x0, [x0, :got_auth_lo12:undef]
+
+.data
+foo:
+.quad undef at 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..e6948af53a005
--- /dev/null
+++ b/lld/test/ELF/aarch64-reloc-pauth-undef-weak.s
@@ -0,0 +1,38 @@
+# REQUIRES: aarch64
+# RUN: llvm-mc -filetype=obj -triple=aarch64 %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:  0x002301d8 00000000 00000000 25000000 00000000
+# DATA-NEXT:  0x002301e8 00000000 00000000 25000000 00000000
+
+# GOT-LABEL:  Hex dump of section '.got':
+# GOT-NEXT:   0x002201d0 00000000 00000000
+
+# DIS-LABEL:  <_start>:
+# DIS-NEXT:     adrp x0, 0x220000
+# DIS-NEXT:     ldr  x0, [x0, #0x1d0]
+
+.weak undef
+
+.globl _start
+_start:
+  adrp x0, :got_auth:undef
+  ldr x0, [x0, :got_auth_lo12:undef]
+
+.data
+foo:
+.quad undef at AUTH(da,42)
+.quad (undef + 37)@AUTH(da,42)
+.quad undef
+.quad undef + 37



More information about the llvm-commits mailing list