Skip to content

[ELF][AArch64][PAC][MTE] Handle Memtag globals for R_AARCH64_AUTH_ABS64#173291

Merged
jrtc27 merged 4 commits intomainfrom
users/jrtc27/spr/elfaarch64pacmte-handle-memtag-globals-for-r_aarch64_auth_abs64
Jan 31, 2026
Merged

[ELF][AArch64][PAC][MTE] Handle Memtag globals for R_AARCH64_AUTH_ABS64#173291
jrtc27 merged 4 commits intomainfrom
users/jrtc27/spr/elfaarch64pacmte-handle-memtag-globals-for-r_aarch64_auth_abs64

Conversation

@jrtc27
Copy link
Copy Markdown
Collaborator

@jrtc27 jrtc27 commented Dec 22, 2025

Currently, R_AARCH64_AUTH_ABS64 against a tagged global just ignores the
tagging and so, if out of the symbol's bounds, does not write the
negated original addend for the loader to determine which granule's tag
to use for it. Handle the composition of the two.

Note that R_AARCH64_AUTH_ABS64/RELATIVE encode the signing schema in the
upper 32 bits of the value at the relocation target, and so only the
lower 32 bits are available for use as an addend, including for Memtag's
disambiguation, and so if a wildly out-of-bounds PAuth relocation
against a tagged global is used we have no choice but to error out with
the current ABI.

Created using spr 1.3.5
@llvmbot
Copy link
Copy Markdown
Member

llvmbot commented Dec 22, 2025

@llvm/pr-subscribers-lld

Author: Jessica Clarke (jrtc27)

Changes

Currently, R_AARCH64_AUTH_ABS64 against a tagged global just ignores the
tagging and so, if out of the symbol's bounds, does not write the
negated original addend for the loader to determine which granule's tag
to use for it. Handle the composition of the two.

Note that R_AARCH64_AUTH_ABS64/RELATIVE encode the signing schema in the
upper 32 bits of the value at the relocation target, and so only the
lower 32 bits are available for use as an addend, including for Memtag's
disambiguation, and so if a wildly out-of-bounds PAuth relocation
against a tagged global is used we have no choice but to error out with
the current ABI.


Full diff: https://github.com/llvm/llvm-project/pull/173291.diff

3 Files Affected:

  • (modified) lld/ELF/Relocations.cpp (+6-1)
  • (added) lld/test/ELF/aarch64-memtag-pauth-globals-out-of-range.s (+24)
  • (added) lld/test/ELF/aarch64-memtag-pauth-globals.s (+27)
