[PATCH v3 4/7] Add aarch64-specific SEH commands
Evgeny Karpov
evgeny@kmaps.co
Thu Aug 14 08:20:03 GMT 2025
Implementation for aarch64 contains SEH commands that are not present for
x64 architecture, such as .seh_startepilogue/.seh_endepilogue,
.seh_save_reg*, .seh_save_freg*, and others.
gas/ChangeLog:
* config/obj-coff-seh.c (defined): Use COFFAARCH64 guard.
(obj_coff_seh_startepilogue): New.
(obj_coff_seh_endepilogue): New.
(obj_coff_seh_endfunclet): New.
(obj_coff_seh_save_reg): New.
* config/obj-coff-seh.h: Update.
---
gas/config/obj-coff-seh.c | 151 ++++++++++++++++++++++++++++++++++++++
gas/config/obj-coff-seh.h | 22 +++++-
2 files changed, 172 insertions(+), 1 deletion(-)
diff --git a/gas/config/obj-coff-seh.c b/gas/config/obj-coff-seh.c
index 158be2795dd..a12f5a3efb5 100644
--- a/gas/config/obj-coff-seh.c
+++ b/gas/config/obj-coff-seh.c
@@ -726,6 +726,105 @@ obj_coff_seh_endprologue (int what ATTRIBUTE_UNUSED)
#endif
}
+#if defined (COFFAARCH64)
+static void
+obj_coff_seh_startepilogue (int what ATTRIBUTE_UNUSED)
+{
+ symbolS *epilogue_start_addr;
+ expressionS exp;
+
+ if (!verify_context (".seh_startepilogue")
+ || !seh_validate_seg (".seh_startepilogue"))
+ return;
+ demand_empty_rest_of_line ();
+
+ const unsigned max_epilogue_scopes = AARCH64_MAX_EPILOGUE_SCOPES;
+ if (seh_ctx_cur->aarch64_ctx.epilogue_scopes_count >= max_epilogue_scopes)
+ {
+ as_bad (_("no epilogue scopes available."));
+ return;
+ }
+
+ epilogue_start_addr = symbol_temp_new_now ();
+ exp.X_op = O_subtract;
+ exp.X_add_symbol = epilogue_start_addr;
+ exp.X_op_symbol = seh_ctx_cur->start_addr;
+ exp.X_add_number = 0;
+
+ if (!resolve_expression (&exp) || exp.X_op != O_constant
+ || exp.X_add_number < 0)
+ as_bad (_(".seh_startepilog offset expression for %s "
+ "does not evaluate to a non-negative constant"),
+ S_GET_NAME (epilogue_start_addr));
+
+ if (seh_ctx_cur->aarch64_ctx.epilogue_scopes_count
+ >= seh_ctx_cur->aarch64_ctx.epilogue_scopes_capacity)
+ {
+ const unsigned initial_capacity = 32;
+ if (seh_ctx_cur->aarch64_ctx.epilogue_scopes_capacity)
+ seh_ctx_cur->aarch64_ctx.epilogue_scopes_capacity *= 2;
+ else
+ seh_ctx_cur->aarch64_ctx.epilogue_scopes_capacity = initial_capacity;
+
+ seh_ctx_cur->aarch64_ctx.epilogue_scopes
+ = XRESIZEVEC (seh_aarch64_epilogue_scope,
+ seh_ctx_cur->aarch64_ctx.epilogue_scopes,
+ seh_ctx_cur->aarch64_ctx.epilogue_scopes_capacity);
+ }
+
+ seh_aarch64_epilogue_scope *epilogue_scope;
+ epilogue_scope = seh_ctx_cur->aarch64_ctx.epilogue_scopes
+ + seh_ctx_cur->aarch64_ctx.epilogue_scopes_count;
+ epilogue_scope->epilogue_start_offset = exp.X_add_number / 4;
+ epilogue_scope->reserved = 0;
+ epilogue_scope->epilogue_start_index
+ = seh_ctx_cur->aarch64_ctx.unwind_codes_byte_count;
+ seh_ctx_cur->aarch64_ctx.epilogue_scopes_count++;
+}
+
+static void
+obj_coff_seh_endepilogue (int what ATTRIBUTE_UNUSED)
+{
+ if (!verify_context (".seh_endepilogue")
+ || !seh_validate_seg (".seh_endepilogue"))
+ return;
+
+ demand_empty_rest_of_line ();
+
+ expressionS exp;
+ symbolS *epilogue_end_addr = symbol_temp_new_now ();
+ exp.X_op = O_subtract;
+ exp.X_add_symbol = epilogue_end_addr;
+ exp.X_op_symbol = seh_ctx_cur->start_addr;
+ exp.X_add_number = 0;
+
+ if (!resolve_expression (&exp) || exp.X_op != O_constant
+ || exp.X_add_number < 0)
+ as_bad (_(".seh_endepilogue offset expression for %s "
+ "does not evaluate to a non-negative constant"),
+ S_GET_NAME (epilogue_end_addr));
+
+ seh_aarch64_epilogue_scope *epilogue_scope;
+ epilogue_scope = seh_ctx_cur->aarch64_ctx.epilogue_scopes
+ + seh_ctx_cur->aarch64_ctx.epilogue_scopes_count - 1;
+
+ epilogue_scope->epilogue_end_offset = exp.X_add_number;
+
+ /* End code. */
+ seh_aarch64_add_unwind_element (end, 0, 0);
+}
+
+static void
+obj_coff_seh_endfunclet (int what ATTRIBUTE_UNUSED)
+{
+ if (!verify_context (".seh_endfunclet")
+ || !seh_validate_seg (".seh_endfunclet"))
+ return;
+
+ demand_empty_rest_of_line ();
+}
+#endif
+
/* End-of-file hook. */
void
@@ -927,6 +1026,58 @@ obj_coff_seh_save (int what)
}
#endif
+#if defined (COFFAARCH64)
+static void
+obj_coff_seh_save_reg (int type)
+{
+ gas_assert (type >= 0 && type <= unwind_last_type);
+
+ const struct aarch64_unwind_code_pack_info *unwind_code_pack_info;
+ unwind_code_pack_info = aarch64_unwind_code_pack_data + type;
+
+ if (!unwind_code_pack_info->directive
+ || !seh_validate_seg (unwind_code_pack_info->directive))
+ return;
+
+ SKIP_WHITESPACE ();
+
+ char *symbol_name = NULL;
+ int reg = -1;
+
+ if (unwind_code_pack_info->reg_bits)
+ {
+ char name_end = get_symbol_name (&symbol_name);
+ reg = atoi (symbol_name + 1);
+ (void) restore_line_pointer (name_end);
+
+ if (!skip_whitespace_and_comma (1))
+ return;
+
+ if (reg < 0 || reg > 30)
+ {
+ as_bad (_("register number is out of range"));
+ return;
+ }
+ }
+
+ offsetT off = -1;
+ if (unwind_code_pack_info->offset_bits)
+ {
+ off = get_absolute_expression ();
+
+ if (off < 0)
+ {
+ as_bad (_("offset is negative"));
+ return;
+ }
+ }
+
+ demand_empty_rest_of_line ();
+
+ seh_aarch64_add_unwind_element (type, off, reg);
+}
+#endif
+
/* Add a stack-allocation token to current context. */
static void
diff --git a/gas/config/obj-coff-seh.h b/gas/config/obj-coff-seh.h
index 9aa97813754..039e7efe9d5 100644
--- a/gas/config/obj-coff-seh.h
+++ b/gas/config/obj-coff-seh.h
@@ -120,7 +120,27 @@ typedef enum seh_aarch64_unwind_types
{"seh_endprologue", obj_coff_seh_endprologue, 0},
{"seh_stackalloc", obj_coff_seh_stackalloc, 0}, {"seh_handler",
obj_coff_seh_handler, 0}, - {"seh_handlerdata",
obj_coff_seh_handlerdata, 0},
+ {"seh_handlerdata", obj_coff_seh_handlerdata, 0},
+ {"seh_startepilogue", obj_coff_seh_startepilogue, 0},
+ {"seh_endepilogue", obj_coff_seh_endepilogue, 0},
+ {"seh_endfunclet", obj_coff_seh_endfunclet, 0}, + {"seh_save_reg",
obj_coff_seh_save_reg, save_reg}, + {"seh_save_reg_x",
obj_coff_seh_save_reg, save_reg_x}, + {"seh_save_regp",
obj_coff_seh_save_reg, save_regp}, + {"seh_save_regp_x",
obj_coff_seh_save_reg, save_regp_x}, + {"seh_save_lrpair",
obj_coff_seh_save_reg, save_lrpair}, + {"seh_save_fregp",
obj_coff_seh_save_reg, save_fregp}, + {"seh_save_fregp_x",
obj_coff_seh_save_reg, save_fregp_x}, + {"seh_save_freg",
obj_coff_seh_save_reg, save_freg}, + {"seh_save_freg_x",
obj_coff_seh_save_reg, save_freg_x}, + {"seh_save_fplr",
obj_coff_seh_save_reg, save_fplr}, + {"seh_save_fplr_x",
obj_coff_seh_save_reg, save_fplr_x}, + {"seh_save_r19r20_x",
obj_coff_seh_save_reg, save_r19r20_x}, + {"seh_add_fp",
obj_coff_seh_save_reg, add_fp}, + {"seh_nop", obj_coff_seh_save_reg,
nop}, + {"seh_pac_sign_lr", obj_coff_seh_save_reg, pac_sign_lr},
+ {"seh_set_fp", obj_coff_seh_save_reg, set_fp}, + {"seh_save_next",
obj_coff_seh_save_reg, save_next},
#endif
/* Type definitions. */
--
2.39.5
More information about the Binutils
mailing list