]> git.ipfire.org Git - thirdparty/binutils-gdb.git/commitdiff
ld/aarch64elf: add support for DT_AARCH64_MEMTAG_MODE dynamic tag
authorIndu Bhagat <indu.bhagat@oracle.com>
Sat, 12 Jul 2025 09:10:23 +0000 (11:10 +0200)
committerJose E. Marchesi <jose.marchesi@oracle.com>
Sat, 12 Jul 2025 09:33:25 +0000 (11:33 +0200)
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
bfd/elfxx-aarch64.h
binutils/readelf.c
include/elf/aarch64.h
ld/emultempl/aarch64elf.em
ld/ld.texi
ld/testsuite/ld-aarch64/aarch64-elf.exp
ld/testsuite/ld-aarch64/dt-memtag-mode.d [new file with mode: 0644]
ld/testsuite/ld-aarch64/dt-memtag.s [new file with mode: 0644]

index 8f399204f0464b1ec257cc42bce6136e559bce38..0e9e22e210be14a6b031bc0b9865f519b140e83b 100644 (file)
@@ -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;
index 506f4a93c9d7cd7b99d29f2c4a5fbd6b965af232..66c1f48d4500674f6da233cb46eb9e7c0af03ccb 100644 (file)
@@ -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
index 4a3307eaec616658338803245ddce4c82fe6417d..0d8daf3626f6691d6a8c0a1d934b3a80874abcaf 100644 (file)
@@ -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;
     }
index e218e07fa7306fbb1b2d087a5f63c4f26b9b3b98..747d8dc022fa5aedb009b35e2b28e5c41a7597e3 100644 (file)
@@ -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
index afa91afb608e0803176940a1fc76ff25c6f49687..d7e4eb78059c0567433f0cf93caba10cceb3444e 100644 (file)
@@ -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"
 
index afcc3fea94f32162ec086580de6f38ec8156aa50..f5350e799bb1e221e670bffae6fbf06ec814fe2a 100644 (file)
@@ -8374,6 +8374,16 @@ 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}, @samp{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
index 2d444e7d1e26a627a2303c866e62ed6bd4e459b0..56e68c584fb28fbcfc8c8461870be1f263d031df 100644 (file)
@@ -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 (file)
index 0000000..21670bc
--- /dev/null
@@ -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 (file)
index 0000000..51f3ba5
--- /dev/null
@@ -0,0 +1,7 @@
+// Test DT_AARCH64_MEMTAG_MODE.
+
+.text
+.p2align 3
+.global foo
+foo:
+.xword foo