[PATCH v4 2/7] Define unwinding and SEH data structures for aarch64

Jan Beulich jbeulich@suse.com
Fri Oct 10 13:21:38 GMT 2025


On 15.08.2025 00:41, Evgeny Karpov wrote:
> @@ -87,8 +122,104 @@ 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;

I can't find any match for this in the spec above. If I'm overlooking it,
then I don't think you can use seh_aarch64_unwind_types here. If this is
an internal structure, then I question the use of uint32_t (should perhaps
be unsigned int instead). Plus the placement of the struct is then also
misleading.

> +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;

Kind of the inverse question here: If this is (as per its placement)
representing something from the spec, then why unsigned int and not
uint32_t?

> +  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;

Same question here towards uintptr_t, the size of which is a host property,
not a target one.

> +} 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;

This, otoh, is clearly an internal structure. Imo there it would be better
to use bfd_vma (in favor of uintptr_t), for then being tied to the target,
not the host.

> +/* AARCH64_MAX_UNWIND_CODES is limited by
> +   seh_aarch64_xdata_header::ext_code_words.  */
> +#define AARCH64_MAX_UNWIND_CODES (255 * 4)
> +#define AARCH64_MAX_UNWIND_CODES_SIZE (255 * 4)
> +/* 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 unwind_codes_count;
> +  unsigned unwind_codes_byte_count;
> +  seh_aarch64_unwind_code unwind_codes[AARCH64_MAX_UNWIND_CODES];
> +  unsigned epilogue_scopes_count;
> +  unsigned epilogue_scopes_capacity;
> +  seh_aarch64_epilogue_scope *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
>  {
> +  struct seh_context *next;
> +
>    /* Initial code-segment.  */
>    segT code_seg;
>    /* Function name.  */
> @@ -126,6 +257,9 @@ 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 {
> @@ -201,4 +335,29 @@ static void obj_coff_seh_code (int);
>    (PEX64_OFFSET_TO_SCOPE_COUNT(COUNTOFUNWINDCODES) + \
>     PEX64_SCOPE_ENTRY_SIZE * (IDX))
> 
> +/* aarch64 unwind code structs.  */

Why "structs" when ...

> +#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

... all of these are encodings of "Unwind codes" as per the spec naming?

Jan


More information about the Binutils mailing list