From ef6fd9c8c04aa3276fdd4d9b4e98e39ad1854ea6 Mon Sep 17 00:00:00 2001 From: Peter Johnson Date: Mon, 12 Feb 2007 03:48:53 +0000 Subject: [PATCH] Add support for Win64 structured exception handling (aka .xdata and .pdata). Requested by: Myria Chan, Brian Gladman, several others Helped by: Brian Gladman (format documentation pointers) This commit adds the necessary directives and some higher-level macros to make it easier to generate the .xdata and .pdata sections needed for structured exception handling on Win64. The overall construction mirrors MASM very closely, so it should be possible for near-direct translation of MASM code to Yasm; see for example objfmts/win64/tests/sce3.masm and objfmts/win64/tests/sce4.asm. This commit does *not* break generating these yourself (which you may want to do if you're a compiler). This commit adds special proc macros so the function layout will look like: proc_frame ... (frame setup and unwind directives) end_prologue (or alternatively [endprolog]) ... endproc_frame The "raw pseudo operations" (.directives) as described in MSDN (http://msdn2.microsoft.com/en-us/library/ms235231(VS.80).aspx) have been exactly mirrored in Yasm, as follows: [pushreg], [setframe], [allocstack], [savereg], [savexmm128], [pushframe], [endprolog] Note the [] are required. Additionally, the following macros have been implemented that MASM provides in ksamd64.inc, and as documented in MSDN (http://msdn2.microsoft.com/en-us/library/ms235217(VS.80).aspx): push_reg, rex_push_reg, push_eflags, rex_push_eflags, alloc_stack, save_reg, save_xmm128, push_frame, set_frame, end_prologue I'll next work on getting all of this documented in the user manual. svn path=/trunk/yasm/; revision=1762 --- Mkfiles/Makefile.dj | 1 + Mkfiles/Makefile.flat | 1 + Mkfiles/vc/modules/modules.vcproj | 6 + Mkfiles/vc8/modules/modules.vcproj | 8 + modules/objfmts/coff/Makefile.inc | 2 + modules/objfmts/coff/coff-objfmt.c | 428 ++++++++- modules/objfmts/coff/coff-objfmt.h | 77 ++ modules/objfmts/coff/win64-except.c | 553 ++++++++++++ modules/objfmts/win64/tests/Makefile.inc | 16 + modules/objfmts/win64/tests/sce1-err.asm | 36 + modules/objfmts/win64/tests/sce1-err.errwarn | 8 + modules/objfmts/win64/tests/sce1.asm | 44 + modules/objfmts/win64/tests/sce1.hex | 430 ++++++++++ modules/objfmts/win64/tests/sce2-err.asm | 3 + modules/objfmts/win64/tests/sce2-err.errwarn | 2 + modules/objfmts/win64/tests/sce2.asm | 29 + modules/objfmts/win64/tests/sce2.hex | 717 ++++++++++++++++ modules/objfmts/win64/tests/sce3.asm | 73 ++ modules/objfmts/win64/tests/sce3.hex | 859 +++++++++++++++++++ modules/objfmts/win64/tests/sce3.masm | 74 ++ modules/objfmts/win64/tests/sce4-err.asm | 24 + modules/objfmts/win64/tests/sce4-err.errwarn | 9 + modules/objfmts/win64/tests/sce4.asm | 30 + modules/objfmts/win64/tests/sce4.hex | 652 ++++++++++++++ modules/objfmts/win64/tests/sce4.masm | 36 + modules/preprocs/nasm/standard.mac | 129 ++- po/POTFILES.in | 2 + 27 files changed, 4228 insertions(+), 21 deletions(-) create mode 100644 modules/objfmts/coff/coff-objfmt.h create mode 100644 modules/objfmts/coff/win64-except.c create mode 100644 modules/objfmts/win64/tests/sce1-err.asm create mode 100644 modules/objfmts/win64/tests/sce1-err.errwarn create mode 100644 modules/objfmts/win64/tests/sce1.asm create mode 100644 modules/objfmts/win64/tests/sce1.hex create mode 100644 modules/objfmts/win64/tests/sce2-err.asm create mode 100644 modules/objfmts/win64/tests/sce2-err.errwarn create mode 100644 modules/objfmts/win64/tests/sce2.asm create mode 100644 modules/objfmts/win64/tests/sce2.hex create mode 100644 modules/objfmts/win64/tests/sce3.asm create mode 100644 modules/objfmts/win64/tests/sce3.hex create mode 100644 modules/objfmts/win64/tests/sce3.masm create mode 100644 modules/objfmts/win64/tests/sce4-err.asm create mode 100644 modules/objfmts/win64/tests/sce4-err.errwarn create mode 100644 modules/objfmts/win64/tests/sce4.asm create mode 100644 modules/objfmts/win64/tests/sce4.hex create mode 100644 modules/objfmts/win64/tests/sce4.masm diff --git a/Mkfiles/Makefile.dj b/Mkfiles/Makefile.dj index 7a4cad20..dab4a5ff 100644 --- a/Mkfiles/Makefile.dj +++ b/Mkfiles/Makefile.dj @@ -87,6 +87,7 @@ MODULES_OBJFMTS_OBJS= \ modules/objfmts/dbg/dbg-objfmt.o \ modules/objfmts/bin/bin-objfmt.o \ modules/objfmts/coff/coff-objfmt.o \ + modules/objfmts/coff/win64-except.o \ modules/objfmts/elf/elf.o \ modules/objfmts/elf/elf-x86-x86.o \ modules/objfmts/elf/elf-x86-amd64.o \ diff --git a/Mkfiles/Makefile.flat b/Mkfiles/Makefile.flat index 1302cad4..9160a245 100644 --- a/Mkfiles/Makefile.flat +++ b/Mkfiles/Makefile.flat @@ -90,6 +90,7 @@ MODULES_OBJFMTS_OBJS= \ modules/objfmts/dbg/dbg-objfmt.o \ modules/objfmts/bin/bin-objfmt.o \ modules/objfmts/coff/coff-objfmt.o \ + modules/objfmts/coff/win64-except.o \ modules/objfmts/elf/elf.o \ modules/objfmts/elf/elf-x86-x86.o \ modules/objfmts/elf/elf-x86-amd64.o \ diff --git a/Mkfiles/vc/modules/modules.vcproj b/Mkfiles/vc/modules/modules.vcproj index 28081b66..fee60184 100644 --- a/Mkfiles/vc/modules/modules.vcproj +++ b/Mkfiles/vc/modules/modules.vcproj @@ -186,6 +186,12 @@ + + + + diff --git a/Mkfiles/vc8/modules/modules.vcproj b/Mkfiles/vc8/modules/modules.vcproj index 160b217c..03821e78 100644 --- a/Mkfiles/vc8/modules/modules.vcproj +++ b/Mkfiles/vc8/modules/modules.vcproj @@ -409,6 +409,14 @@ RelativePath="..\..\..\modules\objfmts\coff\coff-objfmt.c" > + + + + diff --git a/modules/objfmts/coff/Makefile.inc b/modules/objfmts/coff/Makefile.inc index 975ec388..526f7713 100644 --- a/modules/objfmts/coff/Makefile.inc +++ b/modules/objfmts/coff/Makefile.inc @@ -1,6 +1,8 @@ # $Id$ libyasm_a_SOURCES += modules/objfmts/coff/coff-objfmt.c +libyasm_a_SOURCES += modules/objfmts/coff/coff-objfmt.h +libyasm_a_SOURCES += modules/objfmts/coff/win64-except.c YASM_MODULES += objfmt_coff diff --git a/modules/objfmts/coff/coff-objfmt.c b/modules/objfmts/coff/coff-objfmt.c index 3d518cec..6c2ae9ba 100644 --- a/modules/objfmts/coff/coff-objfmt.c +++ b/modules/objfmts/coff/coff-objfmt.c @@ -33,6 +33,8 @@ #define YASM_EXPR_INTERNAL #include +#include "coff-objfmt.h" + #define REGULAR_OUTBUF_SIZE 1024 @@ -174,7 +176,7 @@ typedef struct coff_symrec_data { } coff_symrec_data; typedef struct yasm_objfmt_coff { - yasm_objfmt_base objfmt; /* base structure*/ + yasm_objfmt_base objfmt; /* base structure */ unsigned int parse_scnum; /* sect numbering in parser */ int win32; /* nonzero for win32/64 output */ @@ -187,6 +189,17 @@ typedef struct yasm_objfmt_coff { /*@dependent@*/ yasm_arch *arch; coff_symrec_data *filesym_data; /* Data for .file symbol */ + + /* Last switched-to section. Used by proc_frame directives to help + * them determine the current assembly position. + * XXX: There should be a better way to do this. + */ + yasm_section *cursect; + + /* data for win64 proc_frame and related directives */ + unsigned long proc_frame; /* Line number of start of proc, or 0 */ + unsigned long done_prolog; /* Line number of end of prologue, or 0 */ + /*@null@*/ coff_unwind_info *unwind; /* Unwind info */ } yasm_objfmt_coff; typedef struct coff_objfmt_output_info { @@ -271,6 +284,12 @@ coff_common_create(yasm_object *object, yasm_arch *a) /* Filename is set in coff_objfmt_output */ objfmt_coff->filesym_data->aux[0].fname = NULL; + objfmt_coff->cursect = NULL; + + objfmt_coff->proc_frame = 0; + objfmt_coff->done_prolog = 0; + objfmt_coff->unwind = NULL; + return objfmt_coff; } @@ -1142,6 +1161,15 @@ coff_objfmt_output(yasm_objfmt *objfmt, FILE *f, int all_syms, yasm_dbgfmt *df, unsigned int flags; unsigned long ts; + if (objfmt_coff->proc_frame) { + yasm_error_set_xref(objfmt_coff->proc_frame, + N_("procedure started here")); + yasm_error_set(YASM_ERROR_GENERAL, + N_("end of file in procedure frame")); + yasm_errwarn_propagate(errwarns, 0); + return; + } + if (objfmt_coff->filesym_data->aux[0].fname) yasm_xfree(objfmt_coff->filesym_data->aux[0].fname); objfmt_coff->filesym_data->aux[0].fname = @@ -1252,6 +1280,8 @@ coff_objfmt_destroy(yasm_objfmt *objfmt) yasm_objfmt_coff *objfmt_coff = (yasm_objfmt_coff *)objfmt; if (objfmt_coff->filesym_data->aux[0].fname) yasm_xfree(objfmt_coff->filesym_data->aux[0].fname); + if (objfmt_coff->unwind) + yasm_win64__uwinfo_destroy(objfmt_coff->unwind); yasm_xfree(objfmt); } @@ -1272,6 +1302,7 @@ coff_objfmt_add_default_section(yasm_objfmt *objfmt) csd->flags |= COFF_STYP_EXECUTE | COFF_STYP_READ; yasm_section_set_default(retval, 1); } + objfmt_coff->cursect = retval; return retval; } @@ -1573,6 +1604,7 @@ coff_objfmt_section_switch(yasm_objfmt *objfmt, yasm_valparamhead *valparams, } else if (flags_override) yasm_warn_set(YASM_WARN_GENERAL, N_("section flags ignored on section redeclaration")); + objfmt_coff->cursect = retval; return retval; } @@ -1829,6 +1861,396 @@ win32_objfmt_directive(yasm_objfmt *objfmt, const char *name, return 1; } +static void +dir_proc_frame(yasm_objfmt_coff *objfmt_coff, + /*@null@*/ yasm_valparamhead *valparams, unsigned long line) +{ + yasm_valparam *vp = yasm_vps_first(valparams); + if (objfmt_coff->proc_frame) { + yasm_error_set_xref(objfmt_coff->proc_frame, + N_("previous procedure started here")); + yasm_error_set(YASM_ERROR_SYNTAX, + N_("nested procedures not supported (didn't use [ENDPROC_FRAME]?)")); + return; + } + if (!vp || !vp->val) { + yasm_error_set(YASM_ERROR_SYNTAX, + N_("[%s] requires a procedure symbol name"), + "PROC_FRAME"); + return; + } + objfmt_coff->proc_frame = line; + objfmt_coff->done_prolog = 0; + objfmt_coff->unwind = yasm_win64__uwinfo_create(); + objfmt_coff->unwind->proc = + yasm_symtab_use(objfmt_coff->symtab, vp->val, line); + + /* Optional error handler */ + vp = yasm_vps_next(vp); + if (!vp || !vp->val) + return; + objfmt_coff->unwind->ehandler = + yasm_symtab_use(objfmt_coff->symtab, vp->val, line); +} + +static int +procframe_checkstate(yasm_objfmt_coff *objfmt_coff, const char *dirname) +{ + if (!objfmt_coff->proc_frame) { + yasm_error_set(YASM_ERROR_SYNTAX, + N_("[%s] without preceding [PROC_FRAME]"), dirname); + return 0; + } + if (objfmt_coff->done_prolog) { + yasm_error_set_xref(objfmt_coff->done_prolog, + N_("prologue ended here")); + yasm_error_set(YASM_ERROR_SYNTAX, N_("[%s] after end of prologue"), + dirname); + return 0; + } + if (!objfmt_coff->unwind) + yasm_internal_error(N_("unwind info not present")); + return 1; +} + +/* Get current assembly position. + * XXX: There should be a better way to do this. + */ +static yasm_symrec * +get_curpos(yasm_objfmt_coff *objfmt_coff, unsigned long line) +{ + return yasm_symtab_define_curpos(objfmt_coff->symtab, "$", + yasm_section_bcs_last(objfmt_coff->cursect), line); +} + +static void +dir_pushreg(yasm_objfmt_coff *objfmt_coff, yasm_valparamhead *valparams, + unsigned long line) +{ + yasm_valparam *vp = yasm_vps_first(valparams); + coff_unwind_code *code; + const unsigned long *reg; + + if (!procframe_checkstate(objfmt_coff, "PUSHREG")) + return; + + if (!vp || !vp->param || !(reg = yasm_expr_get_reg(&vp->param, 0))) { + yasm_error_set(YASM_ERROR_SYNTAX, + N_("[%s] requires a register as the first parameter"), + "PUSHREG"); + return; + } + + /* Generate a PUSH_NONVOL unwind code. */ + code = yasm_xmalloc(sizeof(coff_unwind_code)); + code->proc = objfmt_coff->unwind->proc; + code->loc = get_curpos(objfmt_coff, line); + code->opcode = UWOP_PUSH_NONVOL; + code->info = (unsigned int)(*reg & 0xF); + yasm_value_initialize(&code->off, NULL, 0); + SLIST_INSERT_HEAD(&objfmt_coff->unwind->codes, code, link); +} + +static void +dir_setframe(yasm_objfmt_coff *objfmt_coff, yasm_valparamhead *valparams, + unsigned long line) +{ + yasm_valparam *vp = yasm_vps_first(valparams); + coff_unwind_code *code; + const unsigned long *reg; + yasm_expr *off = NULL; + + if (!procframe_checkstate(objfmt_coff, "SETFRAME")) + return; + + if (!vp || !vp->param || !(reg = yasm_expr_get_reg(&vp->param, 0))) { + yasm_error_set(YASM_ERROR_SYNTAX, + N_("[%s] requires a register as the first parameter"), + "SETFRAME"); + return; + } + + vp = yasm_vps_next(vp); + if (vp && vp->param) { + off = vp->param; + vp->param = NULL; + } + + /* Set the frame fields in the unwind info */ + objfmt_coff->unwind->framereg = *reg; + yasm_value_initialize(&objfmt_coff->unwind->frameoff, off, 8); + + /* Generate a SET_FPREG unwind code */ + code = yasm_xmalloc(sizeof(coff_unwind_code)); + code->proc = objfmt_coff->unwind->proc; + code->loc = get_curpos(objfmt_coff, line); + code->opcode = UWOP_SET_FPREG; + code->info = (unsigned int)(*reg & 0xF); + yasm_value_initialize(&code->off, yasm_expr_copy(off), 8); + SLIST_INSERT_HEAD(&objfmt_coff->unwind->codes, code, link); +} + +static void +dir_allocstack(yasm_objfmt_coff *objfmt_coff, yasm_valparamhead *valparams, + unsigned long line) +{ + yasm_valparam *vp = yasm_vps_first(valparams); + coff_unwind_code *code; + + if (!procframe_checkstate(objfmt_coff, "ALLOCSTACK")) + return; + + /* Transform ID to expression if needed */ + if (vp && vp->val && !vp->param) { + vp->param = yasm_expr_create_ident(yasm_expr_sym( + yasm_symtab_use(objfmt_coff->symtab, vp->val, line)), line); + } + + if (!vp || !vp->param) { + yasm_error_set(YASM_ERROR_SYNTAX, N_("[%s] requires a size"), + "ALLOCSTACK"); + return; + } + + /* Generate an ALLOC_SMALL unwind code; this will get enlarged to an + * ALLOC_LARGE if necessary. + */ + code = yasm_xmalloc(sizeof(coff_unwind_code)); + code->proc = objfmt_coff->unwind->proc; + code->loc = get_curpos(objfmt_coff, line); + code->opcode = UWOP_ALLOC_SMALL; + code->info = 0; + yasm_value_initialize(&code->off, vp->param, 7); + vp->param = NULL; + SLIST_INSERT_HEAD(&objfmt_coff->unwind->codes, code, link); +} + +static void +dir_save_common(yasm_objfmt_coff *objfmt_coff, yasm_valparamhead *valparams, + unsigned long line, const char *name, int op) +{ + yasm_valparam *vp = yasm_vps_first(valparams); + coff_unwind_code *code; + const unsigned long *reg; + + if (!procframe_checkstate(objfmt_coff, name)) + return; + + if (!vp || !vp->param || !(reg = yasm_expr_get_reg(&vp->param, 0))) { + yasm_error_set(YASM_ERROR_SYNTAX, + N_("[%s] requires a register as the first parameter"), + name); + return; + } + + vp = yasm_vps_next(vp); + + /* Transform ID to expression if needed */ + if (vp && vp->val && !vp->param) { + vp->param = yasm_expr_create_ident(yasm_expr_sym( + yasm_symtab_use(objfmt_coff->symtab, vp->val, line)), line); + } + + if (!vp || !vp->param) { + yasm_error_set(YASM_ERROR_SYNTAX, + N_("[%s] requires an offset as the second parameter"), + name); + return; + } + + /* Generate a SAVE_XXX unwind code; this will get enlarged to a + * SAVE_XXX_FAR if necessary. + */ + code = yasm_xmalloc(sizeof(coff_unwind_code)); + code->proc = objfmt_coff->unwind->proc; + code->loc = get_curpos(objfmt_coff, line); + code->opcode = op; + code->info = (unsigned int)(*reg & 0xF); + yasm_value_initialize(&code->off, vp->param, 16); + vp->param = NULL; + SLIST_INSERT_HEAD(&objfmt_coff->unwind->codes, code, link); +} + +static void +dir_savereg(yasm_objfmt_coff *objfmt_coff, yasm_valparamhead *valparams, + unsigned long line) +{ + dir_save_common(objfmt_coff, valparams, line, "SAVEREG", UWOP_SAVE_NONVOL); +} + +static void +dir_savexmm128(yasm_objfmt_coff *objfmt_coff, yasm_valparamhead *valparams, + unsigned long line) +{ + dir_save_common(objfmt_coff, valparams, line, "SAVEXMM128", + UWOP_SAVE_XMM128); +} + +static void +dir_pushframe(yasm_objfmt_coff *objfmt_coff, + /*@null@*/ yasm_valparamhead *valparams, unsigned long line) +{ + yasm_valparam *vp = yasm_vps_first(valparams); + coff_unwind_code *code; + + if (!procframe_checkstate(objfmt_coff, "PUSHFRAME")) + return; + + /* Generate a PUSH_MACHFRAME unwind code. If there's any parameter, + * we set info to 1. Otherwise we set info to 0. + */ + code = yasm_xmalloc(sizeof(coff_unwind_code)); + code->proc = objfmt_coff->unwind->proc; + code->loc = get_curpos(objfmt_coff, line); + code->opcode = UWOP_PUSH_MACHFRAME; + code->info = vp && (vp->val || vp->param); + yasm_value_initialize(&code->off, NULL, 0); + SLIST_INSERT_HEAD(&objfmt_coff->unwind->codes, code, link); +} + +static void +dir_endprolog(yasm_objfmt_coff *objfmt_coff, + /*@null@*/ yasm_valparamhead *valparams, unsigned long line) +{ + if (!procframe_checkstate(objfmt_coff, "ENDPROLOG")) + return; + objfmt_coff->done_prolog = line; + + objfmt_coff->unwind->prolog = get_curpos(objfmt_coff, line); +} + +static void +dir_endproc_frame(yasm_objfmt_coff *objfmt_coff, + /*@null@*/ yasm_valparamhead *valparams, unsigned long line) +{ + yasm_section *sect; + coff_section_data *csd; + yasm_datavalhead dvs; + int isnew; + /*@dependent@*/ yasm_symrec *curpos, *unwindpos, *proc_sym, *xdata_sym; + + if (!objfmt_coff->proc_frame) { + yasm_error_set(YASM_ERROR_SYNTAX, + N_("[%s] without preceding [PROC_FRAME]"), + "ENDPROC_FRAME"); + return; + } + if (!objfmt_coff->done_prolog) { + yasm_error_set_xref(objfmt_coff->proc_frame, + N_("procedure started here")); + yasm_error_set(YASM_ERROR_SYNTAX, + N_("ended procedure without ending prologue"), + "ENDPROC_FRAME"); + objfmt_coff->proc_frame = 0; + yasm_win64__uwinfo_destroy(objfmt_coff->unwind); + objfmt_coff->unwind = NULL; + return; + } + if (!objfmt_coff->unwind) + yasm_internal_error(N_("unwind info not present")); + + proc_sym = objfmt_coff->unwind->proc; + + curpos = get_curpos(objfmt_coff, line); + + /* + * Add unwind info to end of .xdata section. + */ + + sect = yasm_object_get_general(objfmt_coff->object, ".xdata", 0, 0, 0, 0, + &isnew, line); + + /* Initialize xdata section if needed */ + if (isnew) { + csd = coff_objfmt_init_new_section(objfmt_coff, sect, ".xdata", line); + csd->flags = COFF_STYP_DATA | COFF_STYP_READ; + yasm_section_set_align(sect, 8, line); + } + + /* Get current position in .xdata section */ + unwindpos = yasm_symtab_define_curpos(objfmt_coff->symtab, "$", + yasm_section_bcs_last(sect), line); + /* Get symbol for .xdata as we'll want to reference it with WRT */ + csd = yasm_section_get_data(sect, &coff_section_data_cb); + xdata_sym = csd->sym; + + /* Add unwind info. Use line number of start of procedure. */ + yasm_win64__unwind_generate(sect, objfmt_coff->unwind, + objfmt_coff->proc_frame); + objfmt_coff->unwind = NULL; /* generate keeps the unwind pointer */ + + /* + * Add function lookup to end of .pdata section. + */ + + sect = yasm_object_get_general(objfmt_coff->object, ".pdata", 0, 0, 0, 0, + &isnew, line); + + /* Initialize pdata section if needed */ + if (isnew) { + csd = coff_objfmt_init_new_section(objfmt_coff, sect, ".pdata", line); + csd->flags = COFF_STYP_DATA | COFF_STYP_READ; + csd->flags2 = COFF_FLAG_NOBASE; + yasm_section_set_align(sect, 4, line); + } + + /* Add function structure as data bytecode */ + yasm_dvs_initialize(&dvs); + yasm_dvs_append(&dvs, yasm_dv_create_expr( + yasm_expr_create_ident(yasm_expr_sym(proc_sym), line))); + yasm_dvs_append(&dvs, yasm_dv_create_expr( + yasm_expr_create(YASM_EXPR_WRT, yasm_expr_sym(curpos), + yasm_expr_sym(proc_sym), line))); + yasm_dvs_append(&dvs, yasm_dv_create_expr( + yasm_expr_create(YASM_EXPR_WRT, yasm_expr_sym(unwindpos), + yasm_expr_sym(xdata_sym), line))); + yasm_section_bcs_append(sect, yasm_bc_create_data(&dvs, 4, 0, NULL, line)); + + objfmt_coff->proc_frame = 0; + objfmt_coff->done_prolog = 0; +} + +static int +win64_objfmt_directive(yasm_objfmt *objfmt, const char *name, + /*@null@*/ yasm_valparamhead *valparams, + /*@unused@*/ /*@null@*/ + yasm_valparamhead *objext_valparams, + unsigned long line) +{ + yasm_objfmt_coff *objfmt_coff = (yasm_objfmt_coff *)objfmt; + static const struct { + const char *name; + int required_arg; + void (*func) (yasm_objfmt_coff *, yasm_valparamhead *, unsigned long); + } dirs[] = { + {"EXPORT", 1, dir_export}, + {"IDENT", 1, dir_ident}, + {"PROC_FRAME", 0, dir_proc_frame}, + {"PUSHREG", 1, dir_pushreg}, + {"SETFRAME", 1, dir_setframe}, + {"ALLOCSTACK", 1, dir_allocstack}, + {"SAVEREG", 1, dir_savereg}, + {"SAVEXMM128", 1, dir_savexmm128}, + {"PUSHFRAME", 0, dir_pushframe}, + {"ENDPROLOG", 0, dir_endprolog}, + {"ENDPROC_FRAME", 0, dir_endproc_frame} + }; + size_t i; + + for (i=0; i +/*@unused@*/ RCSID("$Id$"); + +#define YASM_LIB_INTERNAL +#define YASM_BC_INTERNAL +#define YASM_EXPR_INTERNAL +#include + +#include "coff-objfmt.h" + + +#define UNW_FLAG_EHANDLER 0x01 +#define UNW_FLAG_UHANDLER 0x02 +#define UNW_FLAG_CHAININFO 0x03 + +/* Bytecode callback function prototypes */ +static void win64_uwinfo_bc_destroy(void *contents); +static void win64_uwinfo_bc_print(const void *contents, FILE *f, + int indent_level); +static void win64_uwinfo_bc_finalize(yasm_bytecode *bc, + yasm_bytecode *prev_bc); +static int win64_uwinfo_bc_calc_len + (yasm_bytecode *bc, yasm_bc_add_span_func add_span, void *add_span_data); +static int win64_uwinfo_bc_expand(yasm_bytecode *bc, int span, long old_val, + long new_val, /*@out@*/ long *neg_thres, + /*@out@*/ long *pos_thres); +static int win64_uwinfo_bc_tobytes + (yasm_bytecode *bc, unsigned char **bufp, void *d, + yasm_output_value_func output_value, + /*@null@*/ yasm_output_reloc_func output_reloc); + +static void win64_uwcode_bc_destroy(void *contents); +static void win64_uwcode_bc_print(const void *contents, FILE *f, + int indent_level); +static void win64_uwcode_bc_finalize(yasm_bytecode *bc, + yasm_bytecode *prev_bc); +static int win64_uwcode_bc_calc_len + (yasm_bytecode *bc, yasm_bc_add_span_func add_span, void *add_span_data); +static int win64_uwcode_bc_expand(yasm_bytecode *bc, int span, long old_val, + long new_val, /*@out@*/ long *neg_thres, + /*@out@*/ long *pos_thres); +static int win64_uwcode_bc_tobytes + (yasm_bytecode *bc, unsigned char **bufp, void *d, + yasm_output_value_func output_value, + /*@null@*/ yasm_output_reloc_func output_reloc); + +/* Bytecode callback structures */ +static const yasm_bytecode_callback win64_uwinfo_bc_callback = { + win64_uwinfo_bc_destroy, + win64_uwinfo_bc_print, + win64_uwinfo_bc_finalize, + win64_uwinfo_bc_calc_len, + win64_uwinfo_bc_expand, + win64_uwinfo_bc_tobytes, + 0 +}; + +static const yasm_bytecode_callback win64_uwcode_bc_callback = { + win64_uwcode_bc_destroy, + win64_uwcode_bc_print, + win64_uwcode_bc_finalize, + win64_uwcode_bc_calc_len, + win64_uwcode_bc_expand, + win64_uwcode_bc_tobytes, + 0 +}; + + +coff_unwind_info * +yasm_win64__uwinfo_create(void) +{ + coff_unwind_info *info = yasm_xmalloc(sizeof(coff_unwind_info)); + info->proc = NULL; + info->prolog = NULL; + info->ehandler = NULL; + info->framereg = 0; + /* Frameoff is really a 4-bit value, scaled by 16 */ + yasm_value_initialize(&info->frameoff, NULL, 8); + SLIST_INIT(&info->codes); + yasm_value_initialize(&info->prolog_size, NULL, 8); + yasm_value_initialize(&info->codes_count, NULL, 8); + return info; +} + +void +yasm_win64__uwinfo_destroy(coff_unwind_info *info) +{ + coff_unwind_code *code; + + yasm_value_delete(&info->frameoff); + yasm_value_delete(&info->prolog_size); + yasm_value_delete(&info->codes_count); + + while (!SLIST_EMPTY(&info->codes)) { + code = SLIST_FIRST(&info->codes); + SLIST_REMOVE_HEAD(&info->codes, link); + yasm_value_delete(&code->off); + yasm_xfree(code); + } + yasm_xfree(info); +} + +void +yasm_win64__unwind_generate(yasm_section *xdata, coff_unwind_info *info, + unsigned long line) +{ + yasm_bytecode *infobc, *codebc = NULL; + coff_unwind_code *code; + + /* 4-byte align the start of unwind info */ + yasm_section_bcs_append(xdata, yasm_bc_create_align( + yasm_expr_create_ident(yasm_expr_int(yasm_intnum_create_uint(4)), + line), + NULL, NULL, NULL, line)); + + /* Prolog size = end of prolog - start of procedure */ + yasm_value_initialize(&info->prolog_size, + yasm_expr_create(YASM_EXPR_SUB, yasm_expr_sym(info->prolog), + yasm_expr_sym(info->proc), line), + 8); + + /* Unwind info */ + infobc = yasm_bc_create_common(&win64_uwinfo_bc_callback, info, line); + yasm_section_bcs_append(xdata, infobc); + + /* Code array */ + SLIST_FOREACH(code, &info->codes, link) { + codebc = yasm_bc_create_common(&win64_uwcode_bc_callback, code, + yasm_symrec_get_line(code->loc)); + yasm_section_bcs_append(xdata, codebc); + } + + /* Avoid double-free (by code destroy and uwinfo destroy). */ + SLIST_INIT(&info->codes); + + /* Number of codes = (Last code - end of info) >> 1 */ + if (!codebc) { + yasm_value_initialize(&info->codes_count, + yasm_expr_create_ident(yasm_expr_int(yasm_intnum_create_uint(0)), + line), + 8); + } else { + yasm_value_initialize(&info->codes_count, + yasm_expr_create(YASM_EXPR_SHR, yasm_expr_expr( + yasm_expr_create(YASM_EXPR_SUB, yasm_expr_precbc(codebc), + yasm_expr_precbc(infobc), line)), + yasm_expr_int(yasm_intnum_create_uint(1)), line), + 8); + } + + /* 4-byte align */ + yasm_section_bcs_append(xdata, yasm_bc_create_align( + yasm_expr_create_ident(yasm_expr_int(yasm_intnum_create_uint(4)), + line), + NULL, NULL, NULL, line)); + + /* Exception handler, if present. Use data bytecode. */ + if (info->ehandler) { + yasm_datavalhead dvs; + + yasm_dvs_initialize(&dvs); + yasm_dvs_append(&dvs, yasm_dv_create_expr( + yasm_expr_create_ident(yasm_expr_sym(info->ehandler), line))); + yasm_section_bcs_append(xdata, + yasm_bc_create_data(&dvs, 4, 0, NULL, line)); + } +} + +static void +win64_uwinfo_bc_destroy(void *contents) +{ + yasm_win64__uwinfo_destroy((coff_unwind_info *)contents); +} + +static void +win64_uwinfo_bc_print(const void *contents, FILE *f, int indent_level) +{ + /* TODO */ +} + +static void +win64_uwinfo_bc_finalize(yasm_bytecode *bc, yasm_bytecode *prev_bc) +{ + coff_unwind_info *info = (coff_unwind_info *)bc->contents; + + if (yasm_value_finalize(&info->prolog_size, prev_bc)) + yasm_internal_error(N_("prolog size expression too complex")); + + if (yasm_value_finalize(&info->codes_count, prev_bc)) + yasm_internal_error(N_("codes count expression too complex")); + + if (yasm_value_finalize(&info->frameoff, prev_bc)) + yasm_error_set(YASM_ERROR_VALUE, + N_("frame offset expression too complex")); +} + +static int +win64_uwinfo_bc_calc_len(yasm_bytecode *bc, yasm_bc_add_span_func add_span, + void *add_span_data) +{ + coff_unwind_info *info = (coff_unwind_info *)bc->contents; + /*@only@*/ /*@null@*/ yasm_intnum *intn; + long intv; + + /* Want to make sure prolog size and codes count doesn't exceed + * byte-size, and scaled frame offset doesn't exceed 4 bits. + */ + add_span(add_span_data, bc, 1, &info->prolog_size, 0, 255); + add_span(add_span_data, bc, 2, &info->codes_count, 0, 255); + + intn = yasm_value_get_intnum(&info->frameoff, bc, 0); + if (intn) { + intv = yasm_intnum_get_int(intn); + if (intv < 0 || intv > 240) + yasm_error_set(YASM_ERROR_VALUE, + N_("frame offset of %ld bytes, must be between 0 and 240"), + intv); + else if ((intv & 0xF) != 0) + yasm_error_set(YASM_ERROR_VALUE, + N_("frame offset of %ld is not a multiple of 16"), intv); + yasm_intnum_destroy(intn); + } else + add_span(add_span_data, bc, 3, &info->frameoff, 0, 240); + + bc->len += 4; + return 0; +} + +static int +win64_uwinfo_bc_expand(yasm_bytecode *bc, int span, long old_val, long new_val, + /*@out@*/ long *neg_thres, /*@out@*/ long *pos_thres) +{ + coff_unwind_info *info = (coff_unwind_info *)bc->contents; + switch (span) { + case 1: + yasm_error_set_xref(yasm_symrec_get_line(info->prolog), + N_("prologue ended here")); + yasm_error_set(YASM_ERROR_VALUE, + N_("prologue %ld bytes, must be <256"), new_val); + return -1; + case 2: + yasm_error_set(YASM_ERROR_VALUE, + N_("%ld unwind codes, maximum of 255"), new_val); + return -1; + case 3: + yasm_error_set(YASM_ERROR_VALUE, + N_("frame offset of %ld bytes, must be between 0 and 240"), + new_val); + return -1; + default: + yasm_internal_error(N_("unrecognized span id")); + } + return 0; +} + +static int +win64_uwinfo_bc_tobytes(yasm_bytecode *bc, unsigned char **bufp, void *d, + yasm_output_value_func output_value, + yasm_output_reloc_func output_reloc) +{ + coff_unwind_info *info = (coff_unwind_info *)bc->contents; + unsigned char *buf = *bufp; + /*@only@*/ /*@null@*/ yasm_intnum *frameoff; + long intv; + + /* Version and flags */ + if (info->ehandler) + YASM_WRITE_8(buf, 1 | (UNW_FLAG_EHANDLER << 3)); + else + YASM_WRITE_8(buf, 1); + + /* Size of prolog */ + output_value(&info->prolog_size, buf, 1, (unsigned long)(buf-*bufp), + bc, 1, d); + buf += 1; + + /* Count of codes */ + output_value(&info->codes_count, buf, 1, (unsigned long)(buf-*bufp), + bc, 1, d); + buf += 1; + + /* Frame register and offset */ + frameoff = yasm_value_get_intnum(&info->frameoff, bc, 1); + if (!frameoff) { + yasm_error_set(YASM_ERROR_VALUE, + N_("frame offset expression too complex")); + return 1; + } + intv = yasm_intnum_get_int(frameoff); + if (intv < 0 || intv > 240) + yasm_error_set(YASM_ERROR_VALUE, + N_("frame offset of %ld bytes, must be between 0 and 240"), intv); + else if ((intv & 0xF) != 0) + yasm_error_set(YASM_ERROR_VALUE, + N_("frame offset of %ld is not a multiple of 16"), intv); + + YASM_WRITE_8(buf, ((unsigned long)intv & 0xF0) | (info->framereg & 0x0F)); + yasm_intnum_destroy(frameoff); + + *bufp = buf; + return 0; +} + +static void +win64_uwcode_bc_destroy(void *contents) +{ + coff_unwind_code *code = (coff_unwind_code *)contents; + yasm_value_delete(&code->off); + yasm_xfree(contents); +} + +static void +win64_uwcode_bc_print(const void *contents, FILE *f, int indent_level) +{ + /* TODO */ +} + +static void +win64_uwcode_bc_finalize(yasm_bytecode *bc, yasm_bytecode *prev_bc) +{ + coff_unwind_code *code = (coff_unwind_code *)bc->contents; + if (yasm_value_finalize(&code->off, prev_bc)) + yasm_error_set(YASM_ERROR_VALUE, N_("offset expression too complex")); +} + +static int +win64_uwcode_bc_calc_len(yasm_bytecode *bc, yasm_bc_add_span_func add_span, + void *add_span_data) +{ + coff_unwind_code *code = (coff_unwind_code *)bc->contents; + int span = 0; + /*@only@*/ /*@null@*/ yasm_intnum *intn; + long intv; + long low, high, mask; + + bc->len += 2; /* Prolog offset, code, and info */ + + switch (code->opcode) { + case UWOP_PUSH_NONVOL: + case UWOP_SET_FPREG: + case UWOP_PUSH_MACHFRAME: + /* always 1 node */ + return 0; + case UWOP_ALLOC_SMALL: + case UWOP_ALLOC_LARGE: + /* Start with smallest, then work our way up as necessary */ + code->opcode = UWOP_ALLOC_SMALL; + code->info = 0; + span = 1; low = 8; high = 128; mask = 0x7; + break; + case UWOP_SAVE_NONVOL: + case UWOP_SAVE_NONVOL_FAR: + /* Start with smallest, then work our way up as necessary */ + code->opcode = UWOP_SAVE_NONVOL; + bc->len += 2; /* Scaled offset */ + span = 2; + low = 0; + high = 8*64*1024-8; /* 16-bit field, *8 scaling */ + mask = 0x7; + break; + case UWOP_SAVE_XMM128: + case UWOP_SAVE_XMM128_FAR: + /* Start with smallest, then work our way up as necessary */ + code->opcode = UWOP_SAVE_XMM128; + bc->len += 2; /* Scaled offset */ + span = 3; + low = 0; + high = 16*64*1024-16; /* 16-bit field, *16 scaling */ + mask = 0xF; + break; + default: + yasm_internal_error(N_("unrecognied unwind opcode")); + } + + intn = yasm_value_get_intnum(&code->off, bc, 0); + if (intn) { + intv = yasm_intnum_get_int(intn); + if (intv > high) { + /* Expand it ourselves here if we can and we're already larger */ + if (win64_uwcode_bc_expand(bc, span, intv, intv, &low, &high) > 0) + add_span(add_span_data, bc, span, &code->off, low, high); + } + if (intv < low) + yasm_error_set(YASM_ERROR_VALUE, + N_("negative offset not allowed")); + if ((intv & mask) != 0) + yasm_error_set(YASM_ERROR_VALUE, + N_("offset of %ld is not a multiple of %ld"), intv, mask+1); + yasm_intnum_destroy(intn); + } else + add_span(add_span_data, bc, span, &code->off, low, high); + return 0; +} + +static int +win64_uwcode_bc_expand(yasm_bytecode *bc, int span, long old_val, long new_val, + /*@out@*/ long *neg_thres, /*@out@*/ long *pos_thres) +{ + coff_unwind_code *code = (coff_unwind_code *)bc->contents; + + if (new_val < 0) { + yasm_error_set(YASM_ERROR_VALUE, N_("negative offset not allowed")); + return -1; + } + + if (span == 1) { + /* 3 stages: SMALL, LARGE and info=0, LARGE and info=1 */ + if (code->opcode == UWOP_ALLOC_LARGE && code->info == 1) + yasm_internal_error(N_("expansion on already largest alloc")); + + if (code->opcode == UWOP_ALLOC_SMALL && new_val > 128) { + /* Overflowed small size */ + code->opcode = UWOP_ALLOC_LARGE; + bc->len += 2; + } + if (new_val <= 8*64*1024-8) { + /* Still can grow one more size */ + *pos_thres = 8*64*1024-8; + return 1; + } + /* We're into the largest size */ + code->info = 1; + bc->len += 2; + } else if (code->opcode == UWOP_SAVE_NONVOL && span == 2) { + code->opcode = UWOP_SAVE_NONVOL_FAR; + bc->len += 2; + } else if (code->opcode == UWOP_SAVE_XMM128 && span == 3) { + code->opcode = UWOP_SAVE_XMM128_FAR; + bc->len += 2; + } + return 0; +} + +static int +win64_uwcode_bc_tobytes(yasm_bytecode *bc, unsigned char **bufp, void *d, + yasm_output_value_func output_value, + yasm_output_reloc_func output_reloc) +{ + coff_unwind_code *code = (coff_unwind_code *)bc->contents; + unsigned char *buf = *bufp; + yasm_value val; + unsigned int size; + int shift; + long intv, low, high, mask; + yasm_intnum *intn; + + /* Offset in prolog */ + yasm_value_initialize(&val, + yasm_expr_create(YASM_EXPR_SUB, yasm_expr_sym(code->loc), + yasm_expr_sym(code->proc), bc->line), + 8); + output_value(&val, buf, 1, (unsigned long)(buf-*bufp), bc, 1, d); + buf += 1; + yasm_value_delete(&val); + + /* Offset value */ + switch (code->opcode) { + case UWOP_PUSH_NONVOL: + case UWOP_SET_FPREG: + case UWOP_PUSH_MACHFRAME: + /* just 1 node, no offset; write opcode and info and we're done */ + YASM_WRITE_8(buf, (code->info << 4) | (code->opcode & 0xF)); + *bufp = buf; + return 0; + case UWOP_ALLOC_SMALL: + /* 1 node, but offset stored in info */ + size = 0; low = 8; high = 128; shift = 3; mask = 0x7; + break; + case UWOP_ALLOC_LARGE: + if (code->info == 0) { + size = 2; low = 136; high = 8*64*1024-8; shift = 3; + } else { + size = 4; low = high = 0; shift = 0; + } + mask = 0x7; + break; + case UWOP_SAVE_NONVOL: + size = 2; low = 0; high = 8*64*1024-8; shift = 3; mask = 0x7; + break; + case UWOP_SAVE_XMM128: + size = 2; low = 0; high = 16*64*1024-16; shift = 4; mask = 0xF; + break; + case UWOP_SAVE_NONVOL_FAR: + size = 4; low = high = 0; shift = 0; mask = 0x7; + break; + case UWOP_SAVE_XMM128_FAR: + size = 4; low = high = 0; shift = 0; mask = 0xF; + break; + } + + /* Check for overflow */ + intn = yasm_value_get_intnum(&code->off, bc, 1); + if (!intn) { + yasm_error_set(YASM_ERROR_VALUE, N_("offset expression too complex")); + return 1; + } + intv = yasm_intnum_get_int(intn); + if (size != 4 && (intv < low || intv > high)) { + yasm_error_set(YASM_ERROR_VALUE, + N_("offset of %ld bytes, must be between %ld and %ld"), + intv, low, high); + return 1; + } + if ((intv & mask) != 0) { + yasm_error_set(YASM_ERROR_VALUE, + N_("offset of %ld is not a multiple of %ld"), + intv, mask+1); + return 1; + } + + /* Stored value in info instead of extra code space */ + if (size == 0) + code->info = (yasm_intnum_get_uint(intn) >> shift)-1; + + /* Opcode and info */ + YASM_WRITE_8(buf, (code->info << 4) | (code->opcode & 0xF)); + + if (size != 0) { + yasm_intnum_get_sized(intn, buf, size, size*8, -shift, 0, 1); + buf += size; + } + + yasm_intnum_destroy(intn); + + *bufp = buf; + return 0; +} diff --git a/modules/objfmts/win64/tests/Makefile.inc b/modules/objfmts/win64/tests/Makefile.inc index b603e04c..4bc0907c 100644 --- a/modules/objfmts/win64/tests/Makefile.inc +++ b/modules/objfmts/win64/tests/Makefile.inc @@ -3,6 +3,22 @@ TESTS += modules/objfmts/win64/tests/win64_test.sh EXTRA_DIST += modules/objfmts/win64/tests/win64_test.sh +EXTRA_DIST += modules/objfmts/win64/tests/sce1.asm +EXTRA_DIST += modules/objfmts/win64/tests/sce1.hex +EXTRA_DIST += modules/objfmts/win64/tests/sce1-err.asm +EXTRA_DIST += modules/objfmts/win64/tests/sce1-err.errwarn +EXTRA_DIST += modules/objfmts/win64/tests/sce2.asm +EXTRA_DIST += modules/objfmts/win64/tests/sce2.hex +EXTRA_DIST += modules/objfmts/win64/tests/sce2-err.asm +EXTRA_DIST += modules/objfmts/win64/tests/sce2-err.errwarn +EXTRA_DIST += modules/objfmts/win64/tests/sce3.asm +EXTRA_DIST += modules/objfmts/win64/tests/sce3.hex +EXTRA_DIST += modules/objfmts/win64/tests/sce3.masm +EXTRA_DIST += modules/objfmts/win64/tests/sce4.asm +EXTRA_DIST += modules/objfmts/win64/tests/sce4.hex +EXTRA_DIST += modules/objfmts/win64/tests/sce4.masm +EXTRA_DIST += modules/objfmts/win64/tests/sce4-err.asm +EXTRA_DIST += modules/objfmts/win64/tests/sce4-err.errwarn EXTRA_DIST += modules/objfmts/win64/tests/win64-curpos.asm EXTRA_DIST += modules/objfmts/win64/tests/win64-curpos.hex EXTRA_DIST += modules/objfmts/win64/tests/win64-dataref.asm diff --git a/modules/objfmts/win64/tests/sce1-err.asm b/modules/objfmts/win64/tests/sce1-err.asm new file mode 100644 index 00000000..a356b5e3 --- /dev/null +++ b/modules/objfmts/win64/tests/sce1-err.asm @@ -0,0 +1,36 @@ +PROC_FRAME sample1 +[pushreg rbp] +[allocstack 040h] +[setframe rbp, 020h] +[savexmm128 xmm7, 020h] +[savereg rsi, 038h] +[savereg rdi, 010h] +;END_PROLOGUE +ENDPROC_FRAME + +PROC_FRAME sample2 +[pushreg rbp] +[allocstack 040h] +[setframe rbp, 020h] +[savexmm128 xmm7, 020h] +[savereg rsi, 038h] +[savereg rdi, 010h] +;END_PROLOGUE + +PROC_FRAME sample3 +[pushreg rbp] +[allocstack 040h] +[setframe rbp, 020h] +[savexmm128 xmm7, 020h] +[savereg rsi, 038h] +END_PROLOGUE +[savereg rdi, 010h] + +ENDPROC_FRAME + +END_PROLOGUE +[savereg rdi, 010h] + +PROC_FRAME sample4 +[pushreg rbp] + diff --git a/modules/objfmts/win64/tests/sce1-err.errwarn b/modules/objfmts/win64/tests/sce1-err.errwarn new file mode 100644 index 00000000..f5b67933 --- /dev/null +++ b/modules/objfmts/win64/tests/sce1-err.errwarn @@ -0,0 +1,8 @@ +-:9: ended procedure without ending prologue +-:1: procedure started here +-:20: nested procedures not supported (didn't use [ENDPROC_FRAME]?) +-:11: previous procedure started here +-:27: [SAVEREG] after end of prologue +-:26: prologue ended here +-:31: [ENDPROLOG] without preceding [PROC_FRAME] +-:32: [SAVEREG] without preceding [PROC_FRAME] diff --git a/modules/objfmts/win64/tests/sce1.asm b/modules/objfmts/win64/tests/sce1.asm new file mode 100644 index 00000000..a021e825 --- /dev/null +++ b/modules/objfmts/win64/tests/sce1.asm @@ -0,0 +1,44 @@ +PROC_FRAME sample + db 048h; emit a REX prefix, to enable hot-patching +push rbp +[pushreg rbp] +sub rsp, 040h +[allocstack 040h] +lea rbp, [rsp+020h] +[setframe rbp, 020h] +movdqa [rbp], xmm7 +[savexmm128 xmm7, 020h];the offset is from the base of the frame +;not the scaled offset of the frame +mov [rbp+018h], rsi +[savereg rsi, 018h] +mov [rsp+010h], rdi +[savereg rdi, 010h]; you can still use RSP as the base of the frame +; or any other register you choose +END_PROLOGUE + +; you can modify the stack pointer outside of the prologue (similar to alloca) +; because we have a frame pointer. +; if we didn't have a frame pointer, this would be illegal +; if we didn't make this modification, +; there would be no need for a frame pointer + +sub rsp, 060h + +; we can unwind from the following AV because of the frame pointer + +mov rax, 0 +mov rax, [rax] ; AV! + +; restore the registers that weren't saved with a push +; this isn't part of the official epilog, as described in section 2.5 + +movdqa xmm7, [rbp] +mov rsi, [rbp+018h] +mov rdi, [rbp-010h] + +; Here's the official epilog + +lea rsp, [rbp-020h] +pop rbp +ret +ENDPROC_FRAME diff --git a/modules/objfmts/win64/tests/sce1.hex b/modules/objfmts/win64/tests/sce1.hex new file mode 100644 index 00000000..d6b1427c --- /dev/null +++ b/modules/objfmts/win64/tests/sce1.hex @@ -0,0 +1,430 @@ +64 +86 +03 +00 +00 +00 +00 +00 +08 +01 +00 +00 +09 +00 +00 +00 +00 +00 +04 +00 +2e +74 +65 +78 +74 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +3a +00 +00 +00 +8c +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +20 +00 +50 +60 +2e +78 +64 +61 +74 +61 +00 +00 +3a +00 +00 +00 +00 +00 +00 +00 +18 +00 +00 +00 +c6 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +40 +00 +40 +40 +2e +70 +64 +61 +74 +61 +00 +00 +52 +00 +00 +00 +00 +00 +00 +00 +0c +00 +00 +00 +de +00 +00 +00 +ea +00 +00 +00 +00 +00 +00 +00 +03 +00 +00 +00 +40 +00 +30 +40 +48 +55 +48 +83 +ec +40 +48 +8d +6c +24 +20 +66 +0f +7f +7d +00 +48 +89 +75 +18 +48 +89 +7c +24 +10 +48 +83 +ec +60 +48 +c7 +c0 +00 +00 +00 +00 +48 +8b +00 +66 +0f +6f +7d +00 +48 +8b +75 +18 +48 +8b +7d +f0 +48 +8d +65 +e0 +5d +c3 +01 +19 +09 +25 +19 +74 +02 +00 +14 +64 +03 +00 +10 +78 +02 +00 +0b +53 +06 +72 +02 +50 +00 +00 +00 +00 +00 +00 +3a +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +04 +00 +00 +00 +03 +00 +04 +00 +00 +00 +04 +00 +00 +00 +03 +00 +08 +00 +00 +00 +05 +00 +00 +00 +03 +00 +2e +66 +69 +6c +65 +00 +00 +00 +00 +00 +00 +00 +fe +ff +00 +00 +67 +01 +2d +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +2e +74 +65 +78 +74 +00 +00 +00 +00 +00 +00 +00 +01 +00 +00 +00 +03 +01 +3a +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +73 +61 +6d +70 +6c +65 +00 +00 +00 +00 +00 +00 +01 +00 +00 +00 +03 +00 +2e +78 +64 +61 +74 +61 +00 +00 +00 +00 +00 +00 +02 +00 +00 +00 +03 +01 +18 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +2e +70 +64 +61 +74 +61 +00 +00 +00 +00 +00 +00 +03 +00 +00 +00 +03 +01 +0c +00 +00 +00 +03 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +04 +00 +00 +00 diff --git a/modules/objfmts/win64/tests/sce2-err.asm b/modules/objfmts/win64/tests/sce2-err.asm new file mode 100644 index 00000000..b5ce9579 --- /dev/null +++ b/modules/objfmts/win64/tests/sce2-err.asm @@ -0,0 +1,3 @@ +PROC_FRAME sample4 +[pushreg rbp] + diff --git a/modules/objfmts/win64/tests/sce2-err.errwarn b/modules/objfmts/win64/tests/sce2-err.errwarn new file mode 100644 index 00000000..d7f0d290 --- /dev/null +++ b/modules/objfmts/win64/tests/sce2-err.errwarn @@ -0,0 +1,2 @@ +-: end of file in procedure frame +-:1: procedure started here diff --git a/modules/objfmts/win64/tests/sce2.asm b/modules/objfmts/win64/tests/sce2.asm new file mode 100644 index 00000000..d76f9463 --- /dev/null +++ b/modules/objfmts/win64/tests/sce2.asm @@ -0,0 +1,29 @@ +struc kFrame +.Fill resq 1 ; fill to 8 mod 16 +.SavedRdi resq 1 ; saved register RDI +.SavedRsi resq 1 ; saved register RSI +endstruc + +struc sampleFrame +.Fill resq 1 ; fill to 8 mod 16 +.SavedRdi resq 1 ; Saved Register RDI +.SavedRsi resq 1 ; Saved Register RSI +endstruc + +PROC_FRAME sample2 +alloc_stack sampleFrame_size +save_reg rdi, sampleFrame.SavedRdi +save_reg rsi, sampleFrame.SavedRsi +END_PROLOGUE + +; function body + +mov rsi, [rsp+sampleFrame.SavedRsi] +mov rdi, [rsp+sampleFrame.SavedRdi] + +; Here's the official epilog + +add rsp, sampleFrame_size +ret +ENDPROC_FRAME + diff --git a/modules/objfmts/win64/tests/sce2.hex b/modules/objfmts/win64/tests/sce2.hex new file mode 100644 index 00000000..1caa10c7 --- /dev/null +++ b/modules/objfmts/win64/tests/sce2.hex @@ -0,0 +1,717 @@ +64 +86 +03 +00 +00 +00 +00 +00 +e3 +00 +00 +00 +13 +00 +00 +00 +00 +00 +04 +00 +2e +74 +65 +78 +74 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +1d +00 +00 +00 +8c +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +20 +00 +50 +60 +2e +78 +64 +61 +74 +61 +00 +00 +1d +00 +00 +00 +00 +00 +00 +00 +10 +00 +00 +00 +a9 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +40 +00 +40 +40 +2e +70 +64 +61 +74 +61 +00 +00 +2d +00 +00 +00 +00 +00 +00 +00 +0c +00 +00 +00 +b9 +00 +00 +00 +c5 +00 +00 +00 +00 +00 +00 +00 +03 +00 +00 +00 +40 +00 +30 +40 +48 +83 +ec +18 +48 +89 +7c +24 +08 +48 +89 +74 +24 +10 +48 +8b +74 +24 +10 +48 +8b +7c +24 +08 +48 +83 +c4 +18 +c3 +01 +0e +05 +00 +0e +64 +02 +00 +09 +74 +01 +00 +04 +22 +00 +00 +00 +00 +00 +00 +1d +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +0e +00 +00 +00 +03 +00 +04 +00 +00 +00 +0e +00 +00 +00 +03 +00 +08 +00 +00 +00 +0f +00 +00 +00 +03 +00 +2e +66 +69 +6c +65 +00 +00 +00 +00 +00 +00 +00 +fe +ff +00 +00 +67 +01 +2d +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +2e +74 +65 +78 +74 +00 +00 +00 +00 +00 +00 +00 +01 +00 +00 +00 +03 +01 +1d +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +6b +46 +72 +61 +6d +65 +00 +00 +00 +00 +00 +00 +ff +ff +00 +00 +03 +00 +00 +00 +00 +00 +04 +00 +00 +00 +00 +00 +00 +00 +ff +ff +00 +00 +03 +00 +00 +00 +00 +00 +10 +00 +00 +00 +08 +00 +00 +00 +ff +ff +00 +00 +03 +00 +00 +00 +00 +00 +20 +00 +00 +00 +10 +00 +00 +00 +ff +ff +00 +00 +03 +00 +00 +00 +00 +00 +30 +00 +00 +00 +18 +00 +00 +00 +ff +ff +00 +00 +03 +00 +00 +00 +00 +00 +3c +00 +00 +00 +00 +00 +00 +00 +ff +ff +00 +00 +03 +00 +00 +00 +00 +00 +48 +00 +00 +00 +00 +00 +00 +00 +ff +ff +00 +00 +03 +00 +00 +00 +00 +00 +59 +00 +00 +00 +08 +00 +00 +00 +ff +ff +00 +00 +03 +00 +00 +00 +00 +00 +6e +00 +00 +00 +10 +00 +00 +00 +ff +ff +00 +00 +03 +00 +00 +00 +00 +00 +83 +00 +00 +00 +18 +00 +00 +00 +ff +ff +00 +00 +03 +00 +73 +61 +6d +70 +6c +65 +32 +00 +00 +00 +00 +00 +01 +00 +00 +00 +03 +00 +2e +78 +64 +61 +74 +61 +00 +00 +00 +00 +00 +00 +02 +00 +00 +00 +03 +01 +10 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +2e +70 +64 +61 +74 +61 +00 +00 +00 +00 +00 +00 +03 +00 +00 +00 +03 +01 +0c +00 +00 +00 +03 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +94 +00 +00 +00 +6b +46 +72 +61 +6d +65 +2e +46 +69 +6c +6c +00 +6b +46 +72 +61 +6d +65 +2e +53 +61 +76 +65 +64 +52 +64 +69 +00 +6b +46 +72 +61 +6d +65 +2e +53 +61 +76 +65 +64 +52 +73 +69 +00 +6b +46 +72 +61 +6d +65 +5f +73 +69 +7a +65 +00 +73 +61 +6d +70 +6c +65 +46 +72 +61 +6d +65 +00 +73 +61 +6d +70 +6c +65 +46 +72 +61 +6d +65 +2e +46 +69 +6c +6c +00 +73 +61 +6d +70 +6c +65 +46 +72 +61 +6d +65 +2e +53 +61 +76 +65 +64 +52 +64 +69 +00 +73 +61 +6d +70 +6c +65 +46 +72 +61 +6d +65 +2e +53 +61 +76 +65 +64 +52 +73 +69 +00 +73 +61 +6d +70 +6c +65 +46 +72 +61 +6d +65 +5f +73 +69 +7a +65 +00 diff --git a/modules/objfmts/win64/tests/sce3.asm b/modules/objfmts/win64/tests/sce3.asm new file mode 100644 index 00000000..788fe6bd --- /dev/null +++ b/modules/objfmts/win64/tests/sce3.asm @@ -0,0 +1,73 @@ +PROC_FRAME sample + db 048h; emit a REX prefix, to enable hot-patching +push rbp +[pushreg rbp] +sub rsp, 040h +[allocstack 040h] +lea rbp, [rsp+020h] +[setframe rbp, 020h] +movdqa [rbp], xmm7 +[savexmm128 xmm7, 020h];the offset is from the base of the frame +;not the scaled offset of the frame +mov [rbp+018h], rsi +[savereg rsi, 018h] +mov [rsp+010h], rdi +[savereg rdi, 010h]; you can still use RSP as the base of the frame +; or any other register you choose +END_PROLOGUE + +; you can modify the stack pointer outside of the prologue (similar to alloca) +; because we have a frame pointer. +; if we didn't have a frame pointer, this would be illegal +; if we didn't make this modification, +; there would be no need for a frame pointer + +sub rsp, 060h + +; we can unwind from the following AV because of the frame pointer + +mov rax, 0 +mov rax, [rax] ; AV! + +; restore the registers that weren't saved with a push +; this isn't part of the official epilog, as described in section 2.5 + +movdqa xmm7, [rbp] +mov rsi, [rbp+018h] +mov rdi, [rbp-010h] + +; Here's the official epilog + +lea rsp, [rbp-020h] +pop rbp +ret +ENDPROC_FRAME +struc kFrame +.Fill resq 1 ; fill to 8 mod 16 +.SavedRdi resq 1 ; saved register RDI +.SavedRsi resq 1 ; saved register RSI +endstruc + +struc sampleFrame +.Fill resq 1 ; fill to 8 mod 16 +.SavedRdi resq 1 ; Saved Register RDI +.SavedRsi resq 1 ; Saved Register RSI +endstruc + +PROC_FRAME sample2 +alloc_stack sampleFrame_size +save_reg rdi, sampleFrame.SavedRdi +save_reg rsi, sampleFrame.SavedRsi +END_PROLOGUE + +; function body + +mov rsi, [rsp+sampleFrame.SavedRsi] +mov rdi, [rsp+sampleFrame.SavedRdi] + +; Here's the official epilog + +add rsp, sampleFrame_size +ret +ENDPROC_FRAME + diff --git a/modules/objfmts/win64/tests/sce3.hex b/modules/objfmts/win64/tests/sce3.hex new file mode 100644 index 00000000..cadf8b94 --- /dev/null +++ b/modules/objfmts/win64/tests/sce3.hex @@ -0,0 +1,859 @@ +64 +86 +03 +00 +00 +00 +00 +00 +5f +01 +00 +00 +14 +00 +00 +00 +00 +00 +04 +00 +2e +74 +65 +78 +74 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +57 +00 +00 +00 +8c +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +20 +00 +50 +60 +2e +78 +64 +61 +74 +61 +00 +00 +57 +00 +00 +00 +00 +00 +00 +00 +28 +00 +00 +00 +e3 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +40 +00 +40 +40 +2e +70 +64 +61 +74 +61 +00 +00 +7f +00 +00 +00 +00 +00 +00 +00 +18 +00 +00 +00 +0b +01 +00 +00 +23 +01 +00 +00 +00 +00 +00 +00 +06 +00 +00 +00 +40 +00 +30 +40 +48 +55 +48 +83 +ec +40 +48 +8d +6c +24 +20 +66 +0f +7f +7d +00 +48 +89 +75 +18 +48 +89 +7c +24 +10 +48 +83 +ec +60 +48 +c7 +c0 +00 +00 +00 +00 +48 +8b +00 +66 +0f +6f +7d +00 +48 +8b +75 +18 +48 +8b +7d +f0 +48 +8d +65 +e0 +5d +c3 +48 +83 +ec +18 +48 +89 +7c +24 +08 +48 +89 +74 +24 +10 +48 +8b +74 +24 +10 +48 +8b +7c +24 +08 +48 +83 +c4 +18 +c3 +01 +19 +09 +25 +19 +74 +02 +00 +14 +64 +03 +00 +10 +78 +02 +00 +0b +53 +06 +72 +02 +50 +00 +00 +01 +0e +05 +00 +0e +64 +02 +00 +09 +74 +01 +00 +04 +22 +00 +00 +00 +00 +00 +00 +3a +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +1d +00 +00 +00 +18 +00 +00 +00 +00 +00 +00 +00 +04 +00 +00 +00 +03 +00 +04 +00 +00 +00 +04 +00 +00 +00 +03 +00 +08 +00 +00 +00 +05 +00 +00 +00 +03 +00 +0c +00 +00 +00 +13 +00 +00 +00 +03 +00 +10 +00 +00 +00 +13 +00 +00 +00 +03 +00 +14 +00 +00 +00 +05 +00 +00 +00 +03 +00 +2e +66 +69 +6c +65 +00 +00 +00 +00 +00 +00 +00 +fe +ff +00 +00 +67 +01 +2d +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +2e +74 +65 +78 +74 +00 +00 +00 +00 +00 +00 +00 +01 +00 +00 +00 +03 +01 +57 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +73 +61 +6d +70 +6c +65 +00 +00 +00 +00 +00 +00 +01 +00 +00 +00 +03 +00 +2e +78 +64 +61 +74 +61 +00 +00 +00 +00 +00 +00 +02 +00 +00 +00 +03 +01 +28 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +2e +70 +64 +61 +74 +61 +00 +00 +00 +00 +00 +00 +03 +00 +00 +00 +03 +01 +18 +00 +00 +00 +06 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +6b +46 +72 +61 +6d +65 +00 +00 +00 +00 +00 +00 +ff +ff +00 +00 +03 +00 +00 +00 +00 +00 +04 +00 +00 +00 +00 +00 +00 +00 +ff +ff +00 +00 +03 +00 +00 +00 +00 +00 +10 +00 +00 +00 +08 +00 +00 +00 +ff +ff +00 +00 +03 +00 +00 +00 +00 +00 +20 +00 +00 +00 +10 +00 +00 +00 +ff +ff +00 +00 +03 +00 +00 +00 +00 +00 +30 +00 +00 +00 +18 +00 +00 +00 +ff +ff +00 +00 +03 +00 +00 +00 +00 +00 +3c +00 +00 +00 +00 +00 +00 +00 +ff +ff +00 +00 +03 +00 +00 +00 +00 +00 +48 +00 +00 +00 +00 +00 +00 +00 +ff +ff +00 +00 +03 +00 +00 +00 +00 +00 +59 +00 +00 +00 +08 +00 +00 +00 +ff +ff +00 +00 +03 +00 +00 +00 +00 +00 +6e +00 +00 +00 +10 +00 +00 +00 +ff +ff +00 +00 +03 +00 +00 +00 +00 +00 +83 +00 +00 +00 +18 +00 +00 +00 +ff +ff +00 +00 +03 +00 +73 +61 +6d +70 +6c +65 +32 +00 +3a +00 +00 +00 +01 +00 +00 +00 +03 +00 +94 +00 +00 +00 +6b +46 +72 +61 +6d +65 +2e +46 +69 +6c +6c +00 +6b +46 +72 +61 +6d +65 +2e +53 +61 +76 +65 +64 +52 +64 +69 +00 +6b +46 +72 +61 +6d +65 +2e +53 +61 +76 +65 +64 +52 +73 +69 +00 +6b +46 +72 +61 +6d +65 +5f +73 +69 +7a +65 +00 +73 +61 +6d +70 +6c +65 +46 +72 +61 +6d +65 +00 +73 +61 +6d +70 +6c +65 +46 +72 +61 +6d +65 +2e +46 +69 +6c +6c +00 +73 +61 +6d +70 +6c +65 +46 +72 +61 +6d +65 +2e +53 +61 +76 +65 +64 +52 +64 +69 +00 +73 +61 +6d +70 +6c +65 +46 +72 +61 +6d +65 +2e +53 +61 +76 +65 +64 +52 +73 +69 +00 +73 +61 +6d +70 +6c +65 +46 +72 +61 +6d +65 +5f +73 +69 +7a +65 +00 diff --git a/modules/objfmts/win64/tests/sce3.masm b/modules/objfmts/win64/tests/sce3.masm new file mode 100644 index 00000000..7bac248f --- /dev/null +++ b/modules/objfmts/win64/tests/sce3.masm @@ -0,0 +1,74 @@ +include macamd64.inc + +_TEXT SEGMENT +sample PROC FRAME + db 048h; emit a REX prefix, to enable hot-patching +push rbp +.pushreg rbp +sub rsp, 040h +.allocstack 040h +lea rbp, [rsp+020h] +.setframe rbp, 020h +movdqa [rbp], xmm7 +.savexmm128 xmm7, 020h;the offset is from the base of the frame +;not the scaled offset of the frame +mov [rbp+018h], rsi +.savereg rsi, 018h +mov [rsp+010h], rdi +.savereg rdi, 010h; you can still use RSP as the base of the frame +; or any other register you choose +.endprolog + +; you can modify the stack pointer outside of the prologue (similar to alloca) +; because we have a frame pointer. +; if we didn't have a frame pointer, this would be illegal +; if we didn't make this modification, +; there would be no need for a frame pointer + +sub rsp, 060h + +; we can unwind from the following AV because of the frame pointer + +mov rax, 0 +mov rax, [rax] ; AV! + +; restore the registers that weren't saved with a push +; this isn't part of the official epilog, as described in section 2.5 + +movdqa xmm7, [rbp] +mov rsi, [rbp+018h] +mov rdi, [rbp-010h] + +; Here's the official epilog + +lea rsp, [rbp-020h] +pop rbp +ret +sample ENDP + + +sampleFrame struct +Fill dq ? ; fill to 8 mod 16 +SavedRdi dq ? ; Saved Register RDI +SavedRsi dq ? ; Saved Register RSI +sampleFrame ends + +sample2 PROC FRAME +alloc_stack(sizeof sampleFrame) +save_reg rdi, sampleFrame.SavedRdi +save_reg rsi, sampleFrame.SavedRsi +.endprolog + +; function body + +mov rsi, sampleFrame.SavedRsi[rsp] +mov rdi, sampleFrame.SavedRdi[rsp] + +; Here's the official epilog + +add rsp, (sizeof sampleFrame) +ret +sample2 ENDP + +_TEXT ENDS +end diff --git a/modules/objfmts/win64/tests/sce4-err.asm b/modules/objfmts/win64/tests/sce4-err.asm new file mode 100644 index 00000000..402f7e96 --- /dev/null +++ b/modules/objfmts/win64/tests/sce4-err.asm @@ -0,0 +1,24 @@ +; Negatives +PROC_FRAME sample +[allocstack 0-8] +[setframe rbp, 0-4] +[savexmm128 xmm7, 0-16] +[savereg rsi, 0-8] +END_PROLOGUE +ENDPROC_FRAME + +; Too positive +PROC_FRAME sample2 +[setframe rbp, 248] +END_PROLOGUE +ENDPROC_FRAME + +; Misaligned +PROC_FRAME sample3 +[allocstack 128-4] +[setframe rbp, 240-4] +[savexmm128 xmm7, 1024+8] +[savereg rsi, 1024+4] +END_PROLOGUE +ENDPROC_FRAME + diff --git a/modules/objfmts/win64/tests/sce4-err.errwarn b/modules/objfmts/win64/tests/sce4-err.errwarn new file mode 100644 index 00000000..92d9cb02 --- /dev/null +++ b/modules/objfmts/win64/tests/sce4-err.errwarn @@ -0,0 +1,9 @@ +-:2: frame offset of -4 bytes, must be between 0 and 240 +-:3: negative offset not allowed +-:5: negative offset not allowed +-:6: negative offset not allowed +-:11: frame offset of 248 bytes, must be between 0 and 240 +-:17: frame offset of 236 is not a multiple of 16 +-:18: offset of 124 is not a multiple of 8 +-:20: offset of 1032 is not a multiple of 16 +-:21: offset of 1028 is not a multiple of 8 diff --git a/modules/objfmts/win64/tests/sce4.asm b/modules/objfmts/win64/tests/sce4.asm new file mode 100644 index 00000000..4072b246 --- /dev/null +++ b/modules/objfmts/win64/tests/sce4.asm @@ -0,0 +1,30 @@ +PROC_FRAME sample +[allocstack 8] ; smallest value +[setframe rbp, 0] ; smallest value +[savexmm128 xmm7, 16*64*1024-16]; last smaller-sized +[savereg rsi, 8*64*1024-8] ; last smaller-sized +END_PROLOGUE +ENDPROC_FRAME + +PROC_FRAME sample2 +[allocstack 128] ; last smaller-sized +[setframe rbp, 240] ; largest value +[savexmm128 xmm7, 16*64*1024] ; first larger-sized +[savereg rsi, 8*64*1024] ; first larger-sized +END_PROLOGUE +ENDPROC_FRAME + +PROC_FRAME sample3 +[allocstack 136] ; first medium-sized +END_PROLOGUE +ENDPROC_FRAME + +PROC_FRAME sample4 +[allocstack 8*64*1024-8] ; last medium-sized +END_PROLOGUE +ENDPROC_FRAME + +PROC_FRAME sample5 +[allocstack 8*64*1024] ; first larger-sized +END_PROLOGUE +ENDPROC_FRAME diff --git a/modules/objfmts/win64/tests/sce4.hex b/modules/objfmts/win64/tests/sce4.hex new file mode 100644 index 00000000..9a57d50d --- /dev/null +++ b/modules/objfmts/win64/tests/sce4.hex @@ -0,0 +1,652 @@ +64 +86 +03 +00 +00 +00 +00 +00 +9e +01 +00 +00 +0d +00 +00 +00 +00 +00 +04 +00 +2e +74 +65 +78 +74 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +20 +00 +50 +60 +2e +78 +64 +61 +74 +61 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +40 +00 +00 +00 +8c +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +40 +00 +40 +40 +2e +70 +64 +61 +74 +61 +00 +00 +40 +00 +00 +00 +00 +00 +00 +00 +3c +00 +00 +00 +cc +00 +00 +00 +08 +01 +00 +00 +00 +00 +00 +00 +0f +00 +00 +00 +40 +00 +30 +40 +01 +00 +06 +05 +00 +64 +ff +ff +00 +78 +ff +ff +00 +53 +00 +02 +01 +00 +08 +f5 +00 +65 +00 +00 +08 +00 +00 +79 +00 +00 +10 +00 +00 +53 +00 +f2 +01 +00 +02 +00 +00 +01 +11 +00 +01 +00 +02 +00 +00 +01 +ff +ff +01 +00 +03 +00 +00 +11 +00 +00 +08 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +10 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +24 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +2c +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +34 +00 +00 +00 +00 +00 +00 +00 +04 +00 +00 +00 +03 +00 +04 +00 +00 +00 +04 +00 +00 +00 +03 +00 +08 +00 +00 +00 +05 +00 +00 +00 +03 +00 +0c +00 +00 +00 +09 +00 +00 +00 +03 +00 +10 +00 +00 +00 +09 +00 +00 +00 +03 +00 +14 +00 +00 +00 +05 +00 +00 +00 +03 +00 +18 +00 +00 +00 +0a +00 +00 +00 +03 +00 +1c +00 +00 +00 +0a +00 +00 +00 +03 +00 +20 +00 +00 +00 +05 +00 +00 +00 +03 +00 +24 +00 +00 +00 +0b +00 +00 +00 +03 +00 +28 +00 +00 +00 +0b +00 +00 +00 +03 +00 +2c +00 +00 +00 +05 +00 +00 +00 +03 +00 +30 +00 +00 +00 +0c +00 +00 +00 +03 +00 +34 +00 +00 +00 +0c +00 +00 +00 +03 +00 +38 +00 +00 +00 +05 +00 +00 +00 +03 +00 +2e +66 +69 +6c +65 +00 +00 +00 +00 +00 +00 +00 +fe +ff +00 +00 +67 +01 +2d +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +2e +74 +65 +78 +74 +00 +00 +00 +00 +00 +00 +00 +01 +00 +00 +00 +03 +01 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +73 +61 +6d +70 +6c +65 +00 +00 +00 +00 +00 +00 +01 +00 +00 +00 +03 +00 +2e +78 +64 +61 +74 +61 +00 +00 +00 +00 +00 +00 +02 +00 +00 +00 +03 +01 +40 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +2e +70 +64 +61 +74 +61 +00 +00 +00 +00 +00 +00 +03 +00 +00 +00 +03 +01 +3c +00 +00 +00 +0f +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +73 +61 +6d +70 +6c +65 +32 +00 +00 +00 +00 +00 +01 +00 +00 +00 +03 +00 +73 +61 +6d +70 +6c +65 +33 +00 +00 +00 +00 +00 +01 +00 +00 +00 +03 +00 +73 +61 +6d +70 +6c +65 +34 +00 +00 +00 +00 +00 +01 +00 +00 +00 +03 +00 +73 +61 +6d +70 +6c +65 +35 +00 +00 +00 +00 +00 +01 +00 +00 +00 +03 +00 +04 +00 +00 +00 diff --git a/modules/objfmts/win64/tests/sce4.masm b/modules/objfmts/win64/tests/sce4.masm new file mode 100644 index 00000000..1ffbf2f7 --- /dev/null +++ b/modules/objfmts/win64/tests/sce4.masm @@ -0,0 +1,36 @@ + +_TEXT SEGMENT + +sample PROC FRAME +.allocstack 8 ; smallest value +.setframe rbp, 0 ; smallest value +.savexmm128 xmm7, 16*64*1024-16 ; last smaller-sized +.savereg rsi, 8*64*1024-8 ; last smaller-sized +.endprolog +sample ENDP + +sample2 PROC FRAME +.allocstack 128 ; last smaller-sized +.setframe rbp, 240 ; largest value +.savexmm128 xmm7, 16*64*1024 ; first larger-sized +.savereg rsi, 8*64*1024 ; first larger-sized +.endprolog +sample2 ENDP + +sample3 PROC FRAME +.allocstack 136 ; first medium-sized +.endprolog +sample3 ENDP + +sample4 PROC FRAME +.allocstack 8*64*1024-8 ; last medium-sized +.endprolog +sample4 ENDP + +sample5 PROC FRAME +.allocstack 8*64*1024 ; first larger-sized +.endprolog +sample5 ENDP + +_TEXT ENDS +end diff --git a/modules/preprocs/nasm/standard.mac b/modules/preprocs/nasm/standard.mac index 56323a31..e88ddef9 100644 --- a/modules/preprocs/nasm/standard.mac +++ b/modules/preprocs/nasm/standard.mac @@ -130,42 +130,135 @@ __SECT__ %endif %ifidn __YASM_OBJFMT__,win64 -%imacro export 1+.nolist -[export %1] -%endmacro +%define __YASM_WIN64__ %endif %ifidn __YASM_OBJFMT__,x64 +%define __YASM_WIN64__ +%endif + +%ifdef __YASM_WIN64__ +%undef __YASM_WIN64__ + %imacro export 1+.nolist [export %1] %endmacro -%endif -%ifidn __YASM_OBJFMT__,elf -%imacro type 1+.nolist -[type %1] +; Raw exception handling operations +%imacro proc_frame 1+.nolist +%1: +[proc_frame %1] %endmacro -%imacro size 1+.nolist -[size %1] + +%if 0 +; Disable these as they're too closely named to the macroized ones. +; MASM needs a preceding . to use these, so it seems reasonable for +; us to similarly require the []. +%imacro pushreg 1.nolist +[pushreg %1] %endmacro -%imacro weak 1+.nolist -[weak %1] + +%imacro setframe 1-2.nolist +[setframe %1 %2] +%endmacro + +%imacro allocstack 1.nolist +[allocstack %1] +%endmacro + +%imacro savereg 2.nolist +[savereg %1 %2] +%endmacro + +%imacro savexmm128 2.nolist +[savexmm128 %1 %2] +%endmacro + +%imacro pushframe 0-1.nolist +[pushframe %1] +%endmacro + +%imacro endprolog 0.nolist +[endprolog] %endmacro %endif -%ifidn __YASM_OBJFMT__,elf32 -%imacro type 1+.nolist -[type %1] +%imacro endproc_frame 0.nolist +[endproc_frame] %endmacro -%imacro size 1+.nolist -[size %1] + +; Complex (macro) exception handling operations +; Mimics many macros provided by MASM's macamd64.inc +%imacro push_reg 1 +push %1 +[pushreg %1] %endmacro -%imacro weak 1+.nolist -[weak %1] + +%imacro rex_push_reg 1 +db 0x48 +push %1 +[pushreg %1] +%endmacro + +%imacro push_eflags 0 +pushfq +[allocstack 8] +%endmacro + +%imacro rex_push_eflags 0 +db 0x48 +pushfq +[allocstack 8] +%endmacro + +%imacro alloc_stack 1 +sub rsp, %1 +[allocstack %1] +%endmacro + +%imacro save_reg 2 +mov [rsp+%2], %1 +[savereg %1 %2] +%endmacro + +%imacro save_xmm128 2 +movdqa [rsp+%2], %1 +[savexmm128 %1 %2] +%endmacro + +%imacro push_frame 0-1.nolist +[pushframe %1] %endmacro + +%imacro set_frame 1-2 +%if %0==1 +mov %1, rsp +%else +lea %1, [rsp+%2] +%endif +[setframe %1 %2] +%endmacro + +%imacro end_prologue 0.nolist +[endprolog] +%endmacro + +%endif + +%ifidn __YASM_OBJFMT__,elf +%define __YASM_ELF__ +%endif + +%ifidn __YASM_OBJFMT__,elf32 +%define __YASM_ELF__ %endif %ifidn __YASM_OBJFMT__,elf64 +%define __YASM_ELF__ +%endif + +%ifdef __YASM_ELF__ +%undef __YASM_ELF__ %imacro type 1+.nolist [type %1] %endmacro diff --git a/po/POTFILES.in b/po/POTFILES.in index 797ecffa..293affc3 100644 --- a/po/POTFILES.in +++ b/po/POTFILES.in @@ -41,11 +41,13 @@ modules/dbgfmts/stabs/stabs-dbgfmt.c modules/listfmts/nasm/nasm-listfmt.c modules/objfmts/bin/bin-objfmt.c modules/objfmts/coff/coff-objfmt.c +modules/objfmts/coff/win64-except.c modules/objfmts/dbg/dbg-objfmt.c modules/objfmts/elf/elf-objfmt.c modules/objfmts/elf/elf-x86-amd64.c modules/objfmts/elf/elf-x86-x86.c modules/objfmts/elf/elf.c +modules/objfmts/macho/macho-objfmt.c modules/objfmts/rdf/rdf-objfmt.c modules/objfmts/xdf/xdf-objfmt.c modules/parsers/gas/gas-parse.c -- 2.40.0