-
Notifications
You must be signed in to change notification settings - Fork 15.7k
[ELF][AArch64][PAC][MTE] Handle Memtag globals for R_AARCH64_AUTH_ABS64 #173291
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: users/jrtc27/spr/main.elfaarch64pacmte-handle-memtag-globals-for-r_aarch64_auth_abs64
Are you sure you want to change the base?
Conversation
Created using spr 1.3.5
|
@llvm/pr-subscribers-lld Author: Jessica Clarke (jrtc27) ChangesCurrently, R_AARCH64_AUTH_ABS64 against a tagged global just ignores the Note that R_AARCH64_AUTH_ABS64/RELATIVE encode the signing schema in the Full diff: https://github.com/llvm/llvm-project/pull/173291.diff 3 Files Affected:
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
|
|
@llvm/pr-subscribers-lld-elf Author: Jessica Clarke (jrtc27) ChangesCurrently, R_AARCH64_AUTH_ABS64 against a tagged global just ignores the Note that R_AARCH64_AUTH_ABS64/RELATIVE encode the signing schema in the Full diff: https://github.com/llvm/llvm-project/pull/173291.diff 3 Files Affected:
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
|
smithp35
left a comment
There was a problem hiding this 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.
The PAuthABI also has the following for AUTH_RELATIVE talking about "reserved for addend":
Probably should have a sentence here to explicitly override that? |
Thanks for the suggestion. I expect it would be something like:
The R_AARCH64_AUTH_RELATIVE entry would then be:
Yes, I could mention that the addend field can be used by the memtagabi extension. |
|
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 |
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.