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 \
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 \
<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
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
# $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
#define YASM_EXPR_INTERNAL
#include <libyasm.h>
+#include "coff-objfmt.h"
+
#define REGULAR_OUTBUF_SIZE 1024
} 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 */
/*@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 {
/* 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;
}
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 =
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);
}
csd->flags |= COFF_STYP_EXECUTE | COFF_STYP_READ;
yasm_section_set_default(retval, 1);
}
+ objfmt_coff->cursect = retval;
return retval;
}
} else if (flags_override)
yasm_warn_set(YASM_WARN_GENERAL,
N_("section flags ignored on section redeclaration"));
+ objfmt_coff->cursect = retval;
return retval;
}
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[] = {
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",
coff_objfmt_extern_declare,
coff_objfmt_global_declare,
coff_objfmt_common_declare,
- win32_objfmt_directive
+ win64_objfmt_directive
};
--- /dev/null
+/* $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
--- /dev/null
+/*
+ * 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;
+}
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
--- /dev/null
+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]
+
--- /dev/null
+-: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]
--- /dev/null
+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
--- /dev/null
+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
--- /dev/null
+PROC_FRAME sample4
+[pushreg rbp]
+
--- /dev/null
+-: end of file in procedure frame
+-:1: procedure started here
--- /dev/null
+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
+
--- /dev/null
+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
--- /dev/null
+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
+
--- /dev/null
+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
--- /dev/null
+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
--- /dev/null
+; 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
+
--- /dev/null
+-: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
--- /dev/null
+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
--- /dev/null
+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
--- /dev/null
+
+_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
%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
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