[PATCH V4 7/8] ld/aarch64elf: add support for DT_AARCH64_MEMTAG_MODE dynamic tag
Richard Earnshaw
Richard.Earnshaw@arm.com
Fri Jul 11 13:37:11 GMT 2025
On 09/07/2025 22:44, Jose E. Marchesi via Binutils wrote:
> 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 that this patch doesn't add support for the "asymm" MTE mode,
> which is an Armv8.7 extension.
>
> 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.
> ---
> bfd/elfnn-aarch64.c | 14 +++++++-
> bfd/elfxx-aarch64.h | 26 ++++++++++++--
> binutils/readelf.c | 6 ++--
> include/elf/aarch64.h | 1 +
> ld/emultempl/aarch64elf.em | 43 +++++++++++++++++++++++-
> 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, 108 insertions(+), 6 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 8f399204f04..0e9e22e210b 100644
> --- a/bfd/elfnn-aarch64.c
> +++ b/bfd/elfnn-aarch64.c
> @@ -2622,6 +2622,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;
>
> @@ -5009,13 +5012,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. */
> @@ -9775,7 +9780,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 bcaac571e73..2ae6eea810f 100644
> --- a/binutils/readelf.c
> +++ b/binutils/readelf.c
> @@ -2584,9 +2584,11 @@ get_aarch64_dynamic_type (unsigned long type)
> {
> switch (type)
> {
> - case DT_AARCH64_BTI_PLT: return "AARCH64_BTI_PLT";
> - case DT_AARCH64_PAC_PLT: return "AARCH64_PAC_PLT";
> + 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)
Use a hard tab here to match the other instances.
>
> /* 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..d7e4eb78059 100644
> --- a/ld/emultempl/aarch64elf.em
> +++ b/ld/emultempl/aarch64elf.em
> @@ -42,6 +42,10 @@ static aarch64_protection_opts sw_protections = {
> .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 +339,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 +445,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 +548,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 +572,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
There should be separate @samp entries for none and sync; the comma and
the space should not be inside a @samp.
> +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
OK with the nits mentioned above fixed.
R.
More information about the Binutils
mailing list