[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