[RFC, V3 4/5] ld/aarch64elf: add support for DT_AARCH64_MEMTAG_MODE dynamic tag
Indu Bhagat
indu.bhagat@oracle.com
Wed Jun 4 23:25:54 GMT 2025
Add new command line option -z memtag-mode=<mode> to aarch64 elf,
where <mode> can be one of none, sync, or async. For mode of sync or
async, a DT_AARCH64_MEMTAG_MODE dynamic tag with a value of 0 or 1
respectively is emitted.
readelf displays the dynamic tag when present:
$ readelf -d <exectutable>
Dynamic section at offset 0xfdd8 contains XX entries:
Tag Type Name/Value
0x0000000000000001 (NEEDED) Shared library: [libc.so.6]
0x000000000000000c (INIT) 0x400520
0x000000000000000d (FINI) 0x400b64
0x0000000000000019 (INIT_ARRAY) 0x41fdc8
... ... ...
0x0000000070000009 (AARCH64_MEMTAG_MODE) 0x1
... ... ...
[Note/FIXME: Asymm is an Armv8.7 extension to MTE; it is a mode of
operation that provides synchronous checking on memory reads, and
asynchronous checking of memory writes. Its not clear if and how the
toolchain (likely the compiler?) can do some sanity checking of whether
asymm is allowed. E.g., asymm should be disallowed with Armv8.5a ?
Further the MemtagABI does not yet define a constant for the asymm mode
value for DT_AARCH64_MEMTAG_MODE.]
The patch skips adding support for asymm altogether ATM.
ChangeLog:
* bfd/elfnn-aarch64.c (struct elf_aarch64_link_hash_table): Add
new member for memtag properties.
(bfd_elfNN_aarch64_set_options): New argument to pass memtag
properties.
(elfNN_aarch64_late_size_sections): Emit DT_AARCH64_MEMTAG_MODE
dynamic tag.
* bfd/elfxx-aarch64.h: New definition for the various memtag
properties.
* binutils/readelf.c (get_aarch64_dynamic_type): Handle
DT_AARCH64_MEMTAG_MODE.
* ld/emultempl/aarch64elf.em: Likewise.
* ld/ld.texi: Add documentation for the new option
-z memtag-mode.
* ld/testsuite/ld-aarch64/aarch64-elf.exp: New test.
* ld/testsuite/ld-aarch64/dt-memtag.d: New test.
* ld/testsuite/ld-aarch64/dt-memtag-mode.s: New test.
include/ChangeLog:
* elf/aarch64.h (DT_AARCH64_MEMTAG_MODE): New definition.
---
[Changes in V3]
- Adjusted the commit log a bit.
- Adjust code comments a bit. Removed the 'FIXME - what about
asymm?'.
- Updated the description of enum aarch64_memtag_mode_type.
[End of changes in V3]
---
bfd/elfnn-aarch64.c | 14 +++++++-
bfd/elfxx-aarch64.h | 26 +++++++++++++--
binutils/readelf.c | 2 ++
include/elf/aarch64.h | 1 +
ld/emultempl/aarch64elf.em | 42 +++++++++++++++++++++++-
ld/ld.texi | 9 +++++
ld/testsuite/ld-aarch64/aarch64-elf.exp | 1 +
ld/testsuite/ld-aarch64/dt-memtag-mode.d | 7 ++++
ld/testsuite/ld-aarch64/dt-memtag.s | 7 ++++
9 files changed, 105 insertions(+), 4 deletions(-)
create mode 100644 ld/testsuite/ld-aarch64/dt-memtag-mode.d
create mode 100644 ld/testsuite/ld-aarch64/dt-memtag.s
diff --git a/bfd/elfnn-aarch64.c b/bfd/elfnn-aarch64.c
index 548da1f8b30..89f4e26245e 100644
--- a/bfd/elfnn-aarch64.c
+++ b/bfd/elfnn-aarch64.c
@@ -2619,6 +2619,9 @@ struct elf_aarch64_link_hash_table
/* Don't apply link-time values for dynamic relocations. */
int no_apply_dynamic_relocs;
+ /* Memtag Extension mode of operation. */
+ aarch64_memtag_opts memtag_opts;
+
/* The number of bytes in the initial entry in the PLT. */
bfd_size_type plt_header_size;
@@ -5006,13 +5009,15 @@ bfd_elfNN_aarch64_set_options (struct bfd *output_bfd,
int fix_erratum_835769,
erratum_84319_opts fix_erratum_843419,
int no_apply_dynamic_relocs,
- const aarch64_protection_opts *sw_protections)
+ const aarch64_protection_opts *sw_protections,
+ const aarch64_memtag_opts *memtag_opts)
{
struct elf_aarch64_link_hash_table *globals;
globals = elf_aarch64_hash_table (link_info);
globals->pic_veneer = pic_veneer;
globals->fix_erratum_835769 = fix_erratum_835769;
+ globals->memtag_opts = *memtag_opts;
/* If the default options are used, then ERRAT_ADR will be set by default
which will enable the ADRP->ADR workaround for the erratum 843419
workaround. */
@@ -9772,7 +9777,14 @@ elfNN_aarch64_late_size_sections (bfd *output_bfd ATTRIBUTE_UNUSED,
&& !add_dynamic_entry (DT_AARCH64_PAC_PLT, 0))
return false;
}
+
+ if (is_aarch64_elf (output_bfd)
+ && htab->memtag_opts.memtag_mode != AARCH64_MEMTAG_MODE_NONE
+ && !add_dynamic_entry (DT_AARCH64_MEMTAG_MODE,
+ htab->memtag_opts.memtag_mode == AARCH64_MEMTAG_MODE_ASYNC))
+ return false;
}
+
#undef add_dynamic_entry
return true;
diff --git a/bfd/elfxx-aarch64.h b/bfd/elfxx-aarch64.h
index 506f4a93c9d..66c1f48d450 100644
--- a/bfd/elfxx-aarch64.h
+++ b/bfd/elfxx-aarch64.h
@@ -129,13 +129,35 @@ typedef enum
ERRAT_ADRP = (1 << 2), /* Erratum workarounds using ADRP are allowed. */
} erratum_84319_opts;
+/* An enum to define the various modes of MTE operation.
+ At this time, except AARCH64_MEMTAG_MODE_NONE, the enumerator constants are
+ the same as specified in the Memtag ABI Extension to ELF for the Arm 64-bit
+ Architecture (AArch64) document (the intent being that this keeps the
+ emission of the associated dynamic tag simple).*/
+typedef enum
+{
+ AARCH64_MEMTAG_MODE_SYNC = 0,
+ AARCH64_MEMTAG_MODE_ASYNC = 1,
+ AARCH64_MEMTAG_MODE_NONE = 2,
+} aarch64_memtag_mode_type;
+
+/* A structure to encompass all information about memtag feature related
+ command line options. */
+struct aarch64_memtag_opts
+{
+ /* Mode of MTE operation. */
+ aarch64_memtag_mode_type memtag_mode;
+};
+
+typedef struct aarch64_memtag_opts aarch64_memtag_opts;
+
extern void bfd_elf64_aarch64_set_options
(bfd *, struct bfd_link_info *, int, int, int, int, erratum_84319_opts, int,
- const aarch64_protection_opts *);
+ const aarch64_protection_opts *, const aarch64_memtag_opts *);
extern void bfd_elf32_aarch64_set_options
(bfd *, struct bfd_link_info *, int, int, int, int, erratum_84319_opts, int,
- const aarch64_protection_opts *);
+ const aarch64_protection_opts *, const aarch64_memtag_opts *);
/* AArch64 stub generation support for ELF64. Called from the linker. */
extern int elf64_aarch64_setup_section_lists
diff --git a/binutils/readelf.c b/binutils/readelf.c
index dd1871d8c75..1a74588087c 100644
--- a/binutils/readelf.c
+++ b/binutils/readelf.c
@@ -2587,6 +2587,8 @@ get_aarch64_dynamic_type (unsigned long type)
case DT_AARCH64_BTI_PLT: return "AARCH64_BTI_PLT";
case DT_AARCH64_PAC_PLT: return "AARCH64_PAC_PLT";
case DT_AARCH64_VARIANT_PCS: return "AARCH64_VARIANT_PCS";
+ case DT_AARCH64_MEMTAG_MODE: return "AARCH64_MEMTAG_MODE";
+
default:
return NULL;
}
diff --git a/include/elf/aarch64.h b/include/elf/aarch64.h
index e218e07fa73..129aef9a524 100644
--- a/include/elf/aarch64.h
+++ b/include/elf/aarch64.h
@@ -52,6 +52,7 @@
#define DT_AARCH64_BTI_PLT (DT_LOPROC + 1)
#define DT_AARCH64_PAC_PLT (DT_LOPROC + 3)
#define DT_AARCH64_VARIANT_PCS (DT_LOPROC + 5)
+#define DT_AARCH64_MEMTAG_MODE (DT_LOPROC + 9)
/* AArch64-specific values for st_other. */
#define STO_AARCH64_VARIANT_PCS 0x80 /* Symbol may follow different call
diff --git a/ld/emultempl/aarch64elf.em b/ld/emultempl/aarch64elf.em
index afa91afb608..dcf314c1a21 100644
--- a/ld/emultempl/aarch64elf.em
+++ b/ld/emultempl/aarch64elf.em
@@ -41,6 +41,9 @@ static aarch64_protection_opts sw_protections = {
.gcs_report = MARKING_WARN,
.gcs_report_dynamic = MARKING_UNSET,
};
+static aarch64_memtag_opts memtag_opts = {
+ .memtag_mode = AARCH64_MEMTAG_MODE_NONE,
+};
#define COMPILE_TIME_STRLEN(s) \
(sizeof(s) - 1)
@@ -335,7 +338,8 @@ aarch64_elf_create_output_section_statements (void)
pic_veneer,
fix_erratum_835769, fix_erratum_843419,
no_apply_dynamic_relocs,
- &sw_protections);
+ &sw_protections,
+ &memtag_opts);
stub_file = lang_add_input_file ("linker stubs",
lang_input_file_is_fake_enum,
@@ -440,6 +444,31 @@ aarch64_parse_gcs_option (const char *_optarg)
#undef GCS
#undef GCS_LEN
}
+
+static bool
+aarch64_parse_memtag_mode_option (const char *optarg)
+{
+ #define MEMTAG_MODE "memtag-mode"
+ #define MEMTAG_MODE_LEN COMPILE_TIME_STRLEN (MEMTAG_MODE)
+
+ if (strncmp (optarg, MEMTAG_MODE, MEMTAG_MODE_LEN) != 0)
+ return false;
+
+ if (strcmp (optarg + MEMTAG_MODE_LEN, "=none") == 0)
+ memtag_opts.memtag_mode = AARCH64_MEMTAG_MODE_NONE;
+ else if (strcmp (optarg + MEMTAG_MODE_LEN, "=sync") == 0)
+ memtag_opts.memtag_mode = AARCH64_MEMTAG_MODE_SYNC;
+ else if (strcmp (optarg + MEMTAG_MODE_LEN, "=async") == 0)
+ memtag_opts.memtag_mode = AARCH64_MEMTAG_MODE_ASYNC;
+ else
+ einfo (_("%X%P: error: unrecognized value '-z %s'\n"), optarg);
+
+ return true;
+
+ #undef MEMTAG_MODE
+ #undef MEMTAG_MODE_LEN
+}
+
EOF
# Define some shell vars to insert bits of code into the standard elf
@@ -518,6 +547,15 @@ PARSE_AND_LIST_OPTIONS='
and output have GCS marking.\n\
error: Emit error when the input objects are missing GCS markings\n\
and output have GCS marking.\n"));
+ fprintf (file, _("\
+ -z memtag-mode[=none|sync|async] Select Memory Tagging Extension mode of operation to use.\n\
+ Emits a DT_AARCH64_MEMTAG_MODE dynamic tag for the binary.\n\
+ This entry is only valid on the main executable. It is\n\
+ ignored in the dynamically loaded objects by the loader.\n\
+ none (default): Disable MTE checking of memory reads and writes.\n\
+ sync: Enable precise exceptions when mismatched address and\n\
+ allocation tags detected on load/store operations.\n\
+ async: Enable imprecise exceptions.\n"));
'
PARSE_AND_LIST_ARGS_CASE_Z_AARCH64='
@@ -533,6 +571,8 @@ PARSE_AND_LIST_ARGS_CASE_Z_AARCH64='
{}
else if (aarch64_parse_gcs_option (optarg))
{}
+ else if (aarch64_parse_memtag_mode_option (optarg))
+ {}
'
PARSE_AND_LIST_ARGS_CASE_Z="$PARSE_AND_LIST_ARGS_CASE_Z $PARSE_AND_LIST_ARGS_CASE_Z_AARCH64"
diff --git a/ld/ld.texi b/ld/ld.texi
index afcc3fea94f..f196f1e5870 100644
--- a/ld/ld.texi
+++ b/ld/ld.texi
@@ -8374,6 +8374,15 @@ GCS markings.
If issues are found, a maximum of 20 messages will be emitted, and then a summary
with the total number of issues will be displayed at the end.
+@kindex -z memtag-mode=@var{mode}
+@cindex MTE modes of operation
+The @samp{-z memtag-mode=mode} specifies the MTE mode of operation. The
+value of @samp{mode} can be one of @samp{none, sync} or @samp{async}. The
+specified modes determine the value of the @samp{DT_AARCH64_MEMTAG_MODE}
+dynamic tag. The @samp{sync} mode implies precise exceptions, with the runtime
+providing the exact instruction where the fault occurred, and the exact
+faulting address. The @samp{async} mode implies imprecise exceptions.
+
@ifclear GENERIC
@lowersections
@end ifclear
diff --git a/ld/testsuite/ld-aarch64/aarch64-elf.exp b/ld/testsuite/ld-aarch64/aarch64-elf.exp
index 2d444e7d1e2..56e68c584fb 100644
--- a/ld/testsuite/ld-aarch64/aarch64-elf.exp
+++ b/ld/testsuite/ld-aarch64/aarch64-elf.exp
@@ -377,6 +377,7 @@ run_dump_test_lp64 "variant_pcs-shared"
run_dump_test_lp64 "variant_pcs-now"
run_dump_test_lp64 "mte-tagged-frame"
+run_dump_test_lp64 "dt-memtag-mode"
set aarch64elflinktests {
{"ld-aarch64/so with global symbol" "-shared" "" "" {copy-reloc-so.s}
diff --git a/ld/testsuite/ld-aarch64/dt-memtag-mode.d b/ld/testsuite/ld-aarch64/dt-memtag-mode.d
new file mode 100644
index 00000000000..21670bc20cd
--- /dev/null
+++ b/ld/testsuite/ld-aarch64/dt-memtag-mode.d
@@ -0,0 +1,7 @@
+#source: dt-memtag.s
+#ld: -shared -z memtag-mode=async
+#readelf: -d
+
+#...
+ 0x0000000070000009 \(AARCH64_MEMTAG_MODE\) 0x1
+#...
diff --git a/ld/testsuite/ld-aarch64/dt-memtag.s b/ld/testsuite/ld-aarch64/dt-memtag.s
new file mode 100644
index 00000000000..51f3ba5ddd2
--- /dev/null
+++ b/ld/testsuite/ld-aarch64/dt-memtag.s
@@ -0,0 +1,7 @@
+// Test DT_AARCH64_MEMTAG_MODE.
+
+.text
+.p2align 3
+.global foo
+foo:
+.xword foo
--
2.43.0
More information about the Binutils
mailing list