]> granicus.if.org Git - yasm/commitdiff
Add support for Win64 structured exception handling (aka .xdata and .pdata).
authorPeter Johnson <peter@tortall.net>
Mon, 12 Feb 2007 03:48:53 +0000 (03:48 -0000)
committerPeter Johnson <peter@tortall.net>
Mon, 12 Feb 2007 03:48:53 +0000 (03:48 -0000)
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 <procname>
... (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

27 files changed:
Mkfiles/Makefile.dj
Mkfiles/Makefile.flat
Mkfiles/vc/modules/modules.vcproj
Mkfiles/vc8/modules/modules.vcproj
modules/objfmts/coff/Makefile.inc
modules/objfmts/coff/coff-objfmt.c
modules/objfmts/coff/coff-objfmt.h [new file with mode: 0644]
modules/objfmts/coff/win64-except.c [new file with mode: 0644]
modules/objfmts/win64/tests/Makefile.inc
modules/objfmts/win64/tests/sce1-err.asm [new file with mode: 0644]
modules/objfmts/win64/tests/sce1-err.errwarn [new file with mode: 0644]
modules/objfmts/win64/tests/sce1.asm [new file with mode: 0644]
modules/objfmts/win64/tests/sce1.hex [new file with mode: 0644]
modules/objfmts/win64/tests/sce2-err.asm [new file with mode: 0644]
modules/objfmts/win64/tests/sce2-err.errwarn [new file with mode: 0644]
modules/objfmts/win64/tests/sce2.asm [new file with mode: 0644]
modules/objfmts/win64/tests/sce2.hex [new file with mode: 0644]
modules/objfmts/win64/tests/sce3.asm [new file with mode: 0644]
modules/objfmts/win64/tests/sce3.hex [new file with mode: 0644]
modules/objfmts/win64/tests/sce3.masm [new file with mode: 0644]
modules/objfmts/win64/tests/sce4-err.asm [new file with mode: 0644]
modules/objfmts/win64/tests/sce4-err.errwarn [new file with mode: 0644]
modules/objfmts/win64/tests/sce4.asm [new file with mode: 0644]
modules/objfmts/win64/tests/sce4.hex [new file with mode: 0644]
modules/objfmts/win64/tests/sce4.masm [new file with mode: 0644]
modules/preprocs/nasm/standard.mac
po/POTFILES.in

index 7a4cad206dd03bc54ef50ad29211b8eb44eb1737..dab4a5ffdd32bf4caa6fff049b29df4a1d4b8507 100644 (file)
@@ -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 \
index 1302cad4d3b7b95193caf8fe14230783580e6ed9..9160a245aff950061453850e633e0bc4ac5d03d0 100644 (file)
@@ -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 \
index 28081b66778004a338966beda4731df47d0cfb87..fee601846ef219793a63b6af8460c11beb5b5611 100644 (file)
                                <File\r
                                        RelativePath="..\..\..\modules\objfmts\coff\coff-objfmt.c">\r
                                </File>\r
+                               <File\r
+                                       RelativePath="..\..\..\modules\objfmts\coff\coff-objfmt.h">\r
+                               </File>\r
+                               <File\r
+                                       RelativePath="..\..\..\modules\objfmts\coff\win64-except.c">\r
+                               </File>\r
                                <File\r
                                        RelativePath="..\..\..\modules\objfmts\dbg\dbg-objfmt.c">\r
                                </File>\r
index 160b217ce4190860b2ea7637fbd55e819210f2be..03821e78e9f274c0792835017704c58c032fb8dc 100644 (file)
                                        RelativePath="..\..\..\modules\objfmts\coff\coff-objfmt.c"\r
                                        >\r
                                </File>\r
+                               <File\r
+                                       RelativePath="..\..\..\modules\objfmts\coff\coff-objfmt.h"\r
+                                       >\r
+                               </File>\r
+                               <File\r
+                                       RelativePath="..\..\..\modules\objfmts\coff\win64-except.c"\r
+                                       >\r
+                               </File>\r
                                <File\r
                                        RelativePath="..\..\..\modules\objfmts\dbg\dbg-objfmt.c"\r
                                        >\r
index 975ec388df938cde6482834a2740adc97811fa89..526f7713ca30dfacbb604c787bfe1989948b82a4 100644 (file)
@@ -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
 
index 3d518cec885e53040c293739f1b44028f0e8dadd..6c2ae9baa1759623a7f6f45dd6312b869673d74b 100644 (file)
@@ -33,6 +33,8 @@
 #define YASM_EXPR_INTERNAL
 #include <libyasm.h>
 
+#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<NELEMS(dirs); i++) {
+       if (yasm__strcasecmp(name, dirs[i].name) == 0) {
+           if (dirs[i].required_arg && !valparams) {
+               yasm_error_set(YASM_ERROR_SYNTAX,
+                              N_("[%s] requires an argument"), dirs[i].name);
+               return 0;
+           }
+           dirs[i].func(objfmt_coff, valparams, line);
+           return 0;
+       }
+    }
+    return 1;
+}
+
 
 /* Define valid debug formats to use with this object format */
 static const char *coff_objfmt_dbgfmt_keywords[] = {
@@ -1899,7 +2321,7 @@ yasm_objfmt_module yasm_win64_LTX_objfmt = {
     coff_objfmt_extern_declare,
     coff_objfmt_global_declare,
     coff_objfmt_common_declare,
-    win32_objfmt_directive
+    win64_objfmt_directive
 };
 yasm_objfmt_module yasm_x64_LTX_objfmt = {
     "Win64",
@@ -1916,5 +2338,5 @@ yasm_objfmt_module yasm_x64_LTX_objfmt = {
     coff_objfmt_extern_declare,
     coff_objfmt_global_declare,
     coff_objfmt_common_declare,
-    win32_objfmt_directive
+    win64_objfmt_directive
 };
diff --git a/modules/objfmts/coff/coff-objfmt.h b/modules/objfmts/coff/coff-objfmt.h
new file mode 100644 (file)
index 0000000..f30c119
--- /dev/null
@@ -0,0 +1,77 @@
+/* $Id$
+ * COFF (DJGPP) object format
+ *
+ *  Copyright (C) 2007  Peter Johnson
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND OTHER CONTRIBUTORS ``AS IS''
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR OTHER CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+#ifndef COFF_OBJFMT_H
+#define COFF_OBJFMT_H
+
+typedef struct coff_unwind_code {
+    SLIST_ENTRY(coff_unwind_code) link;
+
+    /*@dependent@*/ yasm_symrec *proc;     /* Start of procedure */
+    /*@dependent@*/ yasm_symrec *loc;      /* Location of operation */
+    /* Unwind operation code */
+    enum {
+       UWOP_PUSH_NONVOL = 0,
+       UWOP_ALLOC_LARGE = 1,
+       UWOP_ALLOC_SMALL = 2,
+       UWOP_SET_FPREG = 3,
+       UWOP_SAVE_NONVOL = 4,
+       UWOP_SAVE_NONVOL_FAR = 5,
+       UWOP_SAVE_XMM128 = 8,
+       UWOP_SAVE_XMM128_FAR = 9,
+       UWOP_PUSH_MACHFRAME = 10
+    } opcode;
+    unsigned int info;         /* Operation info */
+    yasm_value off;            /* Offset expression (used for some codes) */
+} coff_unwind_code;
+
+typedef struct coff_unwind_info {
+    /*@dependent@*/ yasm_symrec *proc;     /* Start of procedure */
+    /*@dependent@*/ yasm_symrec *prolog;    /* End of prologue */
+
+    /*@null@*/ /*@dependent@*/ yasm_symrec *ehandler;  /* Error handler */
+
+    unsigned long framereg;    /* Frame register */
+    yasm_value frameoff;       /* Frame offset */
+
+    /* Linked list of codes, in decreasing location offset order.
+     * Inserting at the head of this list during assembly naturally results
+     * in this sorting.
+     */
+    SLIST_HEAD(coff_unwind_code_head, coff_unwind_code) codes;
+
+    /* These aren't used until inside of generate. */
+    yasm_value prolog_size;
+    yasm_value codes_count;
+} coff_unwind_info;
+
+coff_unwind_info *yasm_win64__uwinfo_create(void);
+void yasm_win64__uwinfo_destroy(coff_unwind_info *info);
+void yasm_win64__unwind_generate(yasm_section *xdata,
+                                /*@only@*/ coff_unwind_info *info,
+                                unsigned long line);
+
+#endif
diff --git a/modules/objfmts/coff/win64-except.c b/modules/objfmts/coff/win64-except.c
new file mode 100644 (file)
index 0000000..267090f
--- /dev/null
@@ -0,0 +1,553 @@
+/*
+ * Win64 structured exception handling support
+ *
+ *  Copyright (C) 2007  Peter Johnson
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND OTHER CONTRIBUTORS ``AS IS''
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR OTHER CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+#include <util.h>
+/*@unused@*/ RCSID("$Id$");
+
+#define YASM_LIB_INTERNAL
+#define YASM_BC_INTERNAL
+#define YASM_EXPR_INTERNAL
+#include <libyasm.h>
+
+#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;
+}
index b603e04c5eddabaf45c574ef41951dfc7b747e1f..4bc0907c06febd2caca5d5b52de6a5d64bbb285f 100644 (file)
@@ -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 (file)
index 0000000..a356b5e
--- /dev/null
@@ -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 (file)
index 0000000..f5b6793
--- /dev/null
@@ -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 (file)
index 0000000..a021e82
--- /dev/null
@@ -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 (file)
index 0000000..d6b1427
--- /dev/null
@@ -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 (file)
index 0000000..b5ce957
--- /dev/null
@@ -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 (file)
index 0000000..d7f0d29
--- /dev/null
@@ -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 (file)
index 0000000..d76f946
--- /dev/null
@@ -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 (file)
index 0000000..1caa10c
--- /dev/null
@@ -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 (file)
index 0000000..788fe6b
--- /dev/null
@@ -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 (file)
index 0000000..cadf8b9
--- /dev/null
@@ -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 (file)
index 0000000..7bac248
--- /dev/null
@@ -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 (file)
index 0000000..402f7e9
--- /dev/null
@@ -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 (file)
index 0000000..92d9cb0
--- /dev/null
@@ -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 (file)
index 0000000..4072b24
--- /dev/null
@@ -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 (file)
index 0000000..9a57d50
--- /dev/null
@@ -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 (file)
index 0000000..1ffbf2f
--- /dev/null
@@ -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
index 56323a31f40d78bfe432007cab2920bfabbb3019..e88ddef977b4cc32c4603052c11539d610a7e7fc 100644 (file)
@@ -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
index 797ecffa7f4b402d49d31079f09dd54f5c2f3243..293affc39977c9466bb3818e51c24e95c23343b1 100644 (file)
@@ -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