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

Evgeny Karpov Evgeny.Karpov@microsoft.com
Mon Jul 21 12:39:57 GMT 2025


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

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
-- 
2.34.1




More information about the Binutils mailing list