[PATCH v2 2/7] Define unwinding and SEH data structures for aarch64
Jan Beulich
jbeulich@suse.com
Thu Jul 24 07:25:12 GMT 2025
On 21.07.2025 14:39, Evgeny Karpov wrote:
> Friday, May 16
> Jan Beulich <jbeulich@suse.com> wrote:
>
>> Please omit the stray blank line at the end of the comment.
>>
>
> The comment has been corrected.
>
>
>> Also, perhaps both here and in identifiers below: In the past Richard had
>> asked me to use AArch64 / aarch64 in favor of Arm64 / arm64.
>
> Wednesday, May 21
> Richard Earnshaw (lists) <Richard.Earnshaw@arm.com> wrote:
>
>> Please. Being able to 'git grep -i aarch64' and find all the related code (and conversely 'git grep -i arm' not be polluted with unrelated changes) is a useful property of the sources that I'd like to preserve. The only exception is when printing information out when the strings printed are defined by a public ABI document.
>
> Arm64 / arm64 has been replaced with AArch64 / aarch64.
>
>
> Friday, May 16
> Jan Beulich <jbeulich@suse.com> wrote:
>
>>> + uint32_t regI : 4;
>>> + uint32_t regF : 3;
>>> +} seh_arm64_packed_unwind_data;
>>
>> I think at least the more opaquely named the fields here could do with at
>> least some comments. Or at the very least reproduce a link to the spec
>> somewhere around here (the one added in patch 1 is in a different file,
>> and hence not directly relevant here). Same for e.g. struct
>> seh_arm64_xdata_header further down.
>
> The names have been taken from the official documentation, and the link has been added.
>
>
>>> + unsigned int func_start_rva;
>>> + seh_arm64_unwind_info except_info_unwind;
>>> +} seh_arm64_pdata;
>>
>> The long field names are going to make for overly long field access expressions.
>> Could you consider using shorter, yet still sufficiently descriptive names?
>
> The current naming reflects mapping to the official documentation. It is difficult to make
> them shorter without losing meaning.
>
>
>>> +typedef struct seh_arm64_func_fragment
>>> +{
>>> + uintptr_t offset;
>>> + symbolS *xdata_addr;
>>
>> Without seeing uses it's hard to tell whether this couldn't possibly be
>> pointer-to-const. Please in general try to use const for pointer targets
>> wherever possible.
>
> xdata_addr is used in an expressionS::X_add_symbol that is not const.
>
>>> +#define ARM64_MAX_UNWIND_CODES 286
>>
>> Where's this (magic) number coming from?
>
> Thanks for pointing that out. The defines have been updated, and an explanation has been added.
>
> Wednesday, May 21
> Richard Earnshaw (lists) <Richard.Earnshaw@arm.com> wrote:
>
>>>> +typedef struct seh_arm64_xdata_header
>>>> +{
>>>> + uint32_t func_length : 18;
>>>> + uint32_t vers : 2;
>>>> + uint32_t x : 1;
>>>> + uint32_t e : 1;
>>>> + uint32_t epilogue_count : 5;
>>>> + uint32_t code_words : 5;
>>>> + uint32_t ext_epilogue_count : 16;
>>>> + uint32_t ext_code_words : 8;
>>>> + uint32_t reserved : 8;
>>>> +} seh_arm64_xdata_header;
>>>> +
>>
>> Is this supposed to be some form of 'in-file' data structure? If so, this is probably not going to work when cross-building from a big-endian host, unless you've > written some code to do the read/write transforms. But if you have, why do you need the various bits of padding here? The same applies to the other structs you've defined in this file.
>
> Yes, it is the 'in-file' data structure in the .pdata and .xdata sections for unwinding and exception handling.
> It looks like it is consistently handled with number_to_chars_bigendian, which should cover this case.
>
> Regards,
> Evgeny
>
>
> [PATCH] Define unwinding and SEH data structures for aarch64
The responses above are all fine to have in a reply, but please send a new
version of the series as such - a new (complete) submission of all yet to
be committed patches. I now kind of understand what these "patches"
trickled in over the last two or three days ...
Jan
> This patch adds unwinding codes and records that are needed to emit
> SEH data to pdata and xdata sections, and an arm64 context to store
> data required for emitting.
>
> gas/ChangeLog:
>
> * config/obj-coff-seh.h (AARCH64_MAX_UNWIND_CODES): New.
> (AARCH64_MAX_EPILOGUE_SCOPES): New.
> (AARCH64_UNOP_ALLOCS): New.
> (AARCH64_UNOP_SAVER19R20X): New.
> (AARCH64_UNOP_SAVEFPLR): New.
> (AARCH64_UNOP_SAVEFPLRX): New.
> (AARCH64_UNOP_ALLOCM): New.
> (AARCH64_UNOP_SAVEREGP): New.
> (AARCH64_UNOP_SAVEREGPX): New.
> (AARCH64_UNOP_SAVEREG): New.
> (AARCH64_UNOP_SAVEREGX): New.
> (AARCH64_UNOP_SAVELRPAIR): New.
> (AARCH64_UNOP_SAVEFREGP): New.
> (AARCH64_UNOP_SAVEFREGPX): New.
> (AARCH64_UNOP_SAVEFREG): New.
> (AARCH64_UNOP_SAVEFREGX): New.
> (AARCH64_UNOP_ALLOCL): New.
> (AARCH64_UNOP_SETFP): New.
> (AARCH64_UNOP_ADDFP): New.
> (AARCH64_UNOP_NOP): New.
> (AARCH64_UNOP_END): New.
> (AARCH64_UNOP_ENDC): New.
> (AARCH64_UNOP_SAVENEXT): New.
> (AARCH64_UNOP_PACSIGNLR): New.
> ---
> gas/config/obj-coff-seh.h | 160 +++++++++++++++++++++++++++++++++++++-
> 1 file changed, 158 insertions(+), 2 deletions(-)
>
> diff --git a/gas/config/obj-coff-seh.h b/gas/config/obj-coff-seh.h
> index 598870ae4e0..3f7efe56a15 100644
> --- a/gas/config/obj-coff-seh.h
> +++ b/gas/config/obj-coff-seh.h
> @@ -19,12 +19,13 @@
> 02110-1301, USA. */
>
> /* Short overview:
> - There are at the moment three different function entry formats preset.
> + There are at the moment four different function entry formats preset.
> The first is the MIPS one. The second version
> is for ARM, PPC, SH3, and SH4 mainly for Windows CE.
> The third is the IA64 and x64 version. Note, the IA64 isn't implemented yet,
> but to find information about it, please see specification about IA64 on
> http://download.intel.com/design/Itanium/Downloads/245358.pdf file.
> + The fourth is the AArch64 version.
>
> The first version has just entries in the pdata section: BeginAddress,
> EndAddress, ExceptionHandler, HandlerData, and PrologueEndAddress. Each
> @@ -57,8 +58,42 @@
> .seh_savexmm
> .seh_pushframe
> .seh_code
> +
> + The fourth version for AArch64 partially intersects with the x64
> + version, however it has a different extension to the unwind codes.
> + It emits SEH data to pdata and xdata sections. In some cases SEH
> + data could be emitted to a packed record in the pdata section
> + without the need for data in the xdata section. However, the packed
> + pdata record is not implemented yet.
> */
>
> +typedef enum seh_aarch64_unwind_types
> +{
> + alloc_s,
> + alloc_m,
> + alloc_l,
> + save_reg,
> + save_reg_x,
> + save_regp,
> + save_regp_x,
> + save_fregp,
> + save_fregp_x,
> + save_freg,
> + save_freg_x,
> + save_lrpair,
> + save_fplr,
> + save_fplr_x,
> + save_r19r20_x,
> + add_fp,
> + set_fp,
> + save_next,
> + nop,
> + pac_sign_lr,
> + end,
> + end_c,
> + unwind_last_type = end_c
> +} seh_aarch64_unwind_types;
> +
> /* architecture specific pdata/xdata handling. */
> #define SEH_CMDS \
> {"seh_proc", obj_coff_seh_proc, 0}, \
> @@ -87,6 +122,98 @@ typedef struct seh_prologue_element
> symbolS *pc_addr;
> } seh_prologue_element;
>
> +/* AArch64 exceptions handling and unwinding structures.
> + https://learn.microsoft.com/en-us/cpp/build/arm64-exception-handling#pdata-records. */
> +
> +typedef struct seh_aarch64_unwind_code
> +{
> + uint32_t value;
> + seh_aarch64_unwind_types type;
> +} seh_aarch64_unwind_code;
> +
> +typedef struct seh_aarch64_packed_unwind_data
> +{
> + uint32_t flag : 2;
> + uint32_t func_length : 11;
> + uint32_t frame_size : 9;
> + uint32_t cr : 2;
> + uint32_t h : 1;
> + uint32_t regI : 4;
> + uint32_t regF : 3;
> +} seh_aarch64_packed_unwind_data;
> +
> +typedef struct seh_aarch64_except_info
> +{
> + uint32_t flag : 2;
> + uint32_t except_info_rva : 30;
> +} seh_aarch64_except_info;
> +
> +typedef union seh_aarch64_unwind_info
> +{
> + seh_aarch64_except_info except_info;
> + seh_aarch64_packed_unwind_data packed_unwind_data;
> +} seh_aarch64_unwind_info;
> +
> +typedef struct seh_aarch64_pdata
> +{
> + unsigned int func_start_rva;
> + seh_aarch64_unwind_info except_info_unwind;
> +} seh_aarch64_pdata;
> +
> +typedef struct seh_aarch64_xdata_header
> +{
> + uint32_t func_length : 18;
> + uint32_t vers : 2;
> + uint32_t x : 1;
> + uint32_t e : 1;
> + uint32_t epilogue_count : 5;
> + uint32_t code_words : 5;
> + uint32_t ext_epilogue_count : 16;
> + uint32_t ext_code_words : 8;
> + uint32_t reserved : 8;
> +} seh_aarch64_xdata_header;
> +
> +typedef struct seh_aarch64_epilogue_scope
> +{
> + uint32_t epilogue_start_offset_reduced : 18;
> + uint32_t reserved : 4;
> + uint32_t epilogue_start_index : 10;
> + uintptr_t epilogue_start_offset;
> + uintptr_t epilogue_end_offset;
> +} seh_aarch64_epilogue_scope;
> +
> +typedef struct seh_aarch64_func_fragment
> +{
> + uintptr_t offset;
> + symbolS *xdata_addr;
> + struct seh_aarch64_func_fragment *next;
> +} seh_aarch64_func_fragment;
> +
> +/* AARCH64_MAX_UNWIND_CODES is limited by
> + seh_aarch64_xdata_header::ext_code_words. */
> +#define AARCH64_MAX_UNWIND_CODES 255
> +/* AARCH64_MAX_EPILOGUE_SCOPES is limited by
> + seh_aarch64_xdata_header::ext_epilogue_count. */
> +#define AARCH64_MAX_EPILOGUE_SCOPES 65535
> +
> +typedef struct seh_aarch64_context
> +{
> + seh_aarch64_pdata pdata;
> + union {
> + seh_aarch64_xdata_header xdata_header;
> + valueT xdata_header_value;
> + };
> + unsigned int unwind_codes_count;
> + unsigned int unwind_codes_byte_count;
> + seh_aarch64_unwind_code unwind_codes[AARCH64_MAX_UNWIND_CODES];
> + unsigned int epilogue_scopes_count;
> + seh_aarch64_epilogue_scope epilogue_scopes[AARCH64_MAX_EPILOGUE_SCOPES];
> + expressionS except_handler;
> + expressionS except_handler_data;
> + /* The function fragments. */
> + seh_aarch64_func_fragment func_fragment;
> +} seh_aarch64_context;
> +
> typedef struct seh_context
> {
> /* Initial code-segment. */
> @@ -126,13 +253,17 @@ typedef struct seh_context
> int elems_count;
> int elems_max;
> seh_prologue_element *elems;
> +
> + /* aarch64-specific context. */
> + seh_aarch64_context aarch64_ctx;
> } seh_context;
>
> typedef enum seh_kind {
> seh_kind_unknown = 0,
> seh_kind_mips = 1, /* Used for MIPS and x86 pdata generation. */
> seh_kind_arm = 2, /* Used for ARM, PPC, SH3, and SH4 pdata (PDATA_EH) generation. */
> - seh_kind_x64 = 3 /* Used for IA64 and x64 pdata/xdata generation. */
> + seh_kind_x64 = 3, /* Used for IA64 and x64 pdata/xdata generation. */
> + seh_kind_aarch64 = 4 /* Used for AARCH64 pdata/xdata generation. */
> } seh_kind;
>
> /* Forward declarations. */
> @@ -201,4 +332,29 @@ static void obj_coff_seh_code (int);
> (PEX64_OFFSET_TO_SCOPE_COUNT(COUNTOFUNWINDCODES) + \
> PEX64_SCOPE_ENTRY_SIZE * (IDX))
>
> +/* aarch64 unwind code structs. */
> +
> +#define AARCH64_UNOP_ALLOCS 0b000U
> +#define AARCH64_UNOP_SAVER19R20X 0b001U
> +#define AARCH64_UNOP_SAVEFPLR 0b01U
> +#define AARCH64_UNOP_SAVEFPLRX 0b10U
> +#define AARCH64_UNOP_ALLOCM 0b11000U
> +#define AARCH64_UNOP_SAVEREGP 0b110010U
> +#define AARCH64_UNOP_SAVEREGPX 0b110011U
> +#define AARCH64_UNOP_SAVEREG 0b110100U
> +#define AARCH64_UNOP_SAVEREGX 0b1101010U
> +#define AARCH64_UNOP_SAVELRPAIR 0b1101011U
> +#define AARCH64_UNOP_SAVEFREGP 0b1101100U
> +#define AARCH64_UNOP_SAVEFREGPX 0b1101101U
> +#define AARCH64_UNOP_SAVEFREG 0b1101110U
> +#define AARCH64_UNOP_SAVEFREGX 0b11011110U
> +#define AARCH64_UNOP_ALLOCL 0b11100000U
> +#define AARCH64_UNOP_SETFP 0b11100001U
> +#define AARCH64_UNOP_ADDFP 0b11100010U
> +#define AARCH64_UNOP_NOP 0b11100011U
> +#define AARCH64_UNOP_END 0b11100100U
> +#define AARCH64_UNOP_ENDC 0b11100101U
> +#define AARCH64_UNOP_SAVENEXT 0b11100110U
> +#define AARCH64_UNOP_PACSIGNLR 0b11111100U
> +
> #endif
More information about the Binutils
mailing list