[PATCH V4 5/8] gas: aarch64: suppport CFI directive .cfi_mte_tagged_frame
Richard Earnshaw
Richard.Earnshaw@arm.com
Fri Jul 11 13:18:29 GMT 2025
On 09/07/2025 22:44, Jose E. Marchesi via Binutils wrote:
> Process a new aarch64-specific CFI directive: .cfi_mte_tagged_frame
> (LLVM uses this CFI directive already). The CFI directive, when
> present for a function, indicates that the stack frame for the
> function may modify the MTE tags of the stack space it uses. The
> assembler emits char 'G' in the CIE augmentation string to indicate
> the same.
>
> ChangeLog:
>
> * gas/config/tc-aarch64.c (s_aarch64_mte_tagged_frame): New
> definition.
> * gas/config/tc-aarch64.h (tc_fde_entry_extras): Add
> memtag_frame_p.
> (tc_cie_entry_extras): Likewise.
> (tc_fde_entry_init_extra): Likewise.
> (tc_cie_fde_equivalent_extra): Likewise.
> (tc_cie_entry_init_extra): Likewise.
> * gas/doc/c-aarch64.texi: Add documentation for
> .cfi_mte_tagged_frame directive.
> * gas/testsuite/gas/aarch64/mte_tagged_stack.d: New test.
> * gas/testsuite/gas/aarch64/mte_tagged_stack.s: New test.
> ---
> gas/config/tc-aarch64.c | 9 ++++
> gas/config/tc-aarch64.h | 23 +++++++---
> gas/doc/c-aarch64.texi | 8 ++++
> gas/testsuite/gas/aarch64/mte_tagged_stack.d | 47 ++++++++++++++++++++
> gas/testsuite/gas/aarch64/mte_tagged_stack.s | 24 ++++++++++
> 5 files changed, 104 insertions(+), 7 deletions(-)
> create mode 100644 gas/testsuite/gas/aarch64/mte_tagged_stack.d
> create mode 100644 gas/testsuite/gas/aarch64/mte_tagged_stack.s
>
> diff --git a/gas/config/tc-aarch64.c b/gas/config/tc-aarch64.c
> index 13649e8f3d5..b21b1cfc825 100644
> --- a/gas/config/tc-aarch64.c
> +++ b/gas/config/tc-aarch64.c
> @@ -2351,6 +2351,14 @@ s_aarch64_cfi_b_key_frame (int ignored ATTRIBUTE_UNUSED)
> fde->pauth_key = AARCH64_PAUTH_KEY_B;
> }
>
> +static void
> +s_aarch64_mte_tagged_frame (int ignored ATTRIBUTE_UNUSED)
> +{
> + demand_empty_rest_of_line ();
> + struct fde_entry *fde = frchain_now->frch_cfi_data->cur_fde_data;
> + fde->memtag_frame_p = true;
> +}
> +
> #ifdef OBJ_ELF
> /* Emit BFD_RELOC_AARCH64_TLSDESC_ADD on the next ADD instruction. */
>
> @@ -2476,6 +2484,7 @@ const pseudo_typeS md_pseudo_table[] = {
> {"arch_extension", s_aarch64_arch_extension, 0},
> {"inst", s_aarch64_inst, 0},
> {"cfi_b_key_frame", s_aarch64_cfi_b_key_frame, 0},
> + {"cfi_mte_tagged_frame", s_aarch64_mte_tagged_frame, 0},
> #ifdef OBJ_ELF
> {"tlsdescadd", s_tlsdescadd, 0},
> {"tlsdesccall", s_tlsdesccall, 0},
> diff --git a/gas/config/tc-aarch64.h b/gas/config/tc-aarch64.h
> index 0d8066c1ab8..f895ce0c388 100644
> --- a/gas/config/tc-aarch64.h
> +++ b/gas/config/tc-aarch64.h
> @@ -90,13 +90,16 @@ enum pointer_auth_key {
>
> /* The extra fields required by AArch64 in fde_entry and cie_entry. Currently
> only used to store the key used to sign the frame's return address. */
> -#define tc_fde_entry_extras enum pointer_auth_key pauth_key;
> -#define tc_cie_entry_extras enum pointer_auth_key pauth_key;
> +#define tc_fde_entry_extras enum pointer_auth_key pauth_key; \
> + bool memtag_frame_p;
> +#define tc_cie_entry_extras enum pointer_auth_key pauth_key; \
> + bool memtag_frame_p;
>
> /* The extra initialisation steps needed by AArch64 in alloc_fde_entry.
> Currently only used to initialise the key used to sign the return
> address. */
> -#define tc_fde_entry_init_extra(fde) fde->pauth_key = AARCH64_PAUTH_KEY_A;
> +#define tc_fde_entry_init_extra(fde) fde->pauth_key = AARCH64_PAUTH_KEY_A; \
> + fde->memtag_frame_p = false;
I'd split this over (at least) three lines, with the macro definition on
a line by its own.
Also, as this is now multiple statements it's normal to write this as a
do {
stmt1;
stmt2;
...
} while (0)
construct so that it can be safely used inside blocks that expect a
single statement.
>
> /* Extra checks required by AArch64 when outputting the current cie_entry.
> Currently only used to output a 'B' if the return address is signed with the
> @@ -106,18 +109,24 @@ enum pointer_auth_key {
> { \
> if (cie->pauth_key == AARCH64_PAUTH_KEY_B) \
> out_one ('B'); \
> + if (cie->memtag_frame_p) \
> + out_one ('G'); \
> } \
> while (0)
>
> /* Extra equivalence checks required by AArch64 when selecting the correct cie
> - for some fde. Currently only used to check for quivalence between keys used
> - to sign ther return address. */
> -#define tc_cie_fde_equivalent_extra(cie, fde) (cie->pauth_key == fde->pauth_key)
> + for some fde. Currently used to check for equivalence between - keys used
> + to sign the return address, and if stack locations have MTE tagging
> + enabled. */
> +#define tc_cie_fde_equivalent_extra(cie, fde) \
> + ((cie->pauth_key == fde->pauth_key) \
> + && (cie->memtag_frame_p == fde->memtag_frame_p))
>
> /* The extra initialisation steps needed by AArch64 in select_cie_for_fde.
> Currently only used to initialise the key used to sign the return
> address. */
> -#define tc_cie_entry_init_extra(cie, fde) cie->pauth_key = fde->pauth_key;
> +#define tc_cie_entry_init_extra(cie, fde) cie->pauth_key = fde->pauth_key; \
> + cie->memtag_frame_p = fde->memtag_frame_p;
Similarly here.
>
> #define TC_FIX_TYPE struct aarch64_fix
> #define TC_INIT_FIX_DATA(FIX) { (FIX)->tc_fix_data.inst = NULL; \
> diff --git a/gas/doc/c-aarch64.texi b/gas/doc/c-aarch64.texi
> index d7e9c95111d..052fb07a1ed 100644
> --- a/gas/doc/c-aarch64.texi
> +++ b/gas/doc/c-aarch64.texi
> @@ -480,6 +480,14 @@ incrementally to the architecture being compiled for.
> @c BBBBBBBBBBBBBBBBBBBBBBBBBB
> @c CCCCCCCCCCCCCCCCCCCCCCCCCC
>
> +@cindex @code{.cfi_mte_tagged_frame} directive, AArch64
> +@item @code{.cfi_mte_tagged_frame}
> +The @code{.cfi_mte_tagged_frame} directive inserts a 'G' character into the
> +CIE corresponding to the current frame's FDE, meaning that the associated
> +frames may modify MTE tags on the stack space they use. This information is
> +intended to be used by the stack unwinder in order to properly untag stack
> +frames.
> +
> @cindex @code{.cpu} directive, AArch64
> @item .cpu @var{name}
> Set the target processor. Valid values for @var{name} are the same as
> diff --git a/gas/testsuite/gas/aarch64/mte_tagged_stack.d b/gas/testsuite/gas/aarch64/mte_tagged_stack.d
> new file mode 100644
> index 00000000000..5e8afb818e7
> --- /dev/null
> +++ b/gas/testsuite/gas/aarch64/mte_tagged_stack.d
> @@ -0,0 +1,47 @@
> +#objdump: --dwarf=frames
> +# This test is only valid on ELF based ports.
> +#notarget: *-*-*coff *-*-pe *-*-wince *-*-*aout* *-*-netbsd
> +# Test assembling a file with functions using MTE tagged stack or not
> +# It must interpret .cfi_mte_tagged_frame properly and emit a
> +# 'G' character into the correct CIE's augmentation string.
> +
> +.+: file .+
> +
> +Contents of the .eh_frame section:
> +
> +0+ 0+14 0+ CIE
> + Version: 1
> + Augmentation: "zRG"
> + Code alignment factor: 4
> + Data alignment factor: -8
> + Return address column: 30
> + Augmentation data: 1b
> + DW_CFA_def_cfa: r31 \(sp\) ofs 0
> + DW_CFA_nop
> + DW_CFA_nop
> + DW_CFA_nop
> +
> +0+18 0+14 0+1c FDE cie=0+ pc=0+\.\.0+4
> + DW_CFA_advance_loc: 4 to 0+4
> + DW_CFA_def_cfa_offset: 16
> + DW_CFA_offset: r29 \(x29\) at cfa-16
> + DW_CFA_offset: r30 \(x30\) at cfa-8
> +
> +0+30 0+10 0+0 CIE
> + Version: 1
> + Augmentation: "zR"
> + Code alignment factor: 4
> + Data alignment factor: -8
> + Return address column: 30
> + Augmentation data: 1b
> + DW_CFA_def_cfa: r31 \(sp\) ofs 0
> +
> +0+44 0+1(4|8) 0+18 FDE cie=0+30 pc=0+4\.\.0+8
> + DW_CFA_advance_loc: 4 to 0+8
> + DW_CFA_def_cfa_offset: 16
> + DW_CFA_offset: r29 \(x29\) at cfa-16
> + DW_CFA_offset: r30 \(x30\) at cfa-8
> +#? DW_CFA_nop
> +#? DW_CFA_nop
> +#? DW_CFA_nop
> +#? DW_CFA_nop
> diff --git a/gas/testsuite/gas/aarch64/mte_tagged_stack.s b/gas/testsuite/gas/aarch64/mte_tagged_stack.s
> new file mode 100644
> index 00000000000..64a92b488ee
> --- /dev/null
> +++ b/gas/testsuite/gas/aarch64/mte_tagged_stack.s
> @@ -0,0 +1,24 @@
> + .arch armv8-a+memtag
> + .text
> + .align 2
> + .global foo
> + .type foo, %function
> +foo:
> + .cfi_startproc
> + .cfi_mte_tagged_frame
> + stp x29, x30, [sp, -16]!
> + .cfi_def_cfa_offset 16
> + .cfi_offset 29, -16
> + .cfi_offset 30, -8
> + .cfi_endproc
> + .size foo, .-foo
> + .align 2
> + .global bar
> + .type bar, %function
> +bar:
> + .cfi_startproc
> + stp x29, x30, [sp, -16]!
> + .cfi_def_cfa_offset 16
> + .cfi_offset 29, -16
> + .cfi_offset 30, -8
> + .cfi_endproc
Otherwise, this is OK,
R.
More information about the Binutils
mailing list