diff --git a/lld/ELF/Relocations.cpp b/lld/ELF/Relocations.cpp
index d60216da2b03f..dc1c6f24d4a63 100644
--- a/lld/ELF/Relocations.cpp
+++ b/lld/ELF/Relocations.cpp
@@ -1005,9 +1005,11 @@ void RelocScan::process(RelExpr expr, RelType type, uint64_t offset,
       // For a preemptible symbol, we can't use a relative relocation. For an
       // undefined symbol, we can't compute offset at link-time and use a
       // relative relocation. Use a symbolic relocation instead.
+      // Handle the composition with Memtag like addRelativeReloc.
       if (ctx.arg.emachine == EM_AARCH64 && type == R_AARCH64_AUTH_ABS64 &&
           !sym.isPreemptible) {
-        if (part.relrAuthDyn && sec->addralign >= 2 && offset % 2 == 0) {
+        if (!sym.isTagged() && part.relrAuthDyn && sec->addralign >= 2 &&
+            offset % 2 == 0) {
           // When symbol values are determined in
           // finalizeAddressDependentContent, some .relr.auth.dyn relocations
           // may be moved to .rela.dyn.
@@ -1016,6 +1018,9 @@ void RelocScan::process(RelExpr expr, RelType type, uint64_t offset,
         } else {
           part.relaDyn->addReloc({R_AARCH64_AUTH_RELATIVE, sec, offset, false,
                                   sym, addend, R_ABS});
+          if (sym.isTagged() &&
+              (addend < 0 || static_cast<uint64_t>(addend) >= sym.getSize()))
+            sec->addReloc({R_ADDEND_NEG, type, offset, addend, &sym});
         }
         return;
       }
diff --git a/lld/test/ELF/aarch64-memtag-pauth-globals-out-of-range.s b/lld/test/ELF/aarch64-memtag-pauth-globals-out-of-range.s
new file mode 100644
index 0000000000000..c786d52a7ec1e
--- /dev/null
+++ b/lld/test/ELF/aarch64-memtag-pauth-globals-out-of-range.s
@@ -0,0 +1,24 @@
+# REQUIRES: aarch64
+# RUN: llvm-mc -filetype=obj -triple=aarch64-linux-android %s -o %t.o
+# RUN: not ld.lld --shared --android-memtag-mode=sync %t.o -o /dev/null 2>&1 | \
+# RUN:   FileCheck %s --implicit-check-not=error:
+
+## Verify that, when composing PAuth and Memtag ABIs, we error if trying to
+## emit an R_AARCH64_AUTH_RELATIVE for a tagged global using an original addend
+## that's not within the bounds of the symbol and, when negated, does not fit
+## in a signed 32-bit integer, since the signing schema uses the upper 32 bits.
+
+# CHECK: error: {{.*}}aarch64-memtag-pauth-globals-out-of-range.s.tmp.o:(.data+0x0): relocation R_AARCH64_AUTH_ABS64 out of range: 2147483648 is not in [-2147483648, 2147483647]; references 'foo'
+# CHECK: error: {{.*}}aarch64-memtag-pauth-globals-out-of-range.s.tmp.o:(.data+0x8): relocation R_AARCH64_AUTH_ABS64 out of range: -2147483649 is not in [-2147483648, 2147483647]; references 'foo'
+
+.data
+.balign 16
+.memtag foo
+.type foo, @object
+foo:
+.quad (foo - 0x80000000)@AUTH(da,42)
+.quad (foo + 0x80000001)@AUTH(da,42)
+## These are just in bounds
+.quad (foo - 0x7fffffff)@AUTH(da,42)
+.quad (foo + 0x80000000)@AUTH(da,42)
+.size foo, 32
diff --git a/lld/test/ELF/aarch64-memtag-pauth-globals.s b/lld/test/ELF/aarch64-memtag-pauth-globals.s
new file mode 100644
index 0000000000000..2b468cbbb76c6
--- /dev/null
+++ b/lld/test/ELF/aarch64-memtag-pauth-globals.s
@@ -0,0 +1,27 @@
+# REQUIRES: aarch64
+# RUN: llvm-mc -filetype=obj -triple=aarch64-linux-android %s -o %t.o
+# RUN: ld.lld --shared --android-memtag-mode=sync %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
+
+## Verify that, when composing PAuth and Memtag ABIs, R_AARCH64_AUTH_RELATIVE
+## relocations follow R_AARCH64_RELATIVE in emitting the (negated) original
+## addend at the relocated target for tagged globals when not within the
+## symbol's bounds.
+
+# RELA-LABEL: .rela.dyn {
+# RELA-NEXT:    0x303C0 R_AARCH64_AUTH_RELATIVE - 0x303BF
+# RELA-NEXT:    0x303C8 R_AARCH64_AUTH_RELATIVE - 0x303D0
+# RELA-NEXT:  }
+
+# DATA-LABEL: Hex dump of section '.data':
+# DATA-NEXT:  0x000303c0 01000000 2a000020 f0ffffff 2a000020
+
+.data
+.balign 16
+.memtag foo
+.type foo, @object
+foo:
+.quad (foo - 1)@AUTH(da,42)
+.quad (foo + 16)@AUTH(da,42)
+.size foo, 16

@llvmbot
Copy link
Copy Markdown
Member

llvmbot commented Dec 22, 2025

@llvm/pr-subscribers-lld-elf

Author: Jessica Clarke (jrtc27)

Changes

Currently, R_AARCH64_AUTH_ABS64 against a tagged global just ignores the
tagging and so, if out of the symbol's bounds, does not write the
negated original addend for the loader to determine which granule's tag
to use for it. Handle the composition of the two.

Note that R_AARCH64_AUTH_ABS64/RELATIVE encode the signing schema in the
upper 32 bits of the value at the relocation target, and so only the
lower 32 bits are available for use as an addend, including for Memtag's
disambiguation, and so if a wildly out-of-bounds PAuth relocation
against a tagged global is used we have no choice but to error out with
the current ABI.


Full diff: https://github.com/llvm/llvm-project/pull/173291.diff

3 Files Affected:

  • (modified) lld/ELF/Relocations.cpp (+6-1)
  • (added) lld/test/ELF/aarch64-memtag-pauth-globals-out-of-range.s (+24)
  • (added) lld/test/ELF/aarch64-memtag-pauth-globals.s (+27)
diff --git a/lld/ELF/Relocations.cpp b/lld/ELF/Relocations.cpp
index d60216da2b03f..dc1c6f24d4a63 100644
--- a/lld/ELF/Relocations.cpp
+++ b/lld/ELF/Relocations.cpp
@@ -1005,9 +1005,11 @@ void RelocScan::process(RelExpr expr, RelType type, uint64_t offset,
       // For a preemptible symbol, we can't use a relative relocation. For an
       // undefined symbol, we can't compute offset at link-time and use a
       // relative relocation. Use a symbolic relocation instead.
+      // Handle the composition with Memtag like addRelativeReloc.
       if (ctx.arg.emachine == EM_AARCH64 && type == R_AARCH64_AUTH_ABS64 &&
           !sym.isPreemptible) {
-        if (part.relrAuthDyn && sec->addralign >= 2 && offset % 2 == 0) {
+        if (!sym.isTagged() && part.relrAuthDyn && sec->addralign >= 2 &&
+            offset % 2 == 0) {
           // When symbol values are determined in
           // finalizeAddressDependentContent, some .relr.auth.dyn relocations
           // may be moved to .rela.dyn.
@@ -1016,6 +1018,9 @@ void RelocScan::process(RelExpr expr, RelType type, uint64_t offset,
         } else {
           part.relaDyn->addReloc({R_AARCH64_AUTH_RELATIVE, sec, offset, false,
                                   sym, addend, R_ABS});
+          if (sym.isTagged() &&
+              (addend < 0 || static_cast<uint64_t>(addend) >= sym.getSize()))
+            sec->addReloc({R_ADDEND_NEG, type, offset, addend, &sym});
         }
         return;
       }
diff --git a/lld/test/ELF/aarch64-memtag-pauth-globals-out-of-range.s b/lld/test/ELF/aarch64-memtag-pauth-globals-out-of-range.s
new file mode 100644
index 0000000000000..c786d52a7ec1e
--- /dev/null
+++ b/lld/test/ELF/aarch64-memtag-pauth-globals-out-of-range.s
@@ -0,0 +1,24 @@
+# REQUIRES: aarch64
+# RUN: llvm-mc -filetype=obj -triple=aarch64-linux-android %s -o %t.o
+# RUN: not ld.lld --shared --android-memtag-mode=sync %t.o -o /dev/null 2>&1 | \
+# RUN:   FileCheck %s --implicit-check-not=error:
+
+## Verify that, when composing PAuth and Memtag ABIs, we error if trying to
+## emit an R_AARCH64_AUTH_RELATIVE for a tagged global using an original addend
+## that's not within the bounds of the symbol and, when negated, does not fit
+## in a signed 32-bit integer, since the signing schema uses the upper 32 bits.
+
+# CHECK: error: {{.*}}aarch64-memtag-pauth-globals-out-of-range.s.tmp.o:(.data+0x0): relocation R_AARCH64_AUTH_ABS64 out of range: 2147483648 is not in [-2147483648, 2147483647]; references 'foo'
+# CHECK: error: {{.*}}aarch64-memtag-pauth-globals-out-of-range.s.tmp.o:(.data+0x8): relocation R_AARCH64_AUTH_ABS64 out of range: -2147483649 is not in [-2147483648, 2147483647]; references 'foo'
+
+.data
+.balign 16
+.memtag foo
+.type foo, @object
+foo:
+.quad (foo - 0x80000000)@AUTH(da,42)
+.quad (foo + 0x80000001)@AUTH(da,42)
+## These are just in bounds
+.quad (foo - 0x7fffffff)@AUTH(da,42)
+.quad (foo + 0x80000000)@AUTH(da,42)
+.size foo, 32
diff --git a/lld/test/ELF/aarch64-memtag-pauth-globals.s b/lld/test/ELF/aarch64-memtag-pauth-globals.s
new file mode 100644
index 0000000000000..2b468cbbb76c6
--- /dev/null
+++ b/lld/test/ELF/aarch64-memtag-pauth-globals.s
@@ -0,0 +1,27 @@
+# REQUIRES: aarch64
+# RUN: llvm-mc -filetype=obj -triple=aarch64-linux-android %s -o %t.o
+# RUN: ld.lld --shared --android-memtag-mode=sync %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
+
+## Verify that, when composing PAuth and Memtag ABIs, R_AARCH64_AUTH_RELATIVE
+## relocations follow R_AARCH64_RELATIVE in emitting the (negated) original
+## addend at the relocated target for tagged globals when not within the
+## symbol's bounds.
+
+# RELA-LABEL: .rela.dyn {
+# RELA-NEXT:    0x303C0 R_AARCH64_AUTH_RELATIVE - 0x303BF
+# RELA-NEXT:    0x303C8 R_AARCH64_AUTH_RELATIVE - 0x303D0
+# RELA-NEXT:  }
+
+# DATA-LABEL: Hex dump of section '.data':
+# DATA-NEXT:  0x000303c0 01000000 2a000020 f0ffffff 2a000020
+
+.data
+.balign 16
+.memtag foo
+.type foo, @object
+foo:
+.quad (foo - 1)@AUTH(da,42)
+.quad (foo + 16)@AUTH(da,42)
+.size foo, 16

Copy link
Copy Markdown
Collaborator

@smithp35 smithp35 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think this looks like the most reasonable combination of PAuth and Memtag for relative relocations. As long as the PAuthABI team are happy I'm OK with this. The alternative is to just error out until someone has a need to combine the two extensions.

We don't yet have anything documented on the PAuthABI or MemtagABI about the combination of the two ABIs.

I think the description for the resulting dynamic relocations would be (using syntax from https://github.com/ARM-software/abi-aa/blob/main/memtagabielf64/memtagabielf64.rst#84relocation-operations)

LDG is defined as:

  • LDG(pointer) is an instruction for the run-time environment to use the ldg instruction on pointer to materialize the correct logical tag for a symbol. This operation should also align the pointer down to the closest tag granule before executing the ldg instruction.
  • For all the relocation types listed below, the loader should use the ldg instruction on the target address before writing into the target field, as the target field may be inside of a tagged region.
ELF64 Code Name PAuthABI Base Operation MemtagABI Extended Operation
0x244 (580) R_AARCH64_AUTH_ABS64 SIGN((S + A), SCHEMA(*P)) SIGN((LDG(S) + A), SCHEMA(*P))
0x411 (1041) R_AARCH64_AUTH_RELATIVE SIGN(DELTA(S) + A, SCHEMA(*P)) SIGN((LDG(Delta(S) + A + *P) - *P, SCHEMA(*P))
0x412 (1042) R_AARCH64_AUTH_GLOB_DAT SIGN((S + A), SCHEMA(*P)) SIGN((LDG(S) + A), SCHEMA(*P))

SIGN and LDG operate on separate subsets of the top byte. I've put LDG first to cover the second bullet, and to make it easier to write the operation for the R_AARCH64_AUTH_RELATIVE.

If that sounds reasonable I can add that to the PAuthABI documentation as an appendix.

@jrtc27
Copy link
Copy Markdown
Collaborator Author

jrtc27 commented Jan 8, 2026

LDG(Delta(S) + A + *P) - *P

The *Ps here should have some function like SIGN to extract the low 32 bits normally used for a REL(R) addend.

PAuthABI also has the following for AUTH_RELATIVE talking about "reserved for addend":

It must be set to 0 if not used for an addend.

Probably should have a sentence here to explicitly override that?

@smithp35
Copy link
Copy Markdown
Collaborator

smithp35 commented Jan 8, 2026

LDG(Delta(S) + A + *P) - *P

The *Ps here should have some function like SIGN to extract the low 32 bits normally used for a REL(R) addend.

Thanks for the suggestion. I expect it would be something like:

  • ADDEND(*P) represents the dynamic linker reading the addend field from the contents of the place P

The R_AARCH64_AUTH_RELATIVE entry would then be:
SIGN((LDG(Delta(S) + A + ADDEND(*P)) - ADDEND(*P), SCHEMA(*P))

PAuthABI also has the following for AUTH_RELATIVE talking about "reserved for addend":

It must be set to 0 if not used for an addend.

Probably should have a sentence here to explicitly override that?

Yes, I could mention that the addend field can be used by the memtagabi extension.

@jrtc27
Copy link
Copy Markdown
Collaborator Author

jrtc27 commented Jan 8, 2026

Both sound good to me. ADDEND has a bit of a potential for confusion for A / r_addend, but given it takes an explicit argument of *P, and used alongside A, that should be a clear enough signal that it's something different. Could have a , distinct from ``A``, the addend coming from the RELA-type relocation or similar if you want to make it clearer.

@jrtc27
Copy link
Copy Markdown
Collaborator Author

jrtc27 commented Jan 29, 2026

@smithp35 Ping?

@smithp35
Copy link
Copy Markdown
Collaborator

@smithp35 Ping?

I don't have any more comments on the implementation. I was hoping to see if there were any comments from other reviewers.

I'll hopefully have some time next week to make a PR for the ABI. My apologies, I've not found time to do that yet.

As there's not been any objections. I'll mark this approved. Please leave a few days for other reviewers to object.

Copy link
Copy Markdown
Collaborator

@smithp35 smithp35 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I've marked approved on my side as I think this is the obvious way for MTE and PAuthABI to coexist. The use case in the memtag ABI for an addend larger than 32-bits seems extremely unlikey. If there is a need for that we can work out another mechanism.

@jrtc27
Copy link
Copy Markdown
Collaborator Author

jrtc27 commented Jan 30, 2026

No worries. I wasn't sure if this was blocked on the ABI spec change or not.

localspook and others added 2 commits January 31, 2026 18:06
Created using spr 1.3.5

[skip ci]
Created using spr 1.3.5
@jrtc27 jrtc27 changed the base branch from users/jrtc27/spr/main.elfaarch64pacmte-handle-memtag-globals-for-r_aarch64_auth_abs64 to main January 31, 2026 18:06
@jrtc27 jrtc27 merged commit 859d3b8 into main Jan 31, 2026
8 of 16 checks passed
@jrtc27 jrtc27 deleted the users/jrtc27/spr/elfaarch64pacmte-handle-memtag-globals-for-r_aarch64_auth_abs64 branch January 31, 2026 18:06
llvm-sync Bot pushed a commit to arm/arm-toolchain that referenced this pull request Jan 31, 2026
…64_AUTH_ABS64

Currently, R_AARCH64_AUTH_ABS64 against a tagged global just ignores the
tagging and so, if out of the symbol's bounds, does not write the
negated original addend for the loader to determine which granule's tag
to use for it. Handle the composition of the two.

Note that R_AARCH64_AUTH_ABS64/RELATIVE encode the signing schema in the
upper 32 bits of the value at the relocation target, and so only the
lower 32 bits are available for use as an addend, including for Memtag's
disambiguation, and so if a wildly out-of-bounds PAuth relocation
against a tagged global is used we have no choice but to error out with
the current ABI.

Reviewers: MaskRay, kovdan01, smithp35, asl

Reviewed By: smithp35

Pull Request: llvm/llvm-project#173291
smithp35 added a commit to smithp35/abi-aa that referenced this pull request Feb 6, 2026
The PAuthABI introduces some new dynamic relocations and the
MemtagABI adds additional semantics to existing core dynamic
relocations.

The additional semantics for MemtagABI can be applied to the
new PAuthABI dynamic relocations. In most cases the extension
is natural as the LDG and SIGN operations operate on different
bits in the pointer and can apply in either order.

Both the MemtagABI and the PAuthABI require additional metadata
for the R_AARCH64_AUTH_RELATIVE relocation which is stored in the
place of the relocation. The MemtagABI stores
an additional addend compensator so that the dynamic linker can
derive the start address of the datatype so that it can materialize
the correct tag. The PAuthABI stores the signing schema, including
an addend field which contains the relocation addend when RELR
compression is used. As the MemtagABI excludes any relocations with
an addend compensator from RELR compression, and PAuthABI requires
the addend field in the signing schema to be 0 when RELR compression
is not used; we can use the signing schema addend field for the
Memtag addend compensator.

Document the relocation operators and how the MemtagABI applies
to the PAuthABI relocations.

This behaviour was implemented in LLD PR
llvm/llvm-project#173291
@smithp35
Copy link
Copy Markdown
Collaborator

smithp35 commented Feb 6, 2026

ABI pr to document MemtagABI and PAuthABI interoperation at ARM-software/abi-aa#366

smithp35 added a commit to ARM-software/abi-aa that referenced this pull request Feb 10, 2026
…366)

The PAuthABI introduces some new dynamic relocations and the MemtagABI
adds additional semantics to existing core dynamic relocations.

The additional semantics for MemtagABI can be applied to the new
PAuthABI dynamic relocations. In most cases the extension is natural as
the LDG and SIGN operations operate on different bits in the pointer and
can apply in either order.

Both the MemtagABI and the PAuthABI require additional metadata for the
R_AARCH64_AUTH_RELATIVE relocation which is stored in the place of the
relocation. The MemtagABI stores
an additional addend compensator so that the dynamic linker can derive
the start address of the datatype so that it can materialize the correct
tag. The PAuthABI stores the signing schema, including an addend field
which contains the relocation addend when RELR compression is used. As
the MemtagABI excludes any relocations with an addend compensator from
RELR compression, and PAuthABI requires the addend field in the signing
schema to be 0 when RELR compression is not used; we can use the signing
schema addend field for the Memtag addend compensator.

Document the relocation operators and how the MemtagABI applies to the
PAuthABI relocations.

This behaviour was implemented in LLD PR
llvm/llvm-project#173291
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants