aboutsummaryrefslogtreecommitdiffstats
path: root/contrib/tools/yasm/modules/objfmts/coff
diff options
context:
space:
mode:
authorsomov <somov@yandex-team.ru>2022-02-10 16:45:47 +0300
committerDaniil Cherednik <dcherednik@yandex-team.ru>2022-02-10 16:45:47 +0300
commita5950576e397b1909261050b8c7da16db58f10b1 (patch)
tree7ba7677f6a4c3e19e2cefab34d16df2c8963b4d4 /contrib/tools/yasm/modules/objfmts/coff
parent81eddc8c0b55990194e112b02d127b87d54164a9 (diff)
downloadydb-a5950576e397b1909261050b8c7da16db58f10b1.tar.gz
Restoring authorship annotation for <somov@yandex-team.ru>. Commit 1 of 2.
Diffstat (limited to 'contrib/tools/yasm/modules/objfmts/coff')
-rw-r--r--contrib/tools/yasm/modules/objfmts/coff/coff-objfmt.c5032
-rw-r--r--contrib/tools/yasm/modules/objfmts/coff/coff-objfmt.h154
-rw-r--r--contrib/tools/yasm/modules/objfmts/coff/win64-except.c1118
3 files changed, 3152 insertions, 3152 deletions
diff --git a/contrib/tools/yasm/modules/objfmts/coff/coff-objfmt.c b/contrib/tools/yasm/modules/objfmts/coff/coff-objfmt.c
index 388b09af32..80d9567e05 100644
--- a/contrib/tools/yasm/modules/objfmts/coff/coff-objfmt.c
+++ b/contrib/tools/yasm/modules/objfmts/coff/coff-objfmt.c
@@ -1,2522 +1,2522 @@
-/*
- * COFF (DJGPP) object format
- *
- * Copyright (C) 2002-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>
-#include <time.h>
-
-#include <libyasm.h>
-
-#include "coff-objfmt.h"
-
-
-#define REGULAR_OUTBUF_SIZE 1024
-
-/* Defining this to 0 sets all section VMA's to 0 rather than as the same as
- * the LMA. According to the DJGPP COFF Spec, this should be set to 1
- * (VMA=LMA), and indeed DJGPP's GCC output shows VMA=LMA. However, NASM
- * outputs VMA=0 (as if this was 0), and GNU objdump output looks a lot nicer
- * with VMA=0. Who's right? This is #defined as changing this setting affects
- * several places in the code.
- */
-#define COFF_SET_VMA (!objfmt_coff->win32)
-
-#define COFF_MACHINE_I386 0x014C
-#define COFF_MACHINE_AMD64 0x8664
-
-#define COFF_F_LNNO 0x0004 /* line number info NOT present */
-#define COFF_F_LSYMS 0x0008 /* local symbols NOT present */
-#define COFF_F_AR32WR 0x0100 /* 32-bit little endian file */
-
-typedef struct coff_reloc {
- yasm_reloc reloc;
- enum {
- COFF_RELOC_ABSOLUTE = 0, /* absolute, no reloc needed */
-
- /* I386 relocations */
- COFF_RELOC_I386_ADDR16 = 0x1, /* 16-bit absolute reference */
- COFF_RELOC_I386_REL16 = 0x2, /* 16-bit PC-relative reference */
- COFF_RELOC_I386_ADDR32 = 0x6, /* 32-bit absolute reference */
- COFF_RELOC_I386_ADDR32NB = 0x7, /* 32-bit absolute ref w/o base */
- COFF_RELOC_I386_SEG12 = 0x9, /* 16-bit absolute segment ref */
- COFF_RELOC_I386_SECTION = 0xA, /* section index */
- COFF_RELOC_I386_SECREL = 0xB, /* offset from start of segment */
- COFF_RELOC_I386_TOKEN = 0xC, /* CLR metadata token */
- COFF_RELOC_I386_SECREL7 = 0xD, /* 7-bit offset from base of sect */
- COFF_RELOC_I386_REL32 = 0x14, /* 32-bit PC-relative reference */
-
- /* AMD64 relocations */
- COFF_RELOC_AMD64_ADDR64 = 0x1, /* 64-bit address (VA) */
- COFF_RELOC_AMD64_ADDR32 = 0x2, /* 32-bit address (VA) */
- COFF_RELOC_AMD64_ADDR32NB = 0x3, /* 32-bit address w/o base (RVA) */
- COFF_RELOC_AMD64_REL32 = 0x4, /* 32-bit relative (0 byte dist) */
- COFF_RELOC_AMD64_REL32_1 = 0x5, /* 32-bit relative (1 byte dist) */
- COFF_RELOC_AMD64_REL32_2 = 0x6, /* 32-bit relative (2 byte dist) */
- COFF_RELOC_AMD64_REL32_3 = 0x7, /* 32-bit relative (3 byte dist) */
- COFF_RELOC_AMD64_REL32_4 = 0x8, /* 32-bit relative (4 byte dist) */
- COFF_RELOC_AMD64_REL32_5 = 0x9, /* 32-bit relative (5 byte dist) */
- COFF_RELOC_AMD64_SECTION = 0xA, /* section index */
- COFF_RELOC_AMD64_SECREL = 0xB, /* 32-bit offset from base of sect */
- COFF_RELOC_AMD64_SECREL7 = 0xC, /* 7-bit offset from base of sect */
- COFF_RELOC_AMD64_TOKEN = 0xD /* CLR metadata token */
- } type; /* type of relocation */
-} coff_reloc;
-
-#define COFF_STYP_TEXT 0x00000020UL
-#define COFF_STYP_DATA 0x00000040UL
-#define COFF_STYP_BSS 0x00000080UL
-#define COFF_STYP_INFO 0x00000200UL
-#define COFF_STYP_STD_MASK 0x000003FFUL
-#define COFF_STYP_ALIGN_MASK 0x00F00000UL
-#define COFF_STYP_ALIGN_SHIFT 20
-#define COFF_STYP_NRELOC_OVFL 0x01000000UL
-#define COFF_STYP_DISCARD 0x02000000UL
-#define COFF_STYP_NOCACHE 0x04000000UL
-#define COFF_STYP_NOPAGE 0x08000000UL
-#define COFF_STYP_SHARED 0x10000000UL
-#define COFF_STYP_EXECUTE 0x20000000UL
-#define COFF_STYP_READ 0x40000000UL
-#define COFF_STYP_WRITE 0x80000000UL
-#define COFF_STYP_WIN32_MASK 0xFF000000UL
-
-#define COFF_FLAG_NOBASE (1UL<<0) /* Use no-base (NB) relocs */
-
-typedef struct coff_section_data {
- /*@dependent@*/ yasm_symrec *sym; /* symbol created for this section */
- unsigned int scnum; /* section number (1=first section) */
- unsigned long flags; /* section flags (see COFF_STYP_* above) */
- unsigned long addr; /* starting memory address (first section -> 0) */
- unsigned long scnptr; /* file ptr to raw data */
- unsigned long size; /* size of raw data (section data) in bytes */
- unsigned long relptr; /* file ptr to relocation */
- unsigned long nreloc; /* number of relocation entries >64k -> error */
- unsigned long flags2; /* internal flags (see COFF_FLAG_* above) */
- unsigned long strtab_name; /* strtab offset of name if name > 8 chars */
- int isdebug; /* is a debug section? */
-} coff_section_data;
-
-typedef enum coff_symrec_sclass {
- COFF_SCL_EFCN = 0xff, /* physical end of function */
- COFF_SCL_NULL = 0,
- COFF_SCL_AUTO = 1, /* automatic variable */
- COFF_SCL_EXT = 2, /* external symbol */
- COFF_SCL_STAT = 3, /* static */
- COFF_SCL_REG = 4, /* register variable */
- COFF_SCL_EXTDEF = 5, /* external definition */
- COFF_SCL_LABEL = 6, /* label */
- COFF_SCL_ULABEL = 7, /* undefined label */
- COFF_SCL_MOS = 8, /* member of structure */
- COFF_SCL_ARG = 9, /* function argument */
- COFF_SCL_STRTAG = 10, /* structure tag */
- COFF_SCL_MOU = 11, /* member of union */
- COFF_SCL_UNTAG = 12, /* union tag */
- COFF_SCL_TPDEF = 13, /* type definition */
- COFF_SCL_USTATIC = 14, /* undefined static */
- COFF_SCL_ENTAG = 15, /* enumeration tag */
- COFF_SCL_MOE = 16, /* member of enumeration */
- COFF_SCL_REGPARM = 17, /* register parameter */
- COFF_SCL_FIELD = 18, /* bit field */
- COFF_SCL_AUTOARG = 19, /* auto argument */
- COFF_SCL_LASTENT = 20, /* dummy entry (end of block) */
- COFF_SCL_BLOCK = 100, /* ".bb" or ".eb" */
- COFF_SCL_FCN = 101, /* ".bf" or ".ef" */
- COFF_SCL_EOS = 102, /* end of structure */
- COFF_SCL_FILE = 103, /* file name */
- COFF_SCL_LINE = 104, /* line # reformatted as symbol table entry */
- COFF_SCL_ALIAS = 105, /* duplicate tag */
- COFF_SCL_HIDDEN = 106 /* ext symbol in dmert public lib */
-} coff_symrec_sclass;
-
-typedef union coff_symtab_auxent {
- /* no data needed for section symbol auxent, all info avail from sym */
- /*@owned@*/ char *fname; /* filename aux entry */
-} coff_symtab_auxent;
-
-typedef enum coff_symtab_auxtype {
- COFF_SYMTAB_AUX_NONE = 0,
- COFF_SYMTAB_AUX_SECT,
- COFF_SYMTAB_AUX_FILE
-} coff_symtab_auxtype;
-
-typedef struct coff_symrec_data {
- int forcevis; /* force visibility in symbol table */
- unsigned long index; /* assigned COFF symbol table index */
- unsigned int type; /* type */
- coff_symrec_sclass sclass; /* storage class */
-
- int numaux; /* number of auxiliary entries */
- coff_symtab_auxtype auxtype; /* type of aux entries */
- coff_symtab_auxent aux[1]; /* actually may be any size (including 0) */
-} coff_symrec_data;
-
-typedef struct yasm_objfmt_coff {
- yasm_objfmt_base objfmt; /* base structure */
-
- unsigned int parse_scnum; /* sect numbering in parser */
- int win32; /* nonzero for win32/64 output */
- int win64; /* nonzero for win64 output */
-
- unsigned int machine; /* COFF machine to use */
-
- coff_symrec_data *filesym_data; /* Data for .file symbol */
-
- /* data for .def/.endef and related directives */
- coff_symrec_data *def_sym; /* symbol specified by .def */
-
- /* 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_symrec *ssym_imagebase; /* ..imagebase symbol for win64 */
-} yasm_objfmt_coff;
-
-typedef struct coff_objfmt_output_info {
- yasm_object *object;
- yasm_objfmt_coff *objfmt_coff;
- yasm_errwarns *errwarns;
- /*@dependent@*/ FILE *f;
- /*@only@*/ unsigned char *buf;
- yasm_section *sect;
- /*@dependent@*/ coff_section_data *csd;
- unsigned long addr; /* start of next section */
-
- unsigned long indx; /* current symbol index */
- int all_syms; /* outputting all symbols? */
- unsigned long strtab_offset; /* current string table offset */
-} coff_objfmt_output_info;
-
-static void coff_section_data_destroy(/*@only@*/ void *d);
-static void coff_section_data_print(void *data, FILE *f, int indent_level);
-
-static const yasm_assoc_data_callback coff_section_data_cb = {
- coff_section_data_destroy,
- coff_section_data_print
-};
-
-static void coff_symrec_data_destroy(/*@only@*/ void *d);
-static void coff_symrec_data_print(void *data, FILE *f, int indent_level);
-
-static const yasm_assoc_data_callback coff_symrec_data_cb = {
- coff_symrec_data_destroy,
- coff_symrec_data_print
-};
-
-/* Bytecode callback function prototypes */
-static void win32_sxdata_bc_destroy(void *contents);
-static void win32_sxdata_bc_print(const void *contents, FILE *f,
- int indent_level);
-static int win32_sxdata_bc_calc_len
- (yasm_bytecode *bc, yasm_bc_add_span_func add_span, void *add_span_data);
-static int win32_sxdata_bc_tobytes
- (yasm_bytecode *bc, unsigned char **bufp, unsigned char *bufstart, void *d,
- yasm_output_value_func output_value,
- /*@null@*/ yasm_output_reloc_func output_reloc);
-
-/* Bytecode callback structures */
-static const yasm_bytecode_callback win32_sxdata_bc_callback = {
- win32_sxdata_bc_destroy,
- win32_sxdata_bc_print,
- yasm_bc_finalize_common,
- NULL,
- win32_sxdata_bc_calc_len,
- yasm_bc_expand_common,
- win32_sxdata_bc_tobytes,
- 0
-};
-
-yasm_objfmt_module yasm_coff_LTX_objfmt;
-yasm_objfmt_module yasm_win32_LTX_objfmt;
-yasm_objfmt_module yasm_win64_LTX_objfmt;
-
-
-static /*@dependent@*/ coff_symrec_data *
-coff_objfmt_sym_set_data(yasm_symrec *sym, coff_symrec_sclass sclass,
- int numaux, coff_symtab_auxtype auxtype)
-{
- coff_symrec_data *sym_data;
-
- sym_data = yasm_xmalloc(sizeof(coff_symrec_data) +
- (numaux-1)*sizeof(coff_symtab_auxent));
- sym_data->forcevis = 0;
- sym_data->index = 0;
- sym_data->type = 0;
- sym_data->sclass = sclass;
- sym_data->numaux = numaux;
- sym_data->auxtype = auxtype;
-
- yasm_symrec_add_data(sym, &coff_symrec_data_cb, sym_data);
-
- return sym_data;
-}
-
-static yasm_objfmt_coff *
-coff_common_create(yasm_object *object)
-{
- yasm_objfmt_coff *objfmt_coff = yasm_xmalloc(sizeof(yasm_objfmt_coff));
- yasm_symrec *filesym;
-
- /* Only support x86 arch */
- if (yasm__strcasecmp(yasm_arch_keyword(object->arch), "x86") != 0) {
- yasm_xfree(objfmt_coff);
- return NULL;
- }
-
- objfmt_coff->parse_scnum = 1; /* section numbering starts at 1 */
-
- /* FIXME: misuse of NULL bytecode here; it works, but only barely. */
- filesym = yasm_symtab_define_special(object->symtab, ".file",
- YASM_SYM_GLOBAL);
- objfmt_coff->filesym_data =
- coff_objfmt_sym_set_data(filesym, COFF_SCL_FILE, 1,
- COFF_SYMTAB_AUX_FILE);
- /* Filename is set in coff_objfmt_output */
- objfmt_coff->filesym_data->aux[0].fname = NULL;
-
- objfmt_coff->proc_frame = 0;
- objfmt_coff->done_prolog = 0;
- objfmt_coff->unwind = NULL;
- objfmt_coff->ssym_imagebase = NULL;
-
- return objfmt_coff;
-}
-
-static yasm_objfmt *
-coff_objfmt_create(yasm_object *object)
-{
- yasm_objfmt_coff *objfmt_coff = coff_common_create(object);
-
- if (objfmt_coff) {
- /* Support x86 and amd64 machines of x86 arch */
- if (yasm__strcasecmp(yasm_arch_get_machine(object->arch), "x86") == 0)
- objfmt_coff->machine = COFF_MACHINE_I386;
- else if (yasm__strcasecmp(yasm_arch_get_machine(object->arch),
- "amd64") == 0)
- objfmt_coff->machine = COFF_MACHINE_AMD64;
- else {
- yasm_xfree(objfmt_coff);
- return NULL;
- }
-
- objfmt_coff->objfmt.module = &yasm_coff_LTX_objfmt;
- objfmt_coff->win32 = 0;
- objfmt_coff->win64 = 0;
- }
- return (yasm_objfmt *)objfmt_coff;
-}
-
-static yasm_objfmt *
-win32_objfmt_create(yasm_object *object)
-{
- yasm_objfmt_coff *objfmt_coff = coff_common_create(object);
-
- if (objfmt_coff) {
- /* Support x86 and amd64 machines of x86 arch.
- * (amd64 machine supported for backwards compatibility)
- */
- if (yasm__strcasecmp(yasm_arch_get_machine(object->arch),
- "x86") == 0) {
- objfmt_coff->machine = COFF_MACHINE_I386;
- objfmt_coff->objfmt.module = &yasm_win32_LTX_objfmt;
- objfmt_coff->win64 = 0;
- } else if (yasm__strcasecmp(yasm_arch_get_machine(object->arch),
- "amd64") == 0) {
- objfmt_coff->machine = COFF_MACHINE_AMD64;
- objfmt_coff->objfmt.module = &yasm_win64_LTX_objfmt;
- objfmt_coff->win64 = 1;
- } else {
- yasm_xfree(objfmt_coff);
- return NULL;
- }
-
- objfmt_coff->win32 = 1;
- /* Define a @feat.00 symbol for win32 safeseh handling */
- if (!objfmt_coff->win64) {
- yasm_symrec *feat00;
- coff_symrec_data *sym_data;
- feat00 = yasm_symtab_define_equ(object->symtab, "@feat.00",
- yasm_expr_create_ident(yasm_expr_int(
- yasm_intnum_create_uint(1)), 0), 0);
- sym_data = coff_objfmt_sym_set_data(feat00, COFF_SCL_STAT, 0,
- COFF_SYMTAB_AUX_NONE);
- sym_data->forcevis = 1;
- }
- }
- return (yasm_objfmt *)objfmt_coff;
-}
-
-static yasm_objfmt *
-win64_objfmt_create(yasm_object *object)
-{
- yasm_objfmt_coff *objfmt_coff = coff_common_create(object);
-
- if (objfmt_coff) {
- /* Support amd64 machine of x86 arch */
- if (yasm__strcasecmp(yasm_arch_get_machine(object->arch),
- "amd64") == 0) {
- objfmt_coff->machine = COFF_MACHINE_AMD64;
- } else {
- yasm_xfree(objfmt_coff);
- return NULL;
- }
-
- objfmt_coff->objfmt.module = &yasm_win64_LTX_objfmt;
- objfmt_coff->win32 = 1;
- objfmt_coff->win64 = 1;
- objfmt_coff->ssym_imagebase =
- yasm_symtab_define_label(object->symtab, "..imagebase", NULL, 0, 0);
- }
- return (yasm_objfmt *)objfmt_coff;
-}
-
-static void
-coff_objfmt_init_new_section(yasm_section *sect, unsigned long line)
-{
- yasm_object *object = yasm_section_get_object(sect);
- const char *sectname = yasm_section_get_name(sect);
- yasm_objfmt_coff *objfmt_coff = (yasm_objfmt_coff *)object->objfmt;
- coff_section_data *data;
- yasm_symrec *sym;
-
- data = yasm_xmalloc(sizeof(coff_section_data));
- data->scnum = objfmt_coff->parse_scnum++;
- data->flags = 0;
- data->addr = 0;
- data->scnptr = 0;
- data->size = 0;
- data->relptr = 0;
- data->nreloc = 0;
- data->flags2 = 0;
- data->strtab_name = 0;
- data->isdebug = 0;
-
- if (yasm__strncasecmp(sectname, ".debug", 6)==0) {
- data->flags = COFF_STYP_DATA;
- if (objfmt_coff->win32)
- data->flags |= COFF_STYP_DISCARD|COFF_STYP_READ;
- data->isdebug = 1;
- } else
- data->flags = COFF_STYP_TEXT;
-
- yasm_section_add_data(sect, &coff_section_data_cb, data);
-
- sym = yasm_symtab_define_label(object->symtab, sectname,
- yasm_section_bcs_first(sect), 1, line);
- yasm_symrec_declare(sym, YASM_SYM_GLOBAL, line);
- coff_objfmt_sym_set_data(sym, COFF_SCL_STAT, 1, COFF_SYMTAB_AUX_SECT);
- data->sym = sym;
-}
-
-static int
-coff_objfmt_set_section_addr(yasm_section *sect, /*@null@*/ void *d)
-{
- /*@null@*/ coff_objfmt_output_info *info = (coff_objfmt_output_info *)d;
- /*@dependent@*/ /*@null@*/ coff_section_data *csd;
-
- assert(info != NULL);
- csd = yasm_section_get_data(sect, &coff_section_data_cb);
- assert(csd != NULL);
-
- csd->addr = info->addr;
- info->addr += yasm_bc_next_offset(yasm_section_bcs_last(sect));
-
- return 0;
-}
-
-static int
-coff_objfmt_output_value(yasm_value *value, unsigned char *buf,
- unsigned int destsize, unsigned long offset,
- yasm_bytecode *bc, int warn, /*@null@*/ void *d)
-{
- /*@null@*/ coff_objfmt_output_info *info = (coff_objfmt_output_info *)d;
- yasm_objfmt_coff *objfmt_coff;
- /*@only@*/ /*@null@*/ yasm_intnum *dist = NULL;
- /*@dependent@*/ /*@null@*/ yasm_intnum *intn;
- unsigned long intn_val, intn_minus;
- int retval;
- unsigned int valsize = value->size;
-
- assert(info != NULL);
- objfmt_coff = info->objfmt_coff;
-
- if (value->abs)
- value->abs = yasm_expr_simplify(value->abs, 1);
-
- /* Try to output constant and PC-relative section-local first.
- * Note this does NOT output any value with a SEG, WRT, external,
- * cross-section, or non-PC-relative reference (those are handled below).
- */
- switch (yasm_value_output_basic(value, buf, destsize, bc, warn,
- info->object->arch)) {
- case -1:
- return 1;
- case 0:
- break;
- default:
- return 0;
- }
-
- /* Handle other expressions, with relocation if necessary */
- if (value->rshift > 0
- || (value->seg_of && (value->wrt || value->curpos_rel))
- || (value->section_rel && (value->wrt || value->curpos_rel))) {
- yasm_error_set(YASM_ERROR_TOO_COMPLEX,
- N_("coff: relocation too complex"));
- return 1;
- }
-
- intn_val = 0;
- intn_minus = 0;
- if (value->rel) {
- yasm_sym_vis vis = yasm_symrec_get_visibility(value->rel);
- /*@dependent@*/ /*@null@*/ yasm_symrec *sym = value->rel;
- unsigned long addr;
- coff_reloc *reloc;
- int nobase = info->csd->flags2 & COFF_FLAG_NOBASE;
-
- /* Sometimes we want the relocation to be generated against one
- * symbol but the value generated correspond to a different symbol.
- * This is done through (sym being referenced) WRT (sym used for
- * reloc). Note both syms need to be in the same section!
- */
- if (value->wrt && value->wrt == objfmt_coff->ssym_imagebase)
- nobase = 1;
- else if (value->wrt) {
- /*@dependent@*/ /*@null@*/ yasm_bytecode *rel_precbc, *wrt_precbc;
-
- if (!yasm_symrec_get_label(sym, &rel_precbc)
- || !yasm_symrec_get_label(value->wrt, &wrt_precbc)) {
- yasm_error_set(YASM_ERROR_TOO_COMPLEX,
- N_("coff: wrt expression too complex"));
- return 1;
- }
- dist = yasm_calc_bc_dist(wrt_precbc, rel_precbc);
- if (!dist) {
- yasm_error_set(YASM_ERROR_TOO_COMPLEX,
- N_("coff: cannot wrt across sections"));
- return 1;
- }
- sym = value->wrt;
- }
-
- if (vis & YASM_SYM_COMMON) {
- /* In standard COFF, COMMON symbols have their length added in */
- if (!objfmt_coff->win32) {
- /*@dependent@*/ /*@null@*/ yasm_expr **csize_expr;
- /*@dependent@*/ /*@null@*/ yasm_intnum *common_size;
-
- csize_expr = yasm_symrec_get_common_size(sym);
- assert(csize_expr != NULL);
- common_size = yasm_expr_get_intnum(csize_expr, 1);
- if (!common_size) {
- yasm_error_set(YASM_ERROR_TOO_COMPLEX,
- N_("coff: common size too complex"));
- return 1;
- }
-
- if (yasm_intnum_sign(common_size) < 0) {
- yasm_error_set(YASM_ERROR_VALUE,
- N_("coff: common size is negative"));
- return 1;
- }
-
- intn_val += yasm_intnum_get_uint(common_size);
- }
- } else if (!(vis & YASM_SYM_EXTERN) && !objfmt_coff->win64) {
- /*@dependent@*/ /*@null@*/ yasm_bytecode *sym_precbc;
-
- /* Local symbols need relocation to their section's start */
- if (yasm_symrec_get_label(sym, &sym_precbc)) {
- yasm_section *sym_sect = yasm_bc_get_section(sym_precbc);
- /*@null@*/ coff_section_data *sym_csd;
- sym_csd = yasm_section_get_data(sym_sect,
- &coff_section_data_cb);
- assert(sym_csd != NULL);
- sym = sym_csd->sym;
- intn_val = yasm_bc_next_offset(sym_precbc);
- if (COFF_SET_VMA)
- intn_val += sym_csd->addr;
- }
- }
-
- if (value->curpos_rel) {
- /* For standard COFF, need to adjust to start of section, e.g.
- * subtract out the bytecode offset.
- * For Win32 COFF, need to adjust based on value size and position.
- * For Win64 COFF that's IP-relative, adjust to next bytecode;
- * the difference between the offset+destsize and BC length is
- * taken care of by special relocation types.
- */
- if (objfmt_coff->win64 && value->ip_rel)
- intn_val += bc->len*bc->mult_int;
- else if (objfmt_coff->win32)
- intn_val += offset+destsize;
- else
- intn_minus = bc->offset;
- }
-
- if (value->seg_of) {
- /* Segment generation; zero value. */
- intn_val = 0;
- intn_minus = 0;
- }
-
- /* Generate reloc */
- reloc = yasm_xmalloc(sizeof(coff_reloc));
- addr = bc->offset + offset;
- if (COFF_SET_VMA)
- addr += info->addr;
- reloc->reloc.addr = yasm_intnum_create_uint(addr);
- reloc->reloc.sym = sym;
-
- if (value->curpos_rel) {
- if (objfmt_coff->machine == COFF_MACHINE_I386) {
- if (valsize == 32)
- reloc->type = COFF_RELOC_I386_REL32;
- else {
- yasm_error_set(YASM_ERROR_TYPE,
- N_("coff: invalid relocation size"));
- return 1;
- }
- } else if (objfmt_coff->machine == COFF_MACHINE_AMD64) {
- if (valsize != 32) {
- yasm_error_set(YASM_ERROR_TYPE,
- N_("coff: invalid relocation size"));
- return 1;
- }
- if (!value->ip_rel)
- reloc->type = COFF_RELOC_AMD64_REL32;
- else switch (bc->len*bc->mult_int - (offset+destsize)) {
- case 0:
- reloc->type = COFF_RELOC_AMD64_REL32;
- break;
- case 1:
- reloc->type = COFF_RELOC_AMD64_REL32_1;
- break;
- case 2:
- reloc->type = COFF_RELOC_AMD64_REL32_2;
- break;
- case 3:
- reloc->type = COFF_RELOC_AMD64_REL32_3;
- break;
- case 4:
- reloc->type = COFF_RELOC_AMD64_REL32_4;
- break;
- case 5:
- reloc->type = COFF_RELOC_AMD64_REL32_5;
- break;
- default:
- yasm_error_set(YASM_ERROR_TYPE,
- N_("coff: invalid relocation size"));
- return 1;
- }
- } else
- yasm_internal_error(N_("coff objfmt: unrecognized machine"));
- } else if (value->seg_of) {
- if (objfmt_coff->machine == COFF_MACHINE_I386)
- reloc->type = COFF_RELOC_I386_SECTION;
- else if (objfmt_coff->machine == COFF_MACHINE_AMD64)
- reloc->type = COFF_RELOC_AMD64_SECTION;
- else
- yasm_internal_error(N_("coff objfmt: unrecognized machine"));
- } else if (value->section_rel) {
- if (objfmt_coff->machine == COFF_MACHINE_I386)
- reloc->type = COFF_RELOC_I386_SECREL;
- else if (objfmt_coff->machine == COFF_MACHINE_AMD64)
- reloc->type = COFF_RELOC_AMD64_SECREL;
- else
- yasm_internal_error(N_("coff objfmt: unrecognized machine"));
- } else {
- if (objfmt_coff->machine == COFF_MACHINE_I386) {
- if (nobase)
- reloc->type = COFF_RELOC_I386_ADDR32NB;
- else
- reloc->type = COFF_RELOC_I386_ADDR32;
- } else if (objfmt_coff->machine == COFF_MACHINE_AMD64) {
- if (valsize == 32) {
- if (nobase)
- reloc->type = COFF_RELOC_AMD64_ADDR32NB;
- else
- reloc->type = COFF_RELOC_AMD64_ADDR32;
- } else if (valsize == 64)
- reloc->type = COFF_RELOC_AMD64_ADDR64;
- else {
- yasm_error_set(YASM_ERROR_TYPE,
- N_("coff: invalid relocation size"));
- return 1;
- }
- } else
- yasm_internal_error(N_("coff objfmt: unrecognized machine"));
- }
- info->csd->nreloc++;
- yasm_section_add_reloc(info->sect, (yasm_reloc *)reloc, yasm_xfree);
- }
-
- /* Build up final integer output from intn_val, intn_minus, value->abs,
- * and dist. We do all this at the end to avoid creating temporary
- * intnums above (except for dist).
- */
- if (intn_minus <= intn_val)
- intn = yasm_intnum_create_uint(intn_val-intn_minus);
- else {
- intn = yasm_intnum_create_uint(intn_minus-intn_val);
- yasm_intnum_calc(intn, YASM_EXPR_NEG, NULL);
- }
-
- if (value->abs) {
- yasm_intnum *intn2 = yasm_expr_get_intnum(&value->abs, 0);
- if (!intn2) {
- yasm_error_set(YASM_ERROR_TOO_COMPLEX,
- N_("coff: relocation too complex"));
- yasm_intnum_destroy(intn);
- if (dist)
- yasm_intnum_destroy(dist);
- return 1;
- }
- yasm_intnum_calc(intn, YASM_EXPR_ADD, intn2);
- }
-
- if (dist) {
- yasm_intnum_calc(intn, YASM_EXPR_ADD, dist);
- yasm_intnum_destroy(dist);
- }
-
- retval = yasm_arch_intnum_tobytes(info->object->arch, intn, buf, destsize,
- valsize, 0, bc, warn);
- yasm_intnum_destroy(intn);
- return retval;
-}
-
-static int
-coff_objfmt_output_bytecode(yasm_bytecode *bc, /*@null@*/ void *d)
-{
- /*@null@*/ coff_objfmt_output_info *info = (coff_objfmt_output_info *)d;
- /*@null@*/ /*@only@*/ unsigned char *bigbuf;
- unsigned long size = REGULAR_OUTBUF_SIZE;
- int gap;
-
- assert(info != NULL);
-
- bigbuf = yasm_bc_tobytes(bc, info->buf, &size, &gap, info,
- coff_objfmt_output_value, NULL);
-
- /* Don't bother doing anything else if size ended up being 0. */
- if (size == 0) {
- if (bigbuf)
- yasm_xfree(bigbuf);
- return 0;
- }
-
- info->csd->size += size;
-
- /* Warn that gaps are converted to 0 and write out the 0's. */
- if (gap) {
- unsigned long left;
- yasm_warn_set(YASM_WARN_UNINIT_CONTENTS,
- N_("uninitialized space declared in code/data section: zeroing"));
- /* Write out in chunks */
- memset(info->buf, 0, REGULAR_OUTBUF_SIZE);
- left = size;
- while (left > REGULAR_OUTBUF_SIZE) {
- fwrite(info->buf, REGULAR_OUTBUF_SIZE, 1, info->f);
- left -= REGULAR_OUTBUF_SIZE;
- }
- fwrite(info->buf, left, 1, info->f);
- } else {
- /* Output buf (or bigbuf if non-NULL) to file */
- fwrite(bigbuf ? bigbuf : info->buf, (size_t)size, 1, info->f);
- }
-
- /* If bigbuf was allocated, free it */
- if (bigbuf)
- yasm_xfree(bigbuf);
-
- return 0;
-}
-
-static int
-coff_objfmt_output_section(yasm_section *sect, /*@null@*/ void *d)
-{
- /*@null@*/ coff_objfmt_output_info *info = (coff_objfmt_output_info *)d;
- /*@dependent@*/ /*@null@*/ coff_section_data *csd;
- long pos;
- coff_reloc *reloc;
- unsigned char *localbuf;
-
- assert(info != NULL);
- csd = yasm_section_get_data(sect, &coff_section_data_cb);
- assert(csd != NULL);
-
- /* Add to strtab if in win32 format and name > 8 chars */
- if (info->objfmt_coff->win32) {
- size_t namelen = strlen(yasm_section_get_name(sect));
- if (namelen > 8) {
- csd->strtab_name = info->strtab_offset;
- info->strtab_offset += (unsigned long)(namelen + 1);
- }
- }
-
- if (!csd->isdebug)
- csd->addr = info->addr;
-
- if ((csd->flags & COFF_STYP_STD_MASK) == COFF_STYP_BSS) {
- /* Don't output BSS sections.
- * TODO: Check for non-reserve bytecodes?
- */
- pos = 0; /* position = 0 because it's not in the file */
- csd->size = yasm_bc_next_offset(yasm_section_bcs_last(sect));
- } else {
- pos = ftell(info->f);
- if (pos == -1) {
- yasm__fatal(N_("could not get file position on output file"));
- /*@notreached@*/
- return 1;
- }
-
- info->sect = sect;
- info->csd = csd;
- yasm_section_bcs_traverse(sect, info->errwarns, info,
- coff_objfmt_output_bytecode);
-
- /* Sanity check final section size */
- if (yasm_errwarns_num_errors(info->errwarns, 0) == 0 &&
- csd->size != yasm_bc_next_offset(yasm_section_bcs_last(sect)))
- yasm_internal_error(
- N_("coff: section computed size did not match actual size"));
- }
-
- /* Empty? Go on to next section */
- if (csd->size == 0)
- return 0;
-
- if (!csd->isdebug)
- info->addr += csd->size;
- csd->scnptr = (unsigned long)pos;
-
- /* No relocations to output? Go on to next section */
- if (csd->nreloc == 0)
- return 0;
-
- pos = ftell(info->f);
- if (pos == -1) {
- yasm__fatal(N_("could not get file position on output file"));
- /*@notreached@*/
- return 1;
- }
- csd->relptr = (unsigned long)pos;
-
- /* If >=64K relocs (for Win32/64), we set a flag in the section header
- * (NRELOC_OVFL) and the first relocation contains the number of relocs.
- */
- if (csd->nreloc >= 64*1024 && info->objfmt_coff->win32) {
- localbuf = info->buf;
- YASM_WRITE_32_L(localbuf, csd->nreloc+1); /* address of relocation */
- YASM_WRITE_32_L(localbuf, 0); /* relocated symbol */
- YASM_WRITE_16_L(localbuf, 0); /* type of relocation */
- fwrite(info->buf, 10, 1, info->f);
- }
-
- reloc = (coff_reloc *)yasm_section_relocs_first(sect);
- while (reloc) {
- /*@null@*/ coff_symrec_data *csymd;
- localbuf = info->buf;
-
- csymd = yasm_symrec_get_data(reloc->reloc.sym, &coff_symrec_data_cb);
- if (!csymd)
- yasm_internal_error(
- N_("coff: no symbol data for relocated symbol"));
-
- yasm_intnum_get_sized(reloc->reloc.addr, localbuf, 4, 32, 0, 0, 0);
- localbuf += 4; /* address of relocation */
- YASM_WRITE_32_L(localbuf, csymd->index); /* relocated symbol */
- YASM_WRITE_16_L(localbuf, reloc->type); /* type of relocation */
- fwrite(info->buf, 10, 1, info->f);
-
- reloc = (coff_reloc *)yasm_section_reloc_next((yasm_reloc *)reloc);
- }
-
- return 0;
-}
-
-static int
-coff_objfmt_output_sectstr(yasm_section *sect, /*@null@*/ void *d)
-{
- /*@null@*/ coff_objfmt_output_info *info = (coff_objfmt_output_info *)d;
- const char *name;
- size_t len;
-
- /* Add to strtab if in win32 format and name > 8 chars */
- if (!info->objfmt_coff->win32)
- return 0;
-
- name = yasm_section_get_name(sect);
- len = strlen(name);
- if (len > 8)
- fwrite(name, len+1, 1, info->f);
- return 0;
-}
-
-static int
-coff_objfmt_output_secthead(yasm_section *sect, /*@null@*/ void *d)
-{
- /*@null@*/ coff_objfmt_output_info *info = (coff_objfmt_output_info *)d;
- yasm_objfmt_coff *objfmt_coff;
- /*@dependent@*/ /*@null@*/ coff_section_data *csd;
- unsigned char *localbuf;
- unsigned long align = yasm_section_get_align(sect);
-
- assert(info != NULL);
- objfmt_coff = info->objfmt_coff;
- csd = yasm_section_get_data(sect, &coff_section_data_cb);
- assert(csd != NULL);
-
- /* Check to see if alignment is supported size */
- if (align > 8192)
- align = 8192;
-
- /* Convert alignment into flags setting */
- csd->flags &= ~COFF_STYP_ALIGN_MASK;
- while (align != 0) {
- csd->flags += 1<<COFF_STYP_ALIGN_SHIFT;
- align >>= 1;
- }
-
- /* section name */
- localbuf = info->buf;
- if (strlen(yasm_section_get_name(sect)) > 8) {
- char namenum[30];
- sprintf(namenum, "/%ld", csd->strtab_name);
- strncpy((char *)localbuf, namenum, 8);
- } else
- strncpy((char *)localbuf, yasm_section_get_name(sect), 8);
- localbuf += 8;
- if (csd->isdebug) {
- YASM_WRITE_32_L(localbuf, 0); /* physical address */
- YASM_WRITE_32_L(localbuf, 0); /* virtual address */
- } else {
- YASM_WRITE_32_L(localbuf, csd->addr); /* physical address */
- if (COFF_SET_VMA)
- YASM_WRITE_32_L(localbuf, csd->addr);/* virtual address */
- else
- YASM_WRITE_32_L(localbuf, 0); /* virtual address */
- }
- YASM_WRITE_32_L(localbuf, csd->size); /* section size */
- YASM_WRITE_32_L(localbuf, csd->scnptr); /* file ptr to data */
- YASM_WRITE_32_L(localbuf, csd->relptr); /* file ptr to relocs */
- YASM_WRITE_32_L(localbuf, 0); /* file ptr to line nums */
- if (csd->nreloc >= 64*1024) {
- /* Win32/64 has special handling for this case. */
- if (objfmt_coff->win32)
- csd->flags |= COFF_STYP_NRELOC_OVFL;
- else {
- yasm_warn_set(YASM_WARN_GENERAL,
- N_("too many relocations in section `%s'"),
- yasm_section_get_name(sect));
- yasm_errwarn_propagate(info->errwarns, 0);
- }
- YASM_WRITE_16_L(localbuf, 0xFFFF); /* max out */
- } else
- YASM_WRITE_16_L(localbuf, csd->nreloc); /* num of relocation entries */
- YASM_WRITE_16_L(localbuf, 0); /* num of line number entries */
- YASM_WRITE_32_L(localbuf, csd->flags); /* flags */
- fwrite(info->buf, 40, 1, info->f);
-
- return 0;
-}
-
-static int
-coff_objfmt_count_sym(yasm_symrec *sym, /*@null@*/ void *d)
-{
- /*@null@*/ coff_objfmt_output_info *info = (coff_objfmt_output_info *)d;
- yasm_sym_vis vis = yasm_symrec_get_visibility(sym);
- coff_symrec_data *sym_data;
-
- assert(info != NULL);
-
- sym_data = yasm_symrec_get_data(sym, &coff_symrec_data_cb);
-
- if (info->all_syms || vis != YASM_SYM_LOCAL || yasm_symrec_is_abs(sym) ||
- (sym_data && sym_data->forcevis)) {
- /* Save index in symrec data */
- if (!sym_data)
- sym_data = coff_objfmt_sym_set_data(sym, COFF_SCL_NULL, 0,
- COFF_SYMTAB_AUX_NONE);
- /* Set storage class based on visibility if not already set */
- if (sym_data->sclass == COFF_SCL_NULL) {
- if (vis & (YASM_SYM_EXTERN|YASM_SYM_GLOBAL|YASM_SYM_COMMON))
- sym_data->sclass = COFF_SCL_EXT;
- else
- sym_data->sclass = COFF_SCL_STAT;
- }
-
- sym_data->index = info->indx;
-
- info->indx += sym_data->numaux + 1;
- }
- return 0;
-}
-
-static int
-coff_objfmt_output_sym(yasm_symrec *sym, /*@null@*/ void *d)
-{
- /*@null@*/ coff_objfmt_output_info *info = (coff_objfmt_output_info *)d;
- yasm_sym_vis vis = yasm_symrec_get_visibility(sym);
- int is_abs = yasm_symrec_is_abs(sym);
- /*@dependent@*/ /*@null@*/ coff_symrec_data *csymd;
- yasm_valparamhead *objext_valparams =
- yasm_symrec_get_objext_valparams(sym);
- csymd = yasm_symrec_get_data(sym, &coff_symrec_data_cb);
-
- assert(info != NULL);
-
- /* Look for "function" flag on global syms */
- if (csymd && csymd->type == 0 && (vis & YASM_SYM_GLOBAL) != 0) {
- if (objext_valparams) {
- const char *id = yasm_vp_id(yasm_vps_first(objext_valparams));
- if (yasm__strcasecmp(id, "function") == 0)
- csymd->type = 0x20;
- }
- }
-
- /* Don't output local syms unless outputting all syms */
- if (info->all_syms || vis != YASM_SYM_LOCAL || is_abs ||
- (csymd && csymd->forcevis)) {
- /*@only*/ char *name;
- const yasm_expr *equ_val;
- const yasm_intnum *intn;
- unsigned char *localbuf;
- size_t len;
- int aux;
- unsigned long value = 0;
- unsigned int scnum = 0xfffe; /* -2 = debugging symbol */
- /*@dependent@*/ /*@null@*/ yasm_section *sect;
- /*@dependent@*/ /*@null@*/ yasm_bytecode *precbc;
- unsigned long scnlen = 0; /* for sect auxent */
- unsigned long nreloc = 0; /* for sect auxent */
- yasm_objfmt_coff *objfmt_coff = info->objfmt_coff;
-
- if (is_abs)
- name = yasm__xstrdup(".absolut");
- else
- name = yasm_symrec_get_global_name(sym, info->object);
- len = strlen(name);
-
- /* Get symrec's of_data (needed for storage class) */
- if (!csymd)
- yasm_internal_error(N_("coff: expected sym data to be present"));
-
- /* Look at symrec for value/scnum/etc. */
- if (yasm_symrec_get_label(sym, &precbc)) {
- if (precbc)
- sect = yasm_bc_get_section(precbc);
- else
- sect = NULL;
- /* it's a label: get value and offset.
- * If there is not a section, leave as debugging symbol.
- */
- if (sect) {
- /*@dependent@*/ /*@null@*/ coff_section_data *csectd;
- csectd = yasm_section_get_data(sect, &coff_section_data_cb);
- if (csectd) {
- scnum = csectd->scnum;
- scnlen = csectd->size;
- nreloc = csectd->nreloc;
- if (COFF_SET_VMA)
- value = csectd->addr;
- } else
- yasm_internal_error(N_("didn't understand section"));
- if (precbc)
- value += yasm_bc_next_offset(precbc);
- }
- } else if ((equ_val = yasm_symrec_get_equ(sym))) {
- yasm_expr *equ_val_copy = yasm_expr_copy(equ_val);
- intn = yasm_expr_get_intnum(&equ_val_copy, 1);
- if (!intn) {
- if (vis & YASM_SYM_GLOBAL) {
- yasm_error_set(YASM_ERROR_NOT_CONSTANT,
- N_("global EQU value not an integer expression"));
- yasm_errwarn_propagate(info->errwarns, equ_val->line);
- }
- } else
- value = yasm_intnum_get_uint(intn);
- yasm_expr_destroy(equ_val_copy);
-
- scnum = 0xffff; /* -1 = absolute symbol */
- } else {
- if (vis & YASM_SYM_COMMON) {
- /*@dependent@*/ /*@null@*/ yasm_expr **csize_expr;
- csize_expr = yasm_symrec_get_common_size(sym);
- assert(csize_expr != NULL);
- intn = yasm_expr_get_intnum(csize_expr, 1);
- if (!intn) {
- yasm_error_set(YASM_ERROR_NOT_CONSTANT,
- N_("COMMON data size not an integer expression"));
- yasm_errwarn_propagate(info->errwarns,
- (*csize_expr)->line);
- } else
- value = yasm_intnum_get_uint(intn);
- scnum = 0;
- }
- if (vis & YASM_SYM_EXTERN)
- scnum = 0;
- }
-
- localbuf = info->buf;
- if (len > 8) {
- YASM_WRITE_32_L(localbuf, 0); /* "zeros" field */
- YASM_WRITE_32_L(localbuf, info->strtab_offset); /* strtab offset */
- info->strtab_offset += (unsigned long)(len+1);
- } else {
- /* <8 chars, so no string table entry needed */
- strncpy((char *)localbuf, name, 8);
- localbuf += 8;
- }
- YASM_WRITE_32_L(localbuf, value); /* value */
- YASM_WRITE_16_L(localbuf, scnum); /* section number */
- YASM_WRITE_16_L(localbuf, csymd->type); /* type */
- YASM_WRITE_8(localbuf, csymd->sclass); /* storage class */
- YASM_WRITE_8(localbuf, csymd->numaux); /* number of aux entries */
- fwrite(info->buf, 18, 1, info->f);
- for (aux=0; aux<csymd->numaux; aux++) {
- localbuf = info->buf;
- memset(localbuf, 0, 18);
- switch (csymd->auxtype) {
- case COFF_SYMTAB_AUX_NONE:
- break;
- case COFF_SYMTAB_AUX_SECT:
- YASM_WRITE_32_L(localbuf, scnlen); /* section length */
- YASM_WRITE_16_L(localbuf, nreloc); /* number relocs */
- YASM_WRITE_16_L(localbuf, 0); /* number line nums */
- break;
- case COFF_SYMTAB_AUX_FILE:
- len = strlen(csymd->aux[0].fname);
- if (len > 14) {
- YASM_WRITE_32_L(localbuf, 0);
- YASM_WRITE_32_L(localbuf, info->strtab_offset);
- info->strtab_offset += (unsigned long)(len+1);
- } else
- strncpy((char *)localbuf, csymd->aux[0].fname, 14);
- break;
- default:
- yasm_internal_error(
- N_("coff: unrecognized aux symtab type"));
- }
- fwrite(info->buf, 18, 1, info->f);
- }
- yasm_xfree(name);
- }
- return 0;
-}
-
-static int
-coff_objfmt_output_str(yasm_symrec *sym, /*@null@*/ void *d)
-{
- /*@null@*/ coff_objfmt_output_info *info = (coff_objfmt_output_info *)d;
- yasm_sym_vis vis = yasm_symrec_get_visibility(sym);
- /*@dependent@*/ /*@null@*/ coff_symrec_data *csymd;
- csymd = yasm_symrec_get_data(sym, &coff_symrec_data_cb);
-
- assert(info != NULL);
-
- /* Don't output local syms unless outputting all syms */
- if (info->all_syms || vis != YASM_SYM_LOCAL ||
- (csymd && csymd->forcevis)) {
- /*@only@*/ char *name = yasm_symrec_get_global_name(sym, info->object);
- size_t len = strlen(name);
- int aux;
-
- if (!csymd)
- yasm_internal_error(N_("coff: expected sym data to be present"));
-
- if (len > 8)
- fwrite(name, len+1, 1, info->f);
- for (aux=0; aux<csymd->numaux; aux++) {
- switch (csymd->auxtype) {
- case COFF_SYMTAB_AUX_FILE:
- len = strlen(csymd->aux[0].fname);
- if (len > 14)
- fwrite(csymd->aux[0].fname, len+1, 1, info->f);
- break;
- default:
- break;
- }
- }
- yasm_xfree(name);
- }
- return 0;
-}
-
-static void
-coff_objfmt_output(yasm_object *object, FILE *f, int all_syms,
- yasm_errwarns *errwarns)
-{
- yasm_objfmt_coff *objfmt_coff = (yasm_objfmt_coff *)object->objfmt;
- coff_objfmt_output_info info;
- unsigned char *localbuf;
- long pos;
- unsigned long symtab_pos;
- unsigned long symtab_count;
- 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);
+/*
+ * COFF (DJGPP) object format
+ *
+ * Copyright (C) 2002-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>
+#include <time.h>
+
+#include <libyasm.h>
+
+#include "coff-objfmt.h"
+
+
+#define REGULAR_OUTBUF_SIZE 1024
+
+/* Defining this to 0 sets all section VMA's to 0 rather than as the same as
+ * the LMA. According to the DJGPP COFF Spec, this should be set to 1
+ * (VMA=LMA), and indeed DJGPP's GCC output shows VMA=LMA. However, NASM
+ * outputs VMA=0 (as if this was 0), and GNU objdump output looks a lot nicer
+ * with VMA=0. Who's right? This is #defined as changing this setting affects
+ * several places in the code.
+ */
+#define COFF_SET_VMA (!objfmt_coff->win32)
+
+#define COFF_MACHINE_I386 0x014C
+#define COFF_MACHINE_AMD64 0x8664
+
+#define COFF_F_LNNO 0x0004 /* line number info NOT present */
+#define COFF_F_LSYMS 0x0008 /* local symbols NOT present */
+#define COFF_F_AR32WR 0x0100 /* 32-bit little endian file */
+
+typedef struct coff_reloc {
+ yasm_reloc reloc;
+ enum {
+ COFF_RELOC_ABSOLUTE = 0, /* absolute, no reloc needed */
+
+ /* I386 relocations */
+ COFF_RELOC_I386_ADDR16 = 0x1, /* 16-bit absolute reference */
+ COFF_RELOC_I386_REL16 = 0x2, /* 16-bit PC-relative reference */
+ COFF_RELOC_I386_ADDR32 = 0x6, /* 32-bit absolute reference */
+ COFF_RELOC_I386_ADDR32NB = 0x7, /* 32-bit absolute ref w/o base */
+ COFF_RELOC_I386_SEG12 = 0x9, /* 16-bit absolute segment ref */
+ COFF_RELOC_I386_SECTION = 0xA, /* section index */
+ COFF_RELOC_I386_SECREL = 0xB, /* offset from start of segment */
+ COFF_RELOC_I386_TOKEN = 0xC, /* CLR metadata token */
+ COFF_RELOC_I386_SECREL7 = 0xD, /* 7-bit offset from base of sect */
+ COFF_RELOC_I386_REL32 = 0x14, /* 32-bit PC-relative reference */
+
+ /* AMD64 relocations */
+ COFF_RELOC_AMD64_ADDR64 = 0x1, /* 64-bit address (VA) */
+ COFF_RELOC_AMD64_ADDR32 = 0x2, /* 32-bit address (VA) */
+ COFF_RELOC_AMD64_ADDR32NB = 0x3, /* 32-bit address w/o base (RVA) */
+ COFF_RELOC_AMD64_REL32 = 0x4, /* 32-bit relative (0 byte dist) */
+ COFF_RELOC_AMD64_REL32_1 = 0x5, /* 32-bit relative (1 byte dist) */
+ COFF_RELOC_AMD64_REL32_2 = 0x6, /* 32-bit relative (2 byte dist) */
+ COFF_RELOC_AMD64_REL32_3 = 0x7, /* 32-bit relative (3 byte dist) */
+ COFF_RELOC_AMD64_REL32_4 = 0x8, /* 32-bit relative (4 byte dist) */
+ COFF_RELOC_AMD64_REL32_5 = 0x9, /* 32-bit relative (5 byte dist) */
+ COFF_RELOC_AMD64_SECTION = 0xA, /* section index */
+ COFF_RELOC_AMD64_SECREL = 0xB, /* 32-bit offset from base of sect */
+ COFF_RELOC_AMD64_SECREL7 = 0xC, /* 7-bit offset from base of sect */
+ COFF_RELOC_AMD64_TOKEN = 0xD /* CLR metadata token */
+ } type; /* type of relocation */
+} coff_reloc;
+
+#define COFF_STYP_TEXT 0x00000020UL
+#define COFF_STYP_DATA 0x00000040UL
+#define COFF_STYP_BSS 0x00000080UL
+#define COFF_STYP_INFO 0x00000200UL
+#define COFF_STYP_STD_MASK 0x000003FFUL
+#define COFF_STYP_ALIGN_MASK 0x00F00000UL
+#define COFF_STYP_ALIGN_SHIFT 20
+#define COFF_STYP_NRELOC_OVFL 0x01000000UL
+#define COFF_STYP_DISCARD 0x02000000UL
+#define COFF_STYP_NOCACHE 0x04000000UL
+#define COFF_STYP_NOPAGE 0x08000000UL
+#define COFF_STYP_SHARED 0x10000000UL
+#define COFF_STYP_EXECUTE 0x20000000UL
+#define COFF_STYP_READ 0x40000000UL
+#define COFF_STYP_WRITE 0x80000000UL
+#define COFF_STYP_WIN32_MASK 0xFF000000UL
+
+#define COFF_FLAG_NOBASE (1UL<<0) /* Use no-base (NB) relocs */
+
+typedef struct coff_section_data {
+ /*@dependent@*/ yasm_symrec *sym; /* symbol created for this section */
+ unsigned int scnum; /* section number (1=first section) */
+ unsigned long flags; /* section flags (see COFF_STYP_* above) */
+ unsigned long addr; /* starting memory address (first section -> 0) */
+ unsigned long scnptr; /* file ptr to raw data */
+ unsigned long size; /* size of raw data (section data) in bytes */
+ unsigned long relptr; /* file ptr to relocation */
+ unsigned long nreloc; /* number of relocation entries >64k -> error */
+ unsigned long flags2; /* internal flags (see COFF_FLAG_* above) */
+ unsigned long strtab_name; /* strtab offset of name if name > 8 chars */
+ int isdebug; /* is a debug section? */
+} coff_section_data;
+
+typedef enum coff_symrec_sclass {
+ COFF_SCL_EFCN = 0xff, /* physical end of function */
+ COFF_SCL_NULL = 0,
+ COFF_SCL_AUTO = 1, /* automatic variable */
+ COFF_SCL_EXT = 2, /* external symbol */
+ COFF_SCL_STAT = 3, /* static */
+ COFF_SCL_REG = 4, /* register variable */
+ COFF_SCL_EXTDEF = 5, /* external definition */
+ COFF_SCL_LABEL = 6, /* label */
+ COFF_SCL_ULABEL = 7, /* undefined label */
+ COFF_SCL_MOS = 8, /* member of structure */
+ COFF_SCL_ARG = 9, /* function argument */
+ COFF_SCL_STRTAG = 10, /* structure tag */
+ COFF_SCL_MOU = 11, /* member of union */
+ COFF_SCL_UNTAG = 12, /* union tag */
+ COFF_SCL_TPDEF = 13, /* type definition */
+ COFF_SCL_USTATIC = 14, /* undefined static */
+ COFF_SCL_ENTAG = 15, /* enumeration tag */
+ COFF_SCL_MOE = 16, /* member of enumeration */
+ COFF_SCL_REGPARM = 17, /* register parameter */
+ COFF_SCL_FIELD = 18, /* bit field */
+ COFF_SCL_AUTOARG = 19, /* auto argument */
+ COFF_SCL_LASTENT = 20, /* dummy entry (end of block) */
+ COFF_SCL_BLOCK = 100, /* ".bb" or ".eb" */
+ COFF_SCL_FCN = 101, /* ".bf" or ".ef" */
+ COFF_SCL_EOS = 102, /* end of structure */
+ COFF_SCL_FILE = 103, /* file name */
+ COFF_SCL_LINE = 104, /* line # reformatted as symbol table entry */
+ COFF_SCL_ALIAS = 105, /* duplicate tag */
+ COFF_SCL_HIDDEN = 106 /* ext symbol in dmert public lib */
+} coff_symrec_sclass;
+
+typedef union coff_symtab_auxent {
+ /* no data needed for section symbol auxent, all info avail from sym */
+ /*@owned@*/ char *fname; /* filename aux entry */
+} coff_symtab_auxent;
+
+typedef enum coff_symtab_auxtype {
+ COFF_SYMTAB_AUX_NONE = 0,
+ COFF_SYMTAB_AUX_SECT,
+ COFF_SYMTAB_AUX_FILE
+} coff_symtab_auxtype;
+
+typedef struct coff_symrec_data {
+ int forcevis; /* force visibility in symbol table */
+ unsigned long index; /* assigned COFF symbol table index */
+ unsigned int type; /* type */
+ coff_symrec_sclass sclass; /* storage class */
+
+ int numaux; /* number of auxiliary entries */
+ coff_symtab_auxtype auxtype; /* type of aux entries */
+ coff_symtab_auxent aux[1]; /* actually may be any size (including 0) */
+} coff_symrec_data;
+
+typedef struct yasm_objfmt_coff {
+ yasm_objfmt_base objfmt; /* base structure */
+
+ unsigned int parse_scnum; /* sect numbering in parser */
+ int win32; /* nonzero for win32/64 output */
+ int win64; /* nonzero for win64 output */
+
+ unsigned int machine; /* COFF machine to use */
+
+ coff_symrec_data *filesym_data; /* Data for .file symbol */
+
+ /* data for .def/.endef and related directives */
+ coff_symrec_data *def_sym; /* symbol specified by .def */
+
+ /* 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_symrec *ssym_imagebase; /* ..imagebase symbol for win64 */
+} yasm_objfmt_coff;
+
+typedef struct coff_objfmt_output_info {
+ yasm_object *object;
+ yasm_objfmt_coff *objfmt_coff;
+ yasm_errwarns *errwarns;
+ /*@dependent@*/ FILE *f;
+ /*@only@*/ unsigned char *buf;
+ yasm_section *sect;
+ /*@dependent@*/ coff_section_data *csd;
+ unsigned long addr; /* start of next section */
+
+ unsigned long indx; /* current symbol index */
+ int all_syms; /* outputting all symbols? */
+ unsigned long strtab_offset; /* current string table offset */
+} coff_objfmt_output_info;
+
+static void coff_section_data_destroy(/*@only@*/ void *d);
+static void coff_section_data_print(void *data, FILE *f, int indent_level);
+
+static const yasm_assoc_data_callback coff_section_data_cb = {
+ coff_section_data_destroy,
+ coff_section_data_print
+};
+
+static void coff_symrec_data_destroy(/*@only@*/ void *d);
+static void coff_symrec_data_print(void *data, FILE *f, int indent_level);
+
+static const yasm_assoc_data_callback coff_symrec_data_cb = {
+ coff_symrec_data_destroy,
+ coff_symrec_data_print
+};
+
+/* Bytecode callback function prototypes */
+static void win32_sxdata_bc_destroy(void *contents);
+static void win32_sxdata_bc_print(const void *contents, FILE *f,
+ int indent_level);
+static int win32_sxdata_bc_calc_len
+ (yasm_bytecode *bc, yasm_bc_add_span_func add_span, void *add_span_data);
+static int win32_sxdata_bc_tobytes
+ (yasm_bytecode *bc, unsigned char **bufp, unsigned char *bufstart, void *d,
+ yasm_output_value_func output_value,
+ /*@null@*/ yasm_output_reloc_func output_reloc);
+
+/* Bytecode callback structures */
+static const yasm_bytecode_callback win32_sxdata_bc_callback = {
+ win32_sxdata_bc_destroy,
+ win32_sxdata_bc_print,
+ yasm_bc_finalize_common,
+ NULL,
+ win32_sxdata_bc_calc_len,
+ yasm_bc_expand_common,
+ win32_sxdata_bc_tobytes,
+ 0
+};
+
+yasm_objfmt_module yasm_coff_LTX_objfmt;
+yasm_objfmt_module yasm_win32_LTX_objfmt;
+yasm_objfmt_module yasm_win64_LTX_objfmt;
+
+
+static /*@dependent@*/ coff_symrec_data *
+coff_objfmt_sym_set_data(yasm_symrec *sym, coff_symrec_sclass sclass,
+ int numaux, coff_symtab_auxtype auxtype)
+{
+ coff_symrec_data *sym_data;
+
+ sym_data = yasm_xmalloc(sizeof(coff_symrec_data) +
+ (numaux-1)*sizeof(coff_symtab_auxent));
+ sym_data->forcevis = 0;
+ sym_data->index = 0;
+ sym_data->type = 0;
+ sym_data->sclass = sclass;
+ sym_data->numaux = numaux;
+ sym_data->auxtype = auxtype;
+
+ yasm_symrec_add_data(sym, &coff_symrec_data_cb, sym_data);
+
+ return sym_data;
+}
+
+static yasm_objfmt_coff *
+coff_common_create(yasm_object *object)
+{
+ yasm_objfmt_coff *objfmt_coff = yasm_xmalloc(sizeof(yasm_objfmt_coff));
+ yasm_symrec *filesym;
+
+ /* Only support x86 arch */
+ if (yasm__strcasecmp(yasm_arch_keyword(object->arch), "x86") != 0) {
+ yasm_xfree(objfmt_coff);
+ return NULL;
+ }
+
+ objfmt_coff->parse_scnum = 1; /* section numbering starts at 1 */
+
+ /* FIXME: misuse of NULL bytecode here; it works, but only barely. */
+ filesym = yasm_symtab_define_special(object->symtab, ".file",
+ YASM_SYM_GLOBAL);
+ objfmt_coff->filesym_data =
+ coff_objfmt_sym_set_data(filesym, COFF_SCL_FILE, 1,
+ COFF_SYMTAB_AUX_FILE);
+ /* Filename is set in coff_objfmt_output */
+ objfmt_coff->filesym_data->aux[0].fname = NULL;
+
+ objfmt_coff->proc_frame = 0;
+ objfmt_coff->done_prolog = 0;
+ objfmt_coff->unwind = NULL;
+ objfmt_coff->ssym_imagebase = NULL;
+
+ return objfmt_coff;
+}
+
+static yasm_objfmt *
+coff_objfmt_create(yasm_object *object)
+{
+ yasm_objfmt_coff *objfmt_coff = coff_common_create(object);
+
+ if (objfmt_coff) {
+ /* Support x86 and amd64 machines of x86 arch */
+ if (yasm__strcasecmp(yasm_arch_get_machine(object->arch), "x86") == 0)
+ objfmt_coff->machine = COFF_MACHINE_I386;
+ else if (yasm__strcasecmp(yasm_arch_get_machine(object->arch),
+ "amd64") == 0)
+ objfmt_coff->machine = COFF_MACHINE_AMD64;
+ else {
+ yasm_xfree(objfmt_coff);
+ return NULL;
+ }
+
+ objfmt_coff->objfmt.module = &yasm_coff_LTX_objfmt;
+ objfmt_coff->win32 = 0;
+ objfmt_coff->win64 = 0;
+ }
+ return (yasm_objfmt *)objfmt_coff;
+}
+
+static yasm_objfmt *
+win32_objfmt_create(yasm_object *object)
+{
+ yasm_objfmt_coff *objfmt_coff = coff_common_create(object);
+
+ if (objfmt_coff) {
+ /* Support x86 and amd64 machines of x86 arch.
+ * (amd64 machine supported for backwards compatibility)
+ */
+ if (yasm__strcasecmp(yasm_arch_get_machine(object->arch),
+ "x86") == 0) {
+ objfmt_coff->machine = COFF_MACHINE_I386;
+ objfmt_coff->objfmt.module = &yasm_win32_LTX_objfmt;
+ objfmt_coff->win64 = 0;
+ } else if (yasm__strcasecmp(yasm_arch_get_machine(object->arch),
+ "amd64") == 0) {
+ objfmt_coff->machine = COFF_MACHINE_AMD64;
+ objfmt_coff->objfmt.module = &yasm_win64_LTX_objfmt;
+ objfmt_coff->win64 = 1;
+ } else {
+ yasm_xfree(objfmt_coff);
+ return NULL;
+ }
+
+ objfmt_coff->win32 = 1;
+ /* Define a @feat.00 symbol for win32 safeseh handling */
+ if (!objfmt_coff->win64) {
+ yasm_symrec *feat00;
+ coff_symrec_data *sym_data;
+ feat00 = yasm_symtab_define_equ(object->symtab, "@feat.00",
+ yasm_expr_create_ident(yasm_expr_int(
+ yasm_intnum_create_uint(1)), 0), 0);
+ sym_data = coff_objfmt_sym_set_data(feat00, COFF_SCL_STAT, 0,
+ COFF_SYMTAB_AUX_NONE);
+ sym_data->forcevis = 1;
+ }
+ }
+ return (yasm_objfmt *)objfmt_coff;
+}
+
+static yasm_objfmt *
+win64_objfmt_create(yasm_object *object)
+{
+ yasm_objfmt_coff *objfmt_coff = coff_common_create(object);
+
+ if (objfmt_coff) {
+ /* Support amd64 machine of x86 arch */
+ if (yasm__strcasecmp(yasm_arch_get_machine(object->arch),
+ "amd64") == 0) {
+ objfmt_coff->machine = COFF_MACHINE_AMD64;
+ } else {
+ yasm_xfree(objfmt_coff);
+ return NULL;
+ }
+
+ objfmt_coff->objfmt.module = &yasm_win64_LTX_objfmt;
+ objfmt_coff->win32 = 1;
+ objfmt_coff->win64 = 1;
+ objfmt_coff->ssym_imagebase =
+ yasm_symtab_define_label(object->symtab, "..imagebase", NULL, 0, 0);
+ }
+ return (yasm_objfmt *)objfmt_coff;
+}
+
+static void
+coff_objfmt_init_new_section(yasm_section *sect, unsigned long line)
+{
+ yasm_object *object = yasm_section_get_object(sect);
+ const char *sectname = yasm_section_get_name(sect);
+ yasm_objfmt_coff *objfmt_coff = (yasm_objfmt_coff *)object->objfmt;
+ coff_section_data *data;
+ yasm_symrec *sym;
+
+ data = yasm_xmalloc(sizeof(coff_section_data));
+ data->scnum = objfmt_coff->parse_scnum++;
+ data->flags = 0;
+ data->addr = 0;
+ data->scnptr = 0;
+ data->size = 0;
+ data->relptr = 0;
+ data->nreloc = 0;
+ data->flags2 = 0;
+ data->strtab_name = 0;
+ data->isdebug = 0;
+
+ if (yasm__strncasecmp(sectname, ".debug", 6)==0) {
+ data->flags = COFF_STYP_DATA;
+ if (objfmt_coff->win32)
+ data->flags |= COFF_STYP_DISCARD|COFF_STYP_READ;
+ data->isdebug = 1;
+ } else
+ data->flags = COFF_STYP_TEXT;
+
+ yasm_section_add_data(sect, &coff_section_data_cb, data);
+
+ sym = yasm_symtab_define_label(object->symtab, sectname,
+ yasm_section_bcs_first(sect), 1, line);
+ yasm_symrec_declare(sym, YASM_SYM_GLOBAL, line);
+ coff_objfmt_sym_set_data(sym, COFF_SCL_STAT, 1, COFF_SYMTAB_AUX_SECT);
+ data->sym = sym;
+}
+
+static int
+coff_objfmt_set_section_addr(yasm_section *sect, /*@null@*/ void *d)
+{
+ /*@null@*/ coff_objfmt_output_info *info = (coff_objfmt_output_info *)d;
+ /*@dependent@*/ /*@null@*/ coff_section_data *csd;
+
+ assert(info != NULL);
+ csd = yasm_section_get_data(sect, &coff_section_data_cb);
+ assert(csd != NULL);
+
+ csd->addr = info->addr;
+ info->addr += yasm_bc_next_offset(yasm_section_bcs_last(sect));
+
+ return 0;
+}
+
+static int
+coff_objfmt_output_value(yasm_value *value, unsigned char *buf,
+ unsigned int destsize, unsigned long offset,
+ yasm_bytecode *bc, int warn, /*@null@*/ void *d)
+{
+ /*@null@*/ coff_objfmt_output_info *info = (coff_objfmt_output_info *)d;
+ yasm_objfmt_coff *objfmt_coff;
+ /*@only@*/ /*@null@*/ yasm_intnum *dist = NULL;
+ /*@dependent@*/ /*@null@*/ yasm_intnum *intn;
+ unsigned long intn_val, intn_minus;
+ int retval;
+ unsigned int valsize = value->size;
+
+ assert(info != NULL);
+ objfmt_coff = info->objfmt_coff;
+
+ if (value->abs)
+ value->abs = yasm_expr_simplify(value->abs, 1);
+
+ /* Try to output constant and PC-relative section-local first.
+ * Note this does NOT output any value with a SEG, WRT, external,
+ * cross-section, or non-PC-relative reference (those are handled below).
+ */
+ switch (yasm_value_output_basic(value, buf, destsize, bc, warn,
+ info->object->arch)) {
+ case -1:
+ return 1;
+ case 0:
+ break;
+ default:
+ return 0;
+ }
+
+ /* Handle other expressions, with relocation if necessary */
+ if (value->rshift > 0
+ || (value->seg_of && (value->wrt || value->curpos_rel))
+ || (value->section_rel && (value->wrt || value->curpos_rel))) {
+ yasm_error_set(YASM_ERROR_TOO_COMPLEX,
+ N_("coff: relocation too complex"));
+ return 1;
+ }
+
+ intn_val = 0;
+ intn_minus = 0;
+ if (value->rel) {
+ yasm_sym_vis vis = yasm_symrec_get_visibility(value->rel);
+ /*@dependent@*/ /*@null@*/ yasm_symrec *sym = value->rel;
+ unsigned long addr;
+ coff_reloc *reloc;
+ int nobase = info->csd->flags2 & COFF_FLAG_NOBASE;
+
+ /* Sometimes we want the relocation to be generated against one
+ * symbol but the value generated correspond to a different symbol.
+ * This is done through (sym being referenced) WRT (sym used for
+ * reloc). Note both syms need to be in the same section!
+ */
+ if (value->wrt && value->wrt == objfmt_coff->ssym_imagebase)
+ nobase = 1;
+ else if (value->wrt) {
+ /*@dependent@*/ /*@null@*/ yasm_bytecode *rel_precbc, *wrt_precbc;
+
+ if (!yasm_symrec_get_label(sym, &rel_precbc)
+ || !yasm_symrec_get_label(value->wrt, &wrt_precbc)) {
+ yasm_error_set(YASM_ERROR_TOO_COMPLEX,
+ N_("coff: wrt expression too complex"));
+ return 1;
+ }
+ dist = yasm_calc_bc_dist(wrt_precbc, rel_precbc);
+ if (!dist) {
+ yasm_error_set(YASM_ERROR_TOO_COMPLEX,
+ N_("coff: cannot wrt across sections"));
+ return 1;
+ }
+ sym = value->wrt;
+ }
+
+ if (vis & YASM_SYM_COMMON) {
+ /* In standard COFF, COMMON symbols have their length added in */
+ if (!objfmt_coff->win32) {
+ /*@dependent@*/ /*@null@*/ yasm_expr **csize_expr;
+ /*@dependent@*/ /*@null@*/ yasm_intnum *common_size;
+
+ csize_expr = yasm_symrec_get_common_size(sym);
+ assert(csize_expr != NULL);
+ common_size = yasm_expr_get_intnum(csize_expr, 1);
+ if (!common_size) {
+ yasm_error_set(YASM_ERROR_TOO_COMPLEX,
+ N_("coff: common size too complex"));
+ return 1;
+ }
+
+ if (yasm_intnum_sign(common_size) < 0) {
+ yasm_error_set(YASM_ERROR_VALUE,
+ N_("coff: common size is negative"));
+ return 1;
+ }
+
+ intn_val += yasm_intnum_get_uint(common_size);
+ }
+ } else if (!(vis & YASM_SYM_EXTERN) && !objfmt_coff->win64) {
+ /*@dependent@*/ /*@null@*/ yasm_bytecode *sym_precbc;
+
+ /* Local symbols need relocation to their section's start */
+ if (yasm_symrec_get_label(sym, &sym_precbc)) {
+ yasm_section *sym_sect = yasm_bc_get_section(sym_precbc);
+ /*@null@*/ coff_section_data *sym_csd;
+ sym_csd = yasm_section_get_data(sym_sect,
+ &coff_section_data_cb);
+ assert(sym_csd != NULL);
+ sym = sym_csd->sym;
+ intn_val = yasm_bc_next_offset(sym_precbc);
+ if (COFF_SET_VMA)
+ intn_val += sym_csd->addr;
+ }
+ }
+
+ if (value->curpos_rel) {
+ /* For standard COFF, need to adjust to start of section, e.g.
+ * subtract out the bytecode offset.
+ * For Win32 COFF, need to adjust based on value size and position.
+ * For Win64 COFF that's IP-relative, adjust to next bytecode;
+ * the difference between the offset+destsize and BC length is
+ * taken care of by special relocation types.
+ */
+ if (objfmt_coff->win64 && value->ip_rel)
+ intn_val += bc->len*bc->mult_int;
+ else if (objfmt_coff->win32)
+ intn_val += offset+destsize;
+ else
+ intn_minus = bc->offset;
+ }
+
+ if (value->seg_of) {
+ /* Segment generation; zero value. */
+ intn_val = 0;
+ intn_minus = 0;
+ }
+
+ /* Generate reloc */
+ reloc = yasm_xmalloc(sizeof(coff_reloc));
+ addr = bc->offset + offset;
+ if (COFF_SET_VMA)
+ addr += info->addr;
+ reloc->reloc.addr = yasm_intnum_create_uint(addr);
+ reloc->reloc.sym = sym;
+
+ if (value->curpos_rel) {
+ if (objfmt_coff->machine == COFF_MACHINE_I386) {
+ if (valsize == 32)
+ reloc->type = COFF_RELOC_I386_REL32;
+ else {
+ yasm_error_set(YASM_ERROR_TYPE,
+ N_("coff: invalid relocation size"));
+ return 1;
+ }
+ } else if (objfmt_coff->machine == COFF_MACHINE_AMD64) {
+ if (valsize != 32) {
+ yasm_error_set(YASM_ERROR_TYPE,
+ N_("coff: invalid relocation size"));
+ return 1;
+ }
+ if (!value->ip_rel)
+ reloc->type = COFF_RELOC_AMD64_REL32;
+ else switch (bc->len*bc->mult_int - (offset+destsize)) {
+ case 0:
+ reloc->type = COFF_RELOC_AMD64_REL32;
+ break;
+ case 1:
+ reloc->type = COFF_RELOC_AMD64_REL32_1;
+ break;
+ case 2:
+ reloc->type = COFF_RELOC_AMD64_REL32_2;
+ break;
+ case 3:
+ reloc->type = COFF_RELOC_AMD64_REL32_3;
+ break;
+ case 4:
+ reloc->type = COFF_RELOC_AMD64_REL32_4;
+ break;
+ case 5:
+ reloc->type = COFF_RELOC_AMD64_REL32_5;
+ break;
+ default:
+ yasm_error_set(YASM_ERROR_TYPE,
+ N_("coff: invalid relocation size"));
+ return 1;
+ }
+ } else
+ yasm_internal_error(N_("coff objfmt: unrecognized machine"));
+ } else if (value->seg_of) {
+ if (objfmt_coff->machine == COFF_MACHINE_I386)
+ reloc->type = COFF_RELOC_I386_SECTION;
+ else if (objfmt_coff->machine == COFF_MACHINE_AMD64)
+ reloc->type = COFF_RELOC_AMD64_SECTION;
+ else
+ yasm_internal_error(N_("coff objfmt: unrecognized machine"));
+ } else if (value->section_rel) {
+ if (objfmt_coff->machine == COFF_MACHINE_I386)
+ reloc->type = COFF_RELOC_I386_SECREL;
+ else if (objfmt_coff->machine == COFF_MACHINE_AMD64)
+ reloc->type = COFF_RELOC_AMD64_SECREL;
+ else
+ yasm_internal_error(N_("coff objfmt: unrecognized machine"));
+ } else {
+ if (objfmt_coff->machine == COFF_MACHINE_I386) {
+ if (nobase)
+ reloc->type = COFF_RELOC_I386_ADDR32NB;
+ else
+ reloc->type = COFF_RELOC_I386_ADDR32;
+ } else if (objfmt_coff->machine == COFF_MACHINE_AMD64) {
+ if (valsize == 32) {
+ if (nobase)
+ reloc->type = COFF_RELOC_AMD64_ADDR32NB;
+ else
+ reloc->type = COFF_RELOC_AMD64_ADDR32;
+ } else if (valsize == 64)
+ reloc->type = COFF_RELOC_AMD64_ADDR64;
+ else {
+ yasm_error_set(YASM_ERROR_TYPE,
+ N_("coff: invalid relocation size"));
+ return 1;
+ }
+ } else
+ yasm_internal_error(N_("coff objfmt: unrecognized machine"));
+ }
+ info->csd->nreloc++;
+ yasm_section_add_reloc(info->sect, (yasm_reloc *)reloc, yasm_xfree);
+ }
+
+ /* Build up final integer output from intn_val, intn_minus, value->abs,
+ * and dist. We do all this at the end to avoid creating temporary
+ * intnums above (except for dist).
+ */
+ if (intn_minus <= intn_val)
+ intn = yasm_intnum_create_uint(intn_val-intn_minus);
+ else {
+ intn = yasm_intnum_create_uint(intn_minus-intn_val);
+ yasm_intnum_calc(intn, YASM_EXPR_NEG, NULL);
+ }
+
+ if (value->abs) {
+ yasm_intnum *intn2 = yasm_expr_get_intnum(&value->abs, 0);
+ if (!intn2) {
+ yasm_error_set(YASM_ERROR_TOO_COMPLEX,
+ N_("coff: relocation too complex"));
+ yasm_intnum_destroy(intn);
+ if (dist)
+ yasm_intnum_destroy(dist);
+ return 1;
+ }
+ yasm_intnum_calc(intn, YASM_EXPR_ADD, intn2);
+ }
+
+ if (dist) {
+ yasm_intnum_calc(intn, YASM_EXPR_ADD, dist);
+ yasm_intnum_destroy(dist);
+ }
+
+ retval = yasm_arch_intnum_tobytes(info->object->arch, intn, buf, destsize,
+ valsize, 0, bc, warn);
+ yasm_intnum_destroy(intn);
+ return retval;
+}
+
+static int
+coff_objfmt_output_bytecode(yasm_bytecode *bc, /*@null@*/ void *d)
+{
+ /*@null@*/ coff_objfmt_output_info *info = (coff_objfmt_output_info *)d;
+ /*@null@*/ /*@only@*/ unsigned char *bigbuf;
+ unsigned long size = REGULAR_OUTBUF_SIZE;
+ int gap;
+
+ assert(info != NULL);
+
+ bigbuf = yasm_bc_tobytes(bc, info->buf, &size, &gap, info,
+ coff_objfmt_output_value, NULL);
+
+ /* Don't bother doing anything else if size ended up being 0. */
+ if (size == 0) {
+ if (bigbuf)
+ yasm_xfree(bigbuf);
+ return 0;
+ }
+
+ info->csd->size += size;
+
+ /* Warn that gaps are converted to 0 and write out the 0's. */
+ if (gap) {
+ unsigned long left;
+ yasm_warn_set(YASM_WARN_UNINIT_CONTENTS,
+ N_("uninitialized space declared in code/data section: zeroing"));
+ /* Write out in chunks */
+ memset(info->buf, 0, REGULAR_OUTBUF_SIZE);
+ left = size;
+ while (left > REGULAR_OUTBUF_SIZE) {
+ fwrite(info->buf, REGULAR_OUTBUF_SIZE, 1, info->f);
+ left -= REGULAR_OUTBUF_SIZE;
+ }
+ fwrite(info->buf, left, 1, info->f);
+ } else {
+ /* Output buf (or bigbuf if non-NULL) to file */
+ fwrite(bigbuf ? bigbuf : info->buf, (size_t)size, 1, info->f);
+ }
+
+ /* If bigbuf was allocated, free it */
+ if (bigbuf)
+ yasm_xfree(bigbuf);
+
+ return 0;
+}
+
+static int
+coff_objfmt_output_section(yasm_section *sect, /*@null@*/ void *d)
+{
+ /*@null@*/ coff_objfmt_output_info *info = (coff_objfmt_output_info *)d;
+ /*@dependent@*/ /*@null@*/ coff_section_data *csd;
+ long pos;
+ coff_reloc *reloc;
+ unsigned char *localbuf;
+
+ assert(info != NULL);
+ csd = yasm_section_get_data(sect, &coff_section_data_cb);
+ assert(csd != NULL);
+
+ /* Add to strtab if in win32 format and name > 8 chars */
+ if (info->objfmt_coff->win32) {
+ size_t namelen = strlen(yasm_section_get_name(sect));
+ if (namelen > 8) {
+ csd->strtab_name = info->strtab_offset;
+ info->strtab_offset += (unsigned long)(namelen + 1);
+ }
+ }
+
+ if (!csd->isdebug)
+ csd->addr = info->addr;
+
+ if ((csd->flags & COFF_STYP_STD_MASK) == COFF_STYP_BSS) {
+ /* Don't output BSS sections.
+ * TODO: Check for non-reserve bytecodes?
+ */
+ pos = 0; /* position = 0 because it's not in the file */
+ csd->size = yasm_bc_next_offset(yasm_section_bcs_last(sect));
+ } else {
+ pos = ftell(info->f);
+ if (pos == -1) {
+ yasm__fatal(N_("could not get file position on output file"));
+ /*@notreached@*/
+ return 1;
+ }
+
+ info->sect = sect;
+ info->csd = csd;
+ yasm_section_bcs_traverse(sect, info->errwarns, info,
+ coff_objfmt_output_bytecode);
+
+ /* Sanity check final section size */
+ if (yasm_errwarns_num_errors(info->errwarns, 0) == 0 &&
+ csd->size != yasm_bc_next_offset(yasm_section_bcs_last(sect)))
+ yasm_internal_error(
+ N_("coff: section computed size did not match actual size"));
+ }
+
+ /* Empty? Go on to next section */
+ if (csd->size == 0)
+ return 0;
+
+ if (!csd->isdebug)
+ info->addr += csd->size;
+ csd->scnptr = (unsigned long)pos;
+
+ /* No relocations to output? Go on to next section */
+ if (csd->nreloc == 0)
+ return 0;
+
+ pos = ftell(info->f);
+ if (pos == -1) {
+ yasm__fatal(N_("could not get file position on output file"));
+ /*@notreached@*/
+ return 1;
+ }
+ csd->relptr = (unsigned long)pos;
+
+ /* If >=64K relocs (for Win32/64), we set a flag in the section header
+ * (NRELOC_OVFL) and the first relocation contains the number of relocs.
+ */
+ if (csd->nreloc >= 64*1024 && info->objfmt_coff->win32) {
+ localbuf = info->buf;
+ YASM_WRITE_32_L(localbuf, csd->nreloc+1); /* address of relocation */
+ YASM_WRITE_32_L(localbuf, 0); /* relocated symbol */
+ YASM_WRITE_16_L(localbuf, 0); /* type of relocation */
+ fwrite(info->buf, 10, 1, info->f);
+ }
+
+ reloc = (coff_reloc *)yasm_section_relocs_first(sect);
+ while (reloc) {
+ /*@null@*/ coff_symrec_data *csymd;
+ localbuf = info->buf;
+
+ csymd = yasm_symrec_get_data(reloc->reloc.sym, &coff_symrec_data_cb);
+ if (!csymd)
+ yasm_internal_error(
+ N_("coff: no symbol data for relocated symbol"));
+
+ yasm_intnum_get_sized(reloc->reloc.addr, localbuf, 4, 32, 0, 0, 0);
+ localbuf += 4; /* address of relocation */
+ YASM_WRITE_32_L(localbuf, csymd->index); /* relocated symbol */
+ YASM_WRITE_16_L(localbuf, reloc->type); /* type of relocation */
+ fwrite(info->buf, 10, 1, info->f);
+
+ reloc = (coff_reloc *)yasm_section_reloc_next((yasm_reloc *)reloc);
+ }
+
+ return 0;
+}
+
+static int
+coff_objfmt_output_sectstr(yasm_section *sect, /*@null@*/ void *d)
+{
+ /*@null@*/ coff_objfmt_output_info *info = (coff_objfmt_output_info *)d;
+ const char *name;
+ size_t len;
+
+ /* Add to strtab if in win32 format and name > 8 chars */
+ if (!info->objfmt_coff->win32)
+ return 0;
+
+ name = yasm_section_get_name(sect);
+ len = strlen(name);
+ if (len > 8)
+ fwrite(name, len+1, 1, info->f);
+ return 0;
+}
+
+static int
+coff_objfmt_output_secthead(yasm_section *sect, /*@null@*/ void *d)
+{
+ /*@null@*/ coff_objfmt_output_info *info = (coff_objfmt_output_info *)d;
+ yasm_objfmt_coff *objfmt_coff;
+ /*@dependent@*/ /*@null@*/ coff_section_data *csd;
+ unsigned char *localbuf;
+ unsigned long align = yasm_section_get_align(sect);
+
+ assert(info != NULL);
+ objfmt_coff = info->objfmt_coff;
+ csd = yasm_section_get_data(sect, &coff_section_data_cb);
+ assert(csd != NULL);
+
+ /* Check to see if alignment is supported size */
+ if (align > 8192)
+ align = 8192;
+
+ /* Convert alignment into flags setting */
+ csd->flags &= ~COFF_STYP_ALIGN_MASK;
+ while (align != 0) {
+ csd->flags += 1<<COFF_STYP_ALIGN_SHIFT;
+ align >>= 1;
+ }
+
+ /* section name */
+ localbuf = info->buf;
+ if (strlen(yasm_section_get_name(sect)) > 8) {
+ char namenum[30];
+ sprintf(namenum, "/%ld", csd->strtab_name);
+ strncpy((char *)localbuf, namenum, 8);
+ } else
+ strncpy((char *)localbuf, yasm_section_get_name(sect), 8);
+ localbuf += 8;
+ if (csd->isdebug) {
+ YASM_WRITE_32_L(localbuf, 0); /* physical address */
+ YASM_WRITE_32_L(localbuf, 0); /* virtual address */
+ } else {
+ YASM_WRITE_32_L(localbuf, csd->addr); /* physical address */
+ if (COFF_SET_VMA)
+ YASM_WRITE_32_L(localbuf, csd->addr);/* virtual address */
+ else
+ YASM_WRITE_32_L(localbuf, 0); /* virtual address */
+ }
+ YASM_WRITE_32_L(localbuf, csd->size); /* section size */
+ YASM_WRITE_32_L(localbuf, csd->scnptr); /* file ptr to data */
+ YASM_WRITE_32_L(localbuf, csd->relptr); /* file ptr to relocs */
+ YASM_WRITE_32_L(localbuf, 0); /* file ptr to line nums */
+ if (csd->nreloc >= 64*1024) {
+ /* Win32/64 has special handling for this case. */
+ if (objfmt_coff->win32)
+ csd->flags |= COFF_STYP_NRELOC_OVFL;
+ else {
+ yasm_warn_set(YASM_WARN_GENERAL,
+ N_("too many relocations in section `%s'"),
+ yasm_section_get_name(sect));
+ yasm_errwarn_propagate(info->errwarns, 0);
+ }
+ YASM_WRITE_16_L(localbuf, 0xFFFF); /* max out */
+ } else
+ YASM_WRITE_16_L(localbuf, csd->nreloc); /* num of relocation entries */
+ YASM_WRITE_16_L(localbuf, 0); /* num of line number entries */
+ YASM_WRITE_32_L(localbuf, csd->flags); /* flags */
+ fwrite(info->buf, 40, 1, info->f);
+
+ return 0;
+}
+
+static int
+coff_objfmt_count_sym(yasm_symrec *sym, /*@null@*/ void *d)
+{
+ /*@null@*/ coff_objfmt_output_info *info = (coff_objfmt_output_info *)d;
+ yasm_sym_vis vis = yasm_symrec_get_visibility(sym);
+ coff_symrec_data *sym_data;
+
+ assert(info != NULL);
+
+ sym_data = yasm_symrec_get_data(sym, &coff_symrec_data_cb);
+
+ if (info->all_syms || vis != YASM_SYM_LOCAL || yasm_symrec_is_abs(sym) ||
+ (sym_data && sym_data->forcevis)) {
+ /* Save index in symrec data */
+ if (!sym_data)
+ sym_data = coff_objfmt_sym_set_data(sym, COFF_SCL_NULL, 0,
+ COFF_SYMTAB_AUX_NONE);
+ /* Set storage class based on visibility if not already set */
+ if (sym_data->sclass == COFF_SCL_NULL) {
+ if (vis & (YASM_SYM_EXTERN|YASM_SYM_GLOBAL|YASM_SYM_COMMON))
+ sym_data->sclass = COFF_SCL_EXT;
+ else
+ sym_data->sclass = COFF_SCL_STAT;
+ }
+
+ sym_data->index = info->indx;
+
+ info->indx += sym_data->numaux + 1;
+ }
+ return 0;
+}
+
+static int
+coff_objfmt_output_sym(yasm_symrec *sym, /*@null@*/ void *d)
+{
+ /*@null@*/ coff_objfmt_output_info *info = (coff_objfmt_output_info *)d;
+ yasm_sym_vis vis = yasm_symrec_get_visibility(sym);
+ int is_abs = yasm_symrec_is_abs(sym);
+ /*@dependent@*/ /*@null@*/ coff_symrec_data *csymd;
+ yasm_valparamhead *objext_valparams =
+ yasm_symrec_get_objext_valparams(sym);
+ csymd = yasm_symrec_get_data(sym, &coff_symrec_data_cb);
+
+ assert(info != NULL);
+
+ /* Look for "function" flag on global syms */
+ if (csymd && csymd->type == 0 && (vis & YASM_SYM_GLOBAL) != 0) {
+ if (objext_valparams) {
+ const char *id = yasm_vp_id(yasm_vps_first(objext_valparams));
+ if (yasm__strcasecmp(id, "function") == 0)
+ csymd->type = 0x20;
+ }
+ }
+
+ /* Don't output local syms unless outputting all syms */
+ if (info->all_syms || vis != YASM_SYM_LOCAL || is_abs ||
+ (csymd && csymd->forcevis)) {
+ /*@only*/ char *name;
+ const yasm_expr *equ_val;
+ const yasm_intnum *intn;
+ unsigned char *localbuf;
+ size_t len;
+ int aux;
+ unsigned long value = 0;
+ unsigned int scnum = 0xfffe; /* -2 = debugging symbol */
+ /*@dependent@*/ /*@null@*/ yasm_section *sect;
+ /*@dependent@*/ /*@null@*/ yasm_bytecode *precbc;
+ unsigned long scnlen = 0; /* for sect auxent */
+ unsigned long nreloc = 0; /* for sect auxent */
+ yasm_objfmt_coff *objfmt_coff = info->objfmt_coff;
+
+ if (is_abs)
+ name = yasm__xstrdup(".absolut");
+ else
+ name = yasm_symrec_get_global_name(sym, info->object);
+ len = strlen(name);
+
+ /* Get symrec's of_data (needed for storage class) */
+ if (!csymd)
+ yasm_internal_error(N_("coff: expected sym data to be present"));
+
+ /* Look at symrec for value/scnum/etc. */
+ if (yasm_symrec_get_label(sym, &precbc)) {
+ if (precbc)
+ sect = yasm_bc_get_section(precbc);
+ else
+ sect = NULL;
+ /* it's a label: get value and offset.
+ * If there is not a section, leave as debugging symbol.
+ */
+ if (sect) {
+ /*@dependent@*/ /*@null@*/ coff_section_data *csectd;
+ csectd = yasm_section_get_data(sect, &coff_section_data_cb);
+ if (csectd) {
+ scnum = csectd->scnum;
+ scnlen = csectd->size;
+ nreloc = csectd->nreloc;
+ if (COFF_SET_VMA)
+ value = csectd->addr;
+ } else
+ yasm_internal_error(N_("didn't understand section"));
+ if (precbc)
+ value += yasm_bc_next_offset(precbc);
+ }
+ } else if ((equ_val = yasm_symrec_get_equ(sym))) {
+ yasm_expr *equ_val_copy = yasm_expr_copy(equ_val);
+ intn = yasm_expr_get_intnum(&equ_val_copy, 1);
+ if (!intn) {
+ if (vis & YASM_SYM_GLOBAL) {
+ yasm_error_set(YASM_ERROR_NOT_CONSTANT,
+ N_("global EQU value not an integer expression"));
+ yasm_errwarn_propagate(info->errwarns, equ_val->line);
+ }
+ } else
+ value = yasm_intnum_get_uint(intn);
+ yasm_expr_destroy(equ_val_copy);
+
+ scnum = 0xffff; /* -1 = absolute symbol */
+ } else {
+ if (vis & YASM_SYM_COMMON) {
+ /*@dependent@*/ /*@null@*/ yasm_expr **csize_expr;
+ csize_expr = yasm_symrec_get_common_size(sym);
+ assert(csize_expr != NULL);
+ intn = yasm_expr_get_intnum(csize_expr, 1);
+ if (!intn) {
+ yasm_error_set(YASM_ERROR_NOT_CONSTANT,
+ N_("COMMON data size not an integer expression"));
+ yasm_errwarn_propagate(info->errwarns,
+ (*csize_expr)->line);
+ } else
+ value = yasm_intnum_get_uint(intn);
+ scnum = 0;
+ }
+ if (vis & YASM_SYM_EXTERN)
+ scnum = 0;
+ }
+
+ localbuf = info->buf;
+ if (len > 8) {
+ YASM_WRITE_32_L(localbuf, 0); /* "zeros" field */
+ YASM_WRITE_32_L(localbuf, info->strtab_offset); /* strtab offset */
+ info->strtab_offset += (unsigned long)(len+1);
+ } else {
+ /* <8 chars, so no string table entry needed */
+ strncpy((char *)localbuf, name, 8);
+ localbuf += 8;
+ }
+ YASM_WRITE_32_L(localbuf, value); /* value */
+ YASM_WRITE_16_L(localbuf, scnum); /* section number */
+ YASM_WRITE_16_L(localbuf, csymd->type); /* type */
+ YASM_WRITE_8(localbuf, csymd->sclass); /* storage class */
+ YASM_WRITE_8(localbuf, csymd->numaux); /* number of aux entries */
+ fwrite(info->buf, 18, 1, info->f);
+ for (aux=0; aux<csymd->numaux; aux++) {
+ localbuf = info->buf;
+ memset(localbuf, 0, 18);
+ switch (csymd->auxtype) {
+ case COFF_SYMTAB_AUX_NONE:
+ break;
+ case COFF_SYMTAB_AUX_SECT:
+ YASM_WRITE_32_L(localbuf, scnlen); /* section length */
+ YASM_WRITE_16_L(localbuf, nreloc); /* number relocs */
+ YASM_WRITE_16_L(localbuf, 0); /* number line nums */
+ break;
+ case COFF_SYMTAB_AUX_FILE:
+ len = strlen(csymd->aux[0].fname);
+ if (len > 14) {
+ YASM_WRITE_32_L(localbuf, 0);
+ YASM_WRITE_32_L(localbuf, info->strtab_offset);
+ info->strtab_offset += (unsigned long)(len+1);
+ } else
+ strncpy((char *)localbuf, csymd->aux[0].fname, 14);
+ break;
+ default:
+ yasm_internal_error(
+ N_("coff: unrecognized aux symtab type"));
+ }
+ fwrite(info->buf, 18, 1, info->f);
+ }
+ yasm_xfree(name);
+ }
+ return 0;
+}
+
+static int
+coff_objfmt_output_str(yasm_symrec *sym, /*@null@*/ void *d)
+{
+ /*@null@*/ coff_objfmt_output_info *info = (coff_objfmt_output_info *)d;
+ yasm_sym_vis vis = yasm_symrec_get_visibility(sym);
+ /*@dependent@*/ /*@null@*/ coff_symrec_data *csymd;
+ csymd = yasm_symrec_get_data(sym, &coff_symrec_data_cb);
+
+ assert(info != NULL);
+
+ /* Don't output local syms unless outputting all syms */
+ if (info->all_syms || vis != YASM_SYM_LOCAL ||
+ (csymd && csymd->forcevis)) {
+ /*@only@*/ char *name = yasm_symrec_get_global_name(sym, info->object);
+ size_t len = strlen(name);
+ int aux;
+
+ if (!csymd)
+ yasm_internal_error(N_("coff: expected sym data to be present"));
+
+ if (len > 8)
+ fwrite(name, len+1, 1, info->f);
+ for (aux=0; aux<csymd->numaux; aux++) {
+ switch (csymd->auxtype) {
+ case COFF_SYMTAB_AUX_FILE:
+ len = strlen(csymd->aux[0].fname);
+ if (len > 14)
+ fwrite(csymd->aux[0].fname, len+1, 1, info->f);
+ break;
+ default:
+ break;
+ }
+ }
+ yasm_xfree(name);
+ }
+ return 0;
+}
+
+static void
+coff_objfmt_output(yasm_object *object, FILE *f, int all_syms,
+ yasm_errwarns *errwarns)
+{
+ yasm_objfmt_coff *objfmt_coff = (yasm_objfmt_coff *)object->objfmt;
+ coff_objfmt_output_info info;
+ unsigned char *localbuf;
+ long pos;
+ unsigned long symtab_pos;
+ unsigned long symtab_count;
+ 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);
if (!object->deb_filename) {
object->deb_filename = yasm_replace_path(
objfmt_coff->objfmt.module->replace_map, objfmt_coff->objfmt.module->replace_map_size,
object->src_filename, strlen(object->src_filename));
}
- objfmt_coff->filesym_data->aux[0].fname =
+ objfmt_coff->filesym_data->aux[0].fname =
yasm__xstrdup(object->deb_filename);
-
- /* Force all syms for win64 because they're needed for relocations.
- * FIXME: Not *all* syms need to be output, only the ones needed for
- * relocation. Find a way to do that someday.
- */
- all_syms |= objfmt_coff->win64;
-
- info.strtab_offset = 4;
- info.object = object;
- info.objfmt_coff = objfmt_coff;
- info.errwarns = errwarns;
- info.f = f;
- info.buf = yasm_xmalloc(REGULAR_OUTBUF_SIZE);
-
- /* Allocate space for headers by seeking forward */
- if (fseek(f, (long)(20+40*(objfmt_coff->parse_scnum-1)), SEEK_SET) < 0) {
- yasm__fatal(N_("could not seek on output file"));
- /*@notreached@*/
- return;
- }
-
- /* Finalize symbol table (assign index to each symbol) */
- info.indx = 0;
- info.all_syms = all_syms;
- yasm_symtab_traverse(object->symtab, &info, coff_objfmt_count_sym);
- symtab_count = info.indx;
-
- /* Section data/relocs */
- if (COFF_SET_VMA) {
- /* If we're setting the VMA, we need to do a first section pass to
- * determine each section's addr value before actually outputting
- * relocations, as a relocation's section address is added into the
- * addends in the generated code.
- */
- info.addr = 0;
- if (yasm_object_sections_traverse(object, &info,
- coff_objfmt_set_section_addr))
- return;
- }
- info.addr = 0;
- if (yasm_object_sections_traverse(object, &info,
- coff_objfmt_output_section))
- return;
-
- /* Symbol table */
- pos = ftell(f);
- if (pos == -1) {
- yasm__fatal(N_("could not get file position on output file"));
- /*@notreached@*/
- return;
- }
- symtab_pos = (unsigned long)pos;
- yasm_symtab_traverse(object->symtab, &info, coff_objfmt_output_sym);
-
- /* String table */
- yasm_fwrite_32_l(info.strtab_offset, f); /* total length */
- yasm_object_sections_traverse(object, &info, coff_objfmt_output_sectstr);
- yasm_symtab_traverse(object->symtab, &info, coff_objfmt_output_str);
-
- /* Write headers */
- if (fseek(f, 0, SEEK_SET) < 0) {
- yasm__fatal(N_("could not seek on output file"));
- /*@notreached@*/
- return;
- }
-
- localbuf = info.buf;
- YASM_WRITE_16_L(localbuf, objfmt_coff->machine); /* magic number */
- YASM_WRITE_16_L(localbuf, objfmt_coff->parse_scnum-1);/* number of sects */
- if (getenv("YASM_TEST_SUITE"))
- ts = 0;
- else
- ts = (unsigned long)time(NULL);
- YASM_WRITE_32_L(localbuf, ts); /* time/date stamp */
- YASM_WRITE_32_L(localbuf, symtab_pos); /* file ptr to symtab */
- YASM_WRITE_32_L(localbuf, symtab_count); /* number of symtabs */
- YASM_WRITE_16_L(localbuf, 0); /* size of optional header (none) */
- /* flags */
- flags = 0;
- if (strcmp(yasm_dbgfmt_keyword(object->dbgfmt), "null")==0)
- flags = COFF_F_LNNO;
- if (!all_syms)
- flags |= COFF_F_LSYMS;
- if (objfmt_coff->machine != COFF_MACHINE_AMD64)
- flags |= COFF_F_AR32WR;
- YASM_WRITE_16_L(localbuf, flags);
- fwrite(info.buf, 20, 1, f);
-
- yasm_object_sections_traverse(object, &info, coff_objfmt_output_secthead);
-
- yasm_xfree(info.buf);
-}
-
-static void
-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);
-}
-
-static yasm_section *
-coff_objfmt_add_default_section(yasm_object *object)
-{
- yasm_objfmt_coff *objfmt_coff = (yasm_objfmt_coff *)object->objfmt;
- yasm_section *retval;
- coff_section_data *csd;
- int isnew;
-
- retval = yasm_object_get_general(object, ".text", 16, 1, 0, &isnew, 0);
- if (isnew) {
- csd = yasm_section_get_data(retval, &coff_section_data_cb);
- csd->flags = COFF_STYP_TEXT;
- if (objfmt_coff->win32)
- csd->flags |= COFF_STYP_EXECUTE | COFF_STYP_READ;
- yasm_section_set_default(retval, 1);
- }
- return retval;
-}
-
-struct coff_section_switch_data {
- int isdefault;
- int gasflags;
- unsigned long flags;
- unsigned long flags2;
- /*@only@*/ /*@null@*/ yasm_intnum *align_intn;
-};
-
-/* GAS-style flags */
-static int
-coff_helper_gasflags(void *obj, yasm_valparam *vp, unsigned long line, void *d,
- /*@unused@*/ uintptr_t arg)
-{
- struct coff_section_switch_data *data =
- (struct coff_section_switch_data *)d;
- int alloc = 0, load = 0, readonly = 0, code = 0, datasect = 0;
- int shared = 0;
- const char *s = yasm_vp_string(vp);
- size_t i;
-
- if (!s) {
- yasm_error_set(YASM_ERROR_VALUE, N_("non-string section attribute"));
- return -1;
- }
-
- /* For GAS, default to read/write data */
- if (data->isdefault)
- data->flags = COFF_STYP_TEXT | COFF_STYP_READ | COFF_STYP_WRITE;
-
- for (i=0; i<strlen(s); i++) {
- switch (s[i]) {
- case 'a':
- break;
- case 'b':
- alloc = 1;
- load = 0;
- break;
- case 'n':
- load = 0;
- break;
- case 's':
- shared = 1;
- /*@fallthrough@*/
- case 'd':
- datasect = 1;
- load = 1;
- readonly = 0;
- break;
- case 'x':
- code = 1;
- load = 1;
- break;
- case 'r':
- datasect = 1;
- load = 1;
- readonly = 1;
- break;
- case 'w':
- readonly = 0;
- break;
- default:
- yasm_warn_set(YASM_WARN_GENERAL,
- N_("unrecognized section attribute: `%c'"),
- s[i]);
- }
- }
-
- if (code)
- data->flags = COFF_STYP_TEXT | COFF_STYP_EXECUTE | COFF_STYP_READ;
- else if (datasect)
- data->flags = COFF_STYP_DATA | COFF_STYP_READ | COFF_STYP_WRITE;
- else if (readonly)
- data->flags = COFF_STYP_DATA | COFF_STYP_READ;
- else if (load)
- data->flags = COFF_STYP_TEXT;
- else if (alloc)
- data->flags = COFF_STYP_BSS;
-
- if (shared)
- data->flags |= COFF_STYP_SHARED;
-
- data->gasflags = 1;
- return 0;
-}
-
-static /*@observer@*/ /*@null@*/ yasm_section *
-coff_objfmt_section_switch(yasm_object *object, yasm_valparamhead *valparams,
- /*@unused@*/ /*@null@*/
- yasm_valparamhead *objext_valparams,
- unsigned long line)
-{
- yasm_objfmt_coff *objfmt_coff = (yasm_objfmt_coff *)object->objfmt;
- yasm_valparam *vp;
- yasm_section *retval;
- int isnew;
- int iscode = 0;
- int flags_override;
- const char *sectname;
- char *realname;
- int resonly = 0;
- unsigned long align = 0;
- coff_section_data *csd;
-
- struct coff_section_switch_data data;
-
- static const yasm_dir_help help[] = {
- { "code", 0, yasm_dir_helper_flag_set,
- offsetof(struct coff_section_switch_data, flags),
- COFF_STYP_TEXT | COFF_STYP_EXECUTE | COFF_STYP_READ },
- { "text", 0, yasm_dir_helper_flag_set,
- offsetof(struct coff_section_switch_data, flags),
- COFF_STYP_TEXT | COFF_STYP_EXECUTE | COFF_STYP_READ },
- { "data", 0, yasm_dir_helper_flag_set,
- offsetof(struct coff_section_switch_data, flags),
- COFF_STYP_DATA | COFF_STYP_READ | COFF_STYP_WRITE },
- { "rdata", 0, yasm_dir_helper_flag_set,
- offsetof(struct coff_section_switch_data, flags),
- COFF_STYP_DATA | COFF_STYP_READ },
- { "bss", 0, yasm_dir_helper_flag_set,
- offsetof(struct coff_section_switch_data, flags),
- COFF_STYP_BSS | COFF_STYP_READ | COFF_STYP_WRITE },
- { "info", 0, yasm_dir_helper_flag_set,
- offsetof(struct coff_section_switch_data, flags),
- COFF_STYP_INFO | COFF_STYP_DISCARD | COFF_STYP_READ },
- { "gasflags", 1, coff_helper_gasflags, 0, 0 },
- /* Win32 only below this point */
- { "discard", 0, yasm_dir_helper_flag_or,
- offsetof(struct coff_section_switch_data, flags), COFF_STYP_DISCARD},
- { "nodiscard", 0, yasm_dir_helper_flag_and,
- offsetof(struct coff_section_switch_data, flags), COFF_STYP_DISCARD},
- { "cache", 0, yasm_dir_helper_flag_and,
- offsetof(struct coff_section_switch_data, flags), COFF_STYP_NOCACHE},
- { "nocache", 0, yasm_dir_helper_flag_or,
- offsetof(struct coff_section_switch_data, flags), COFF_STYP_NOCACHE},
- { "page", 0, yasm_dir_helper_flag_and,
- offsetof(struct coff_section_switch_data, flags), COFF_STYP_NOPAGE },
- { "nopage", 0, yasm_dir_helper_flag_or,
- offsetof(struct coff_section_switch_data, flags), COFF_STYP_NOPAGE },
- { "share", 0, yasm_dir_helper_flag_or,
- offsetof(struct coff_section_switch_data, flags), COFF_STYP_SHARED },
- { "noshare", 0, yasm_dir_helper_flag_and,
- offsetof(struct coff_section_switch_data, flags), COFF_STYP_SHARED },
- { "execute", 0, yasm_dir_helper_flag_or,
- offsetof(struct coff_section_switch_data, flags), COFF_STYP_EXECUTE},
- { "noexecute", 0, yasm_dir_helper_flag_and,
- offsetof(struct coff_section_switch_data, flags), COFF_STYP_EXECUTE},
- { "read", 0, yasm_dir_helper_flag_or,
- offsetof(struct coff_section_switch_data, flags), COFF_STYP_READ },
- { "noread", 0, yasm_dir_helper_flag_and,
- offsetof(struct coff_section_switch_data, flags), COFF_STYP_READ },
- { "write", 0, yasm_dir_helper_flag_or,
- offsetof(struct coff_section_switch_data, flags), COFF_STYP_WRITE },
- { "nowrite", 0, yasm_dir_helper_flag_and,
- offsetof(struct coff_section_switch_data, flags), COFF_STYP_WRITE },
- { "base", 0, yasm_dir_helper_flag_and,
- offsetof(struct coff_section_switch_data, flags2), COFF_FLAG_NOBASE},
- { "nobase", 0, yasm_dir_helper_flag_or,
- offsetof(struct coff_section_switch_data, flags2), COFF_FLAG_NOBASE},
- { "align", 1, yasm_dir_helper_intn,
- offsetof(struct coff_section_switch_data, align_intn), 0 }
- };
-
- vp = yasm_vps_first(valparams);
- sectname = yasm_vp_string(vp);
- if (!sectname)
- return NULL;
- vp = yasm_vps_next(vp);
-
- data.isdefault = 0;
- data.gasflags = 0;
- data.flags = 0;
- data.flags2 = 0;
- data.align_intn = NULL;
-
- if (strcmp(sectname, ".data") == 0) {
- data.flags = COFF_STYP_DATA | COFF_STYP_READ | COFF_STYP_WRITE;
- if (objfmt_coff->win32) {
- if (objfmt_coff->machine == COFF_MACHINE_AMD64)
- align = 16;
- else
- align = 4;
- }
- } else if (strcmp(sectname, ".bss") == 0) {
- data.flags = COFF_STYP_BSS | COFF_STYP_READ | COFF_STYP_WRITE;
- if (objfmt_coff->win32) {
- if (objfmt_coff->machine == COFF_MACHINE_AMD64)
- align = 16;
- else
- align = 4;
- }
- resonly = 1;
- } else if (strcmp(sectname, ".text") == 0) {
- data.flags = COFF_STYP_TEXT | COFF_STYP_EXECUTE | COFF_STYP_READ;
- if (objfmt_coff->win32)
- align = 16;
- } else if (strcmp(sectname, ".rdata") == 0
- || strncmp(sectname, ".rodata", 7) == 0
- || strncmp(sectname, ".rdata$", 7) == 0) {
- data.flags = COFF_STYP_DATA | COFF_STYP_READ;
- if (objfmt_coff->win32)
- align = 8;
- else
- yasm_warn_set(YASM_WARN_GENERAL,
- N_("Standard COFF does not support read-only data sections"));
- } else if (strcmp(sectname, ".drectve") == 0) {
- data.flags = COFF_STYP_INFO;
- if (objfmt_coff->win32)
- data.flags |= COFF_STYP_DISCARD | COFF_STYP_READ;
- } else if (objfmt_coff->win64 && strcmp(sectname, ".pdata") == 0) {
- data.flags = COFF_STYP_DATA | COFF_STYP_READ;
- align = 4;
- data.flags2 = COFF_FLAG_NOBASE;
- } else if (objfmt_coff->win64 && strcmp(sectname, ".xdata") == 0) {
- data.flags = COFF_STYP_DATA | COFF_STYP_READ;
- align = 8;
- data.flags2 = COFF_FLAG_NOBASE;
- } else if (objfmt_coff->win32 && strcmp(sectname, ".sxdata") == 0) {
- data.flags = COFF_STYP_INFO;
- } else if (strcmp(sectname, ".comment") == 0) {
- data.flags = COFF_STYP_INFO | COFF_STYP_DISCARD | COFF_STYP_READ;
- } else if (yasm__strncasecmp(sectname, ".debug", 6)==0) {
- data.flags = COFF_STYP_DATA | COFF_STYP_DISCARD | COFF_STYP_READ;
- align = 1;
- } else {
- /* Default to code, but set a flag so if we get gasflags we can
- * change it (NASM and GAS have different defaults).
- */
- data.isdefault = 1;
- data.flags = COFF_STYP_TEXT | COFF_STYP_EXECUTE | COFF_STYP_READ;
- }
-
- flags_override = yasm_dir_helper(object, vp, line, help,
- objfmt_coff->win32 ? NELEMS(help) : 7,
- &data, yasm_dir_helper_valparam_warn);
- if (flags_override < 0)
- return NULL; /* error occurred */
-
- if (data.flags & COFF_STYP_EXECUTE)
- iscode = 1;
-
- if (!objfmt_coff->win32)
- data.flags &= ~COFF_STYP_WIN32_MASK;
-
- if (data.align_intn) {
- align = yasm_intnum_get_uint(data.align_intn);
- yasm_intnum_destroy(data.align_intn);
-
- /* Alignments must be a power of two. */
- if (!is_exp2(align)) {
- yasm_error_set(YASM_ERROR_VALUE,
- N_("argument to `%s' is not a power of two"),
- "align");
- return NULL;
- }
-
- /* Check to see if alignment is supported size */
- if (align > 8192) {
- yasm_error_set(YASM_ERROR_VALUE,
- N_("Win32 does not support alignments > 8192"));
- return NULL;
- }
- }
-
- realname = yasm__xstrdup(sectname);
- if (strlen(sectname) > 8 && !objfmt_coff->win32) {
- /* win32 format supports >8 character section names in object
- * files via "/nnnn" (where nnnn is decimal offset into string table),
- * so only warn for regular COFF.
- */
- yasm_warn_set(YASM_WARN_GENERAL,
- N_("COFF section names limited to 8 characters: truncating"));
- realname[8] = '\0';
- }
-
- retval = yasm_object_get_general(object, realname, align, iscode,
- resonly, &isnew, line);
- yasm_xfree(realname);
-
- csd = yasm_section_get_data(retval, &coff_section_data_cb);
-
- if (isnew || yasm_section_is_default(retval)) {
- yasm_section_set_default(retval, 0);
- csd->flags = data.flags;
- csd->flags2 = data.flags2;
- yasm_section_set_align(retval, align, line);
- } else if (flags_override && !data.gasflags)
- yasm_warn_set(YASM_WARN_GENERAL,
- N_("section flags ignored on section redeclaration"));
- return retval;
-}
-
-static /*@observer@*/ /*@null@*/ yasm_symrec *
-coff_objfmt_get_special_sym(yasm_object *object, const char *name,
- const char *parser)
-{
- return NULL;
-}
-
-static /*@observer@*/ /*@null@*/ yasm_symrec *
-win64_objfmt_get_special_sym(yasm_object *object, const char *name,
- const char *parser)
-{
- if (yasm__strcasecmp(name, "imagebase") == 0) {
- yasm_objfmt_coff *objfmt_coff = (yasm_objfmt_coff *)object->objfmt;
- return objfmt_coff->ssym_imagebase;
- }
- return NULL;
-}
-
-static void
-coff_section_data_destroy(void *data)
-{
- yasm_xfree(data);
-}
-
-static void
-coff_section_data_print(void *data, FILE *f, int indent_level)
-{
- coff_section_data *csd = (coff_section_data *)data;
-
- fprintf(f, "%*ssym=\n", indent_level, "");
- yasm_symrec_print(csd->sym, f, indent_level+1);
- fprintf(f, "%*sscnum=%d\n", indent_level, "", csd->scnum);
- fprintf(f, "%*sflags=", indent_level, "");
- switch (csd->flags & COFF_STYP_STD_MASK) {
- case COFF_STYP_TEXT:
- fprintf(f, "TEXT");
- break;
- case COFF_STYP_DATA:
- fprintf(f, "DATA");
- break;
- case COFF_STYP_BSS:
- fprintf(f, "BSS");
- break;
- default:
- fprintf(f, "UNKNOWN");
- break;
- }
- fprintf(f, "\n%*saddr=0x%lx\n", indent_level, "", csd->addr);
- fprintf(f, "%*sscnptr=0x%lx\n", indent_level, "", csd->scnptr);
- fprintf(f, "%*ssize=%ld\n", indent_level, "", csd->size);
- fprintf(f, "%*srelptr=0x%lx\n", indent_level, "", csd->relptr);
- fprintf(f, "%*snreloc=%ld\n", indent_level, "", csd->nreloc);
- fprintf(f, "%*srelocs:\n", indent_level, "");
-}
-
-static void
-coff_symrec_data_destroy(void *data)
-{
- yasm_xfree(data);
-}
-
-static void
-coff_symrec_data_print(void *data, FILE *f, int indent_level)
-{
- coff_symrec_data *csd = (coff_symrec_data *)data;
-
- fprintf(f, "%*ssymtab index=%lu\n", indent_level, "", csd->index);
- fprintf(f, "%*ssclass=%d\n", indent_level, "", csd->sclass);
-}
-
-static void
-dir_export(yasm_object *object, yasm_valparamhead *valparams,
- yasm_valparamhead *objext_valparams, unsigned long line)
-{
- yasm_valparam *vp;
- /*@null@*/ const char *symname;
- int isnew;
- yasm_section *sect;
- yasm_datavalhead dvs;
-
- /* Reference exported symbol (to generate error if not declared) */
- vp = yasm_vps_first(valparams);
- symname = yasm_vp_id(vp);
- if (symname)
- yasm_symtab_use(object->symtab, symname, line);
- else {
- yasm_error_set(YASM_ERROR_SYNTAX,
- N_("argument to EXPORT must be symbol name"));
- return;
- }
-
- /* Add to end of linker directives */
- sect = yasm_object_get_general(object, ".drectve", 0, 0, 0, &isnew, line);
-
- /* Initialize directive section if needed */
- if (isnew) {
- coff_section_data *csd;
- csd = yasm_section_get_data(sect, &coff_section_data_cb);
- csd->flags = COFF_STYP_INFO | COFF_STYP_DISCARD | COFF_STYP_READ;
- }
-
- /* Add text as data bytecode */
- yasm_dvs_initialize(&dvs);
- yasm_dvs_append(&dvs, yasm_dv_create_string(yasm__xstrdup("-export:"),
- strlen("-export:")));
- yasm_dvs_append(&dvs, yasm_dv_create_string(yasm__xstrdup(symname),
- strlen(symname)));
- yasm_dvs_append(&dvs, yasm_dv_create_string(yasm__xstrdup(" "), 1));
- yasm_section_bcs_append(sect, yasm_bc_create_data(&dvs, 1, 0, NULL, line));
-}
-
-static void
-dir_safeseh(yasm_object *object, yasm_valparamhead *valparams,
- yasm_valparamhead *objext_valparams, unsigned long line)
-{
- yasm_valparam *vp;
- /*@null@*/ const char *symname;
- yasm_symrec *sym;
- int isnew;
- yasm_section *sect;
-
- /* Reference symbol (to generate error if not declared).
- * Also, symbol must be externally visible, so force it.
- */
- vp = yasm_vps_first(valparams);
- symname = yasm_vp_id(vp);
- if (symname) {
- coff_symrec_data *sym_data;
- sym = yasm_symtab_use(object->symtab, symname, line);
- sym_data = yasm_symrec_get_data(sym, &coff_symrec_data_cb);
- if (!sym_data) {
- sym_data = coff_objfmt_sym_set_data(sym, COFF_SCL_NULL, 0,
- COFF_SYMTAB_AUX_NONE);
- }
- sym_data->forcevis = 1;
- sym_data->type = 0x20; /* function */
- } else {
- yasm_error_set(YASM_ERROR_SYNTAX,
- N_("argument to SAFESEH must be symbol name"));
- return;
- }
-
- /*
- * Add symbol number to end of .sxdata section.
- */
-
- sect = yasm_object_get_general(object, ".sxdata", 0, 0, 0, &isnew, line);
-
- /* Initialize sxdata section if needed */
- if (isnew) {
- coff_section_data *csd;
- csd = yasm_section_get_data(sect, &coff_section_data_cb);
- csd->flags = COFF_STYP_INFO;
- }
-
- /* Add as sxdata bytecode */
- yasm_section_bcs_append(sect,
- yasm_bc_create_common(&win32_sxdata_bc_callback,
- sym, line));
-}
-
-static void
-win32_sxdata_bc_destroy(void *contents)
-{
- /* Contents is just the symbol pointer, so no need to delete */
-}
-
-static void
-win32_sxdata_bc_print(const void *contents, FILE *f, int indent_level)
-{
- /* TODO */
-}
-
-static int
-win32_sxdata_bc_calc_len(yasm_bytecode *bc, yasm_bc_add_span_func add_span,
- void *add_span_data)
-{
- bc->len += 4;
- return 0;
-}
-
-static int
-win32_sxdata_bc_tobytes(yasm_bytecode *bc, unsigned char **bufp,
- unsigned char *bufstart, void *d,
- yasm_output_value_func output_value,
- yasm_output_reloc_func output_reloc)
-{
- yasm_symrec *sym = (yasm_symrec *)bc->contents;
- unsigned char *buf = *bufp;
- coff_symrec_data *csymd;
-
- csymd = yasm_symrec_get_data(sym, &coff_symrec_data_cb);
- if (!csymd)
- yasm_internal_error(N_("coff: no symbol data for SAFESEH symbol"));
-
- YASM_WRITE_32_L(buf, csymd->index);
-
- *bufp = buf;
- return 0;
-}
-
-static void
-dir_ident(yasm_object *object, yasm_valparamhead *valparams,
- yasm_valparamhead *objext_valparams, unsigned long line)
-{
- yasm_objfmt_coff *objfmt_coff = (yasm_objfmt_coff *)object->objfmt;
- yasm_valparamhead sect_vps;
- yasm_datavalhead dvs;
- yasm_section *comment;
- const char *sectname;
- yasm_valparam *vp, *vp2;
-
- /* Accept, but do nothing with empty ident */
- if (!valparams)
- return;
-
- vp = yasm_vps_first(valparams);
- if (!vp)
- return;
-
- if (objfmt_coff->win32) {
- /* Put ident data into .comment section for COFF, or .rdata$zzz
- * to be compatible with the GNU linker, which doesn't ignore
- * .comment (see binutils/gas/config/obj-coff.c:476-502).
- */
- sectname = ".rdata$zzz";
- } else {
- sectname = ".comment";
- }
- yasm_vps_initialize(&sect_vps);
- vp2 = yasm_vp_create_id(NULL, yasm__xstrdup(sectname), '\0');
- yasm_vps_append(&sect_vps, vp2);
- comment = coff_objfmt_section_switch(object, &sect_vps, NULL, line);
- yasm_vps_delete(&sect_vps);
-
- /* To match GAS output, if the comment section is empty, put an
- * initial 0 byte in the section.
- */
- if (yasm_section_bcs_first(comment) == yasm_section_bcs_last(comment)) {
- yasm_dvs_initialize(&dvs);
- yasm_dvs_append(&dvs, yasm_dv_create_expr(
- yasm_expr_create_ident(yasm_expr_int(yasm_intnum_create_uint(0)),
- line)));
- yasm_section_bcs_append(comment,
- yasm_bc_create_data(&dvs, 1, 0, object->arch, line));
- }
-
- yasm_dvs_initialize(&dvs);
- do {
- const char *s = yasm_vp_string(vp);
- if (!s) {
- yasm_error_set(YASM_ERROR_VALUE,
- N_(".comment requires string parameters"));
- yasm_dvs_delete(&dvs);
- return;
- }
- yasm_dvs_append(&dvs,
- yasm_dv_create_string(yasm__xstrdup(s), strlen(s)));
- } while ((vp = yasm_vps_next(vp)));
-
- yasm_section_bcs_append(comment,
- yasm_bc_create_data(&dvs, 1, 1, object->arch, line));
-}
-
-static void
-dir_secrel32(yasm_object *object, yasm_valparamhead *valparams,
- yasm_valparamhead *objext_valparams, unsigned long line)
-{
- yasm_datavalhead dvs;
- yasm_valparam *vp;
-
- if (!object->cur_section) {
- yasm_error_set(YASM_ERROR_SYNTAX,
- N_(".secrel32 can only be used inside of a section"));
- return;
- }
-
- vp = yasm_vps_first(valparams);
- yasm_dvs_initialize(&dvs);
- do {
- yasm_expr *e = yasm_vp_expr(vp, object->symtab, line);
- yasm_dataval *dv;
- if (!e) {
- yasm_error_set(YASM_ERROR_VALUE,
- N_(".secrel32 requires expressions"));
- yasm_dvs_delete(&dvs);
- return;
- }
- dv = yasm_dv_create_expr(e);
- yasm_dv_get_value(dv)->section_rel = 1;
- yasm_dvs_append(&dvs, dv);
- } while ((vp = yasm_vps_next(vp)));
-
- yasm_section_bcs_append(object->cur_section,
- yasm_bc_create_data(&dvs, 4, 0, object->arch, line));
-}
-
-static void
-dir_def(yasm_object *object, yasm_valparamhead *valparams,
- yasm_valparamhead *objext_valparams, unsigned long line)
-{
- yasm_objfmt_coff *objfmt_coff = (yasm_objfmt_coff *)object->objfmt;
- yasm_valparam *vp;
- const char *symname;
- yasm_symrec *sym;
- coff_symrec_data *sym_data;
-
- if (objfmt_coff->def_sym) {
- yasm_warn_set(YASM_WARN_GENERAL,
- N_(".def pseudo-op used inside of .def/.endef; ignored"));
- return;
- }
-
- vp = yasm_vps_first(valparams);
- symname = yasm_vp_id(vp);
- if (!symname) {
- yasm_error_set(YASM_ERROR_SYNTAX,
- N_("argument to SAFESEH must be symbol name"));
- return;
- }
-
- sym = yasm_symtab_use(object->symtab, symname, line);
- sym_data = yasm_symrec_get_data(sym, &coff_symrec_data_cb);
- if (!sym_data) {
- sym_data = coff_objfmt_sym_set_data(sym, COFF_SCL_NULL, 0,
- COFF_SYMTAB_AUX_NONE);
- }
- objfmt_coff->def_sym = sym_data;
-}
-
-static void
-dir_scl(yasm_object *object, yasm_valparamhead *valparams,
- yasm_valparamhead *objext_valparams, unsigned long line)
-{
- yasm_objfmt_coff *objfmt_coff = (yasm_objfmt_coff *)object->objfmt;
- yasm_intnum *intn = NULL;
-
- if (!objfmt_coff->def_sym) {
- yasm_warn_set(YASM_WARN_GENERAL,
- N_("%s pseudo-op used outside of .def/.endef; ignored"),
- ".scl");
- return;
- }
-
- if (yasm_dir_helper_intn(object, yasm_vps_first(valparams), line,
- &intn, 0) < 0)
- return;
- if (!intn)
- return;
- objfmt_coff->def_sym->sclass = yasm_intnum_get_uint(intn);
- yasm_intnum_destroy(intn);
-}
-
-static void
-dir_type(yasm_object *object, yasm_valparamhead *valparams,
- yasm_valparamhead *objext_valparams, unsigned long line)
-{
- yasm_objfmt_coff *objfmt_coff = (yasm_objfmt_coff *)object->objfmt;
- yasm_intnum *intn = NULL;
-
- if (!objfmt_coff->def_sym) {
- yasm_warn_set(YASM_WARN_GENERAL,
- N_("%s pseudo-op used outside of .def/.endef; ignored"),
- ".type");
- return;
- }
-
- if (yasm_dir_helper_intn(object, yasm_vps_first(valparams), line,
- &intn, 0) < 0)
- return;
- if (!intn)
- return;
- objfmt_coff->def_sym->type = yasm_intnum_get_uint(intn);
- yasm_intnum_destroy(intn);
-}
-
-static void
-dir_endef(yasm_object *object, yasm_valparamhead *valparams,
- yasm_valparamhead *objext_valparams, unsigned long line)
-{
- yasm_objfmt_coff *objfmt_coff = (yasm_objfmt_coff *)object->objfmt;
- if (!objfmt_coff->def_sym) {
- yasm_warn_set(YASM_WARN_GENERAL,
- N_(".endef pseudo-op used before .def; ignored"));
- return;
- }
- objfmt_coff->def_sym = NULL;
-}
-
-static void
-dir_proc_frame(yasm_object *object, /*@null@*/ yasm_valparamhead *valparams,
- yasm_valparamhead *objext_valparams, unsigned long line)
-{
- yasm_objfmt_coff *objfmt_coff = (yasm_objfmt_coff *)object->objfmt;
- yasm_valparam *vp = yasm_vps_first(valparams);
- const char *name = yasm_vp_id(vp);
-
- 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;
- }
- objfmt_coff->proc_frame = line;
- objfmt_coff->done_prolog = 0;
- objfmt_coff->unwind = yasm_win64__uwinfo_create();
- objfmt_coff->unwind->proc = yasm_symtab_use(object->symtab, name, line);
-
- /* Optional error handler */
- vp = yasm_vps_next(vp);
- if (!vp || !(name = yasm_vp_id(vp)))
- return;
- objfmt_coff->unwind->ehandler =
- yasm_symtab_use(object->symtab, name, 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_object *object, const char *dirname, unsigned long line)
-{
- if (!object->cur_section) {
- yasm_error_set(YASM_ERROR_SYNTAX,
- N_("[%s] can only be used inside of a section"),
- dirname);
- return NULL;
- }
- return yasm_symtab_define_curpos(object->symtab, "$",
- yasm_section_bcs_last(object->cur_section), line);
-}
-
-static void
-dir_pushreg(yasm_object *object, yasm_valparamhead *valparams,
- yasm_valparamhead *objext_valparams, unsigned long line)
-{
- yasm_objfmt_coff *objfmt_coff = (yasm_objfmt_coff *)object->objfmt;
- yasm_valparam *vp = yasm_vps_first(valparams);
- coff_unwind_code *code;
- const uintptr_t *reg;
-
- if (!procframe_checkstate(objfmt_coff, "PUSHREG"))
- return;
-
- if (vp->type != YASM_PARAM_EXPR ||
- !(reg = yasm_expr_get_reg(&vp->param.e, 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(object, "PUSHREG", 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_object *object, yasm_valparamhead *valparams,
- yasm_valparamhead *objext_valparams, unsigned long line)
-{
- yasm_objfmt_coff *objfmt_coff = (yasm_objfmt_coff *)object->objfmt;
- yasm_valparam *vp = yasm_vps_first(valparams);
- coff_unwind_code *code;
- const uintptr_t *reg;
- yasm_expr *off = NULL;
-
- if (!procframe_checkstate(objfmt_coff, "SETFRAME"))
- return;
-
- if (vp->type != YASM_PARAM_EXPR ||
- !(reg = yasm_expr_get_reg(&vp->param.e, 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)
- off = yasm_vp_expr(vp, object->symtab, line);
-
- /* Set the frame fields in the unwind info */
- objfmt_coff->unwind->framereg = (unsigned long)(*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(object, "SETFRAME", line);
- code->opcode = UWOP_SET_FPREG;
- code->info = (unsigned int)(*reg & 0xF);
- yasm_value_initialize(&code->off, off ? yasm_expr_copy(off) : NULL, 8);
- SLIST_INSERT_HEAD(&objfmt_coff->unwind->codes, code, link);
-}
-
-static void
-dir_allocstack(yasm_object *object, yasm_valparamhead *valparams,
- yasm_valparamhead *objext_valparams, unsigned long line)
-{
- yasm_objfmt_coff *objfmt_coff = (yasm_objfmt_coff *)object->objfmt;
- yasm_valparam *vp = yasm_vps_first(valparams);
- /*@null@*/ /*@only@*/ yasm_expr *size;
- coff_unwind_code *code;
-
- if (!procframe_checkstate(objfmt_coff, "ALLOCSTACK"))
- return;
-
- size = yasm_vp_expr(vp, object->symtab, line);
- if (!size) {
- 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(object, "ALLOCSTACK", line);
- code->opcode = UWOP_ALLOC_SMALL;
- code->info = 0;
- yasm_value_initialize(&code->off, size, 7);
- SLIST_INSERT_HEAD(&objfmt_coff->unwind->codes, code, link);
-}
-
-static void
-dir_save_common(yasm_object *object, yasm_valparamhead *valparams,
- unsigned long line, const char *name, int op)
-{
- yasm_objfmt_coff *objfmt_coff = (yasm_objfmt_coff *)object->objfmt;
- yasm_valparam *vp = yasm_vps_first(valparams);
- coff_unwind_code *code;
- const uintptr_t *reg;
- /*@only@*/ /*@null@*/ yasm_expr *offset;
-
- if (!procframe_checkstate(objfmt_coff, name))
- return;
-
- if (vp->type != YASM_PARAM_EXPR ||
- !(reg = yasm_expr_get_reg(&vp->param.e, 0))) {
- yasm_error_set(YASM_ERROR_SYNTAX,
- N_("[%s] requires a register as the first parameter"),
- name);
- return;
- }
-
- vp = yasm_vps_next(vp);
- offset = yasm_vp_expr(vp, object->symtab, line);
- if (!offset) {
- 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(object, name, line);
- code->opcode = op;
- code->info = (unsigned int)(*reg & 0xF);
- yasm_value_initialize(&code->off, offset, 16);
- SLIST_INSERT_HEAD(&objfmt_coff->unwind->codes, code, link);
-}
-
-static void
-dir_savereg(yasm_object *object, yasm_valparamhead *valparams,
- yasm_valparamhead *objext_valparams, unsigned long line)
-{
- dir_save_common(object, valparams, line, "SAVEREG", UWOP_SAVE_NONVOL);
-}
-
-static void
-dir_savexmm128(yasm_object *object, yasm_valparamhead *valparams,
- yasm_valparamhead *objext_valparams, unsigned long line)
-{
- dir_save_common(object, valparams, line, "SAVEXMM128", UWOP_SAVE_XMM128);
-}
-
-static void
-dir_pushframe(yasm_object *object, /*@null@*/ yasm_valparamhead *valparams,
- yasm_valparamhead *objext_valparams, unsigned long line)
-{
- yasm_objfmt_coff *objfmt_coff = (yasm_objfmt_coff *)object->objfmt;
- 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(object, "PUSHFRAME", line);
- code->opcode = UWOP_PUSH_MACHFRAME;
- code->info = vp != NULL;
- yasm_value_initialize(&code->off, NULL, 0);
- SLIST_INSERT_HEAD(&objfmt_coff->unwind->codes, code, link);
-}
-
-static void
-dir_endprolog(yasm_object *object, /*@null@*/ yasm_valparamhead *valparams,
- yasm_valparamhead *objext_valparams, unsigned long line)
-{
- yasm_objfmt_coff *objfmt_coff = (yasm_objfmt_coff *)object->objfmt;
- if (!procframe_checkstate(objfmt_coff, "ENDPROLOG"))
- return;
- objfmt_coff->done_prolog = line;
-
- objfmt_coff->unwind->prolog = get_curpos(object, "ENDPROLOG", line);
-}
-
-static void
-dir_endproc_frame(yasm_object *object, /*@null@*/ yasm_valparamhead *valparams,
- yasm_valparamhead *objext_valparams, unsigned long line)
-{
- yasm_objfmt_coff *objfmt_coff = (yasm_objfmt_coff *)object->objfmt;
- 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(object, "ENDPROC_FRAME", line);
-
- /*
- * Add unwind info to end of .xdata section.
- */
-
- sect = yasm_object_get_general(object, ".xdata", 0, 0, 0, &isnew, line);
-
- /* Initialize xdata section if needed */
- if (isnew) {
- csd = yasm_section_get_data(sect, &coff_section_data_cb);
- 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(object->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(object, ".pdata", 0, 0, 0, &isnew, line);
-
- /* Initialize pdata section if needed */
- if (isnew) {
- csd = yasm_section_get_data(sect, &coff_section_data_cb);
- 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;
-}
-
-/* Define valid debug formats to use with this object format */
-static const char *coff_objfmt_dbgfmt_keywords[] = {
- "null",
- "dwarf2",
- NULL
-};
-
-static const yasm_directive coff_objfmt_directives[] = {
- { ".ident", "gas", dir_ident, YASM_DIR_ANY },
- { "ident", "nasm", dir_ident, YASM_DIR_ANY },
- { ".def", "gas", dir_def, YASM_DIR_ID_REQUIRED },
- { ".endef", "gas", dir_endef, YASM_DIR_ANY },
- { ".scl", "gas", dir_scl, YASM_DIR_ARG_REQUIRED },
- { ".type", "gas", dir_type, YASM_DIR_ARG_REQUIRED },
- { ".secrel32", "gas", dir_secrel32, YASM_DIR_ARG_REQUIRED },
- { NULL, NULL, NULL, 0 }
-};
-
-/* Define objfmt structure -- see objfmt.h for details */
-yasm_objfmt_module yasm_coff_LTX_objfmt = {
- "COFF (DJGPP)",
- "coff",
- "o",
- 32,
- 0,
- coff_objfmt_dbgfmt_keywords,
- "null",
- coff_objfmt_directives,
- NULL, /* no standard macros */
- coff_objfmt_create,
- coff_objfmt_output,
- coff_objfmt_destroy,
- coff_objfmt_add_default_section,
- coff_objfmt_init_new_section,
- coff_objfmt_section_switch,
- coff_objfmt_get_special_sym
-};
-
-/* Define valid debug formats to use with this object format */
-static const char *winXX_objfmt_dbgfmt_keywords[] = {
- "null",
- "dwarf2",
- "cv8",
- NULL
-};
-
-static const yasm_directive win32_objfmt_directives[] = {
- { ".ident", "gas", dir_ident, YASM_DIR_ANY },
- { "ident", "nasm", dir_ident, YASM_DIR_ANY },
- { ".def", "gas", dir_def, YASM_DIR_ID_REQUIRED },
- { ".endef", "gas", dir_endef, YASM_DIR_ANY },
- { ".scl", "gas", dir_scl, YASM_DIR_ARG_REQUIRED },
- { ".type", "gas", dir_type, YASM_DIR_ARG_REQUIRED },
- { ".secrel32", "gas", dir_secrel32, YASM_DIR_ARG_REQUIRED },
- { ".export", "gas", dir_export, YASM_DIR_ID_REQUIRED },
- { "export", "nasm", dir_export, YASM_DIR_ID_REQUIRED },
- { ".safeseh", "gas", dir_safeseh, YASM_DIR_ID_REQUIRED },
- { "safeseh", "nasm", dir_safeseh, YASM_DIR_ID_REQUIRED },
- { NULL, NULL, NULL, 0 }
-};
-
-static const char *win32_nasm_stdmac[] = {
- "%imacro export 1+.nolist",
- "[export %1]",
- "%endmacro",
- "%imacro safeseh 1+.nolist",
- "[safeseh %1]",
- "%endmacro",
- NULL
-};
-
-static const yasm_stdmac win32_objfmt_stdmacs[] = {
- { "nasm", "nasm", win32_nasm_stdmac },
- { NULL, NULL, NULL }
-};
-
-/* Define objfmt structure -- see objfmt.h for details */
-yasm_objfmt_module yasm_win32_LTX_objfmt = {
- "Win32",
- "win32",
- "obj",
- 32,
- 1,
- winXX_objfmt_dbgfmt_keywords,
- "null",
- win32_objfmt_directives,
- win32_objfmt_stdmacs,
- win32_objfmt_create,
- coff_objfmt_output,
- coff_objfmt_destroy,
- coff_objfmt_add_default_section,
- coff_objfmt_init_new_section,
- coff_objfmt_section_switch,
- coff_objfmt_get_special_sym
-};
-
-static const yasm_directive win64_objfmt_directives[] = {
- { ".ident", "gas", dir_ident, YASM_DIR_ANY },
- { "ident", "nasm", dir_ident, YASM_DIR_ANY },
- { ".def", "gas", dir_def, YASM_DIR_ID_REQUIRED },
- { ".endef", "gas", dir_endef, YASM_DIR_ANY },
- { ".scl", "gas", dir_scl, YASM_DIR_ARG_REQUIRED },
- { ".type", "gas", dir_type, YASM_DIR_ARG_REQUIRED },
- { ".secrel32", "gas", dir_secrel32, YASM_DIR_ARG_REQUIRED },
- { ".export", "gas", dir_export, YASM_DIR_ID_REQUIRED },
- { "export", "nasm", dir_export, YASM_DIR_ID_REQUIRED },
- { ".proc_frame", "gas", dir_proc_frame, YASM_DIR_ID_REQUIRED },
- { "proc_frame", "nasm", dir_proc_frame, YASM_DIR_ID_REQUIRED },
- { ".pushreg", "gas", dir_pushreg, YASM_DIR_ARG_REQUIRED },
- { "pushreg", "nasm", dir_pushreg, YASM_DIR_ARG_REQUIRED },
- { ".setframe", "gas", dir_setframe, YASM_DIR_ARG_REQUIRED },
- { "setframe", "nasm", dir_setframe, YASM_DIR_ARG_REQUIRED },
- { ".allocstack", "gas", dir_allocstack, YASM_DIR_ARG_REQUIRED },
- { "allocstack", "nasm", dir_allocstack, YASM_DIR_ARG_REQUIRED },
- { ".savereg", "gas", dir_savereg, YASM_DIR_ARG_REQUIRED },
- { "savereg", "nasm", dir_savereg, YASM_DIR_ARG_REQUIRED },
- { ".savexmm128", "gas", dir_savexmm128, YASM_DIR_ARG_REQUIRED },
- { "savexmm128", "nasm", dir_savexmm128, YASM_DIR_ARG_REQUIRED },
- { ".pushframe", "gas", dir_pushframe, YASM_DIR_ANY },
- { "pushframe", "nasm", dir_pushframe, YASM_DIR_ANY },
- { ".endprolog", "gas", dir_endprolog, YASM_DIR_ANY },
- { "endprolog", "nasm", dir_endprolog, YASM_DIR_ANY },
- { ".endproc_frame", "gas", dir_endproc_frame, YASM_DIR_ANY },
- { "endproc_frame", "nasm", dir_endproc_frame, YASM_DIR_ANY },
- { NULL, NULL, NULL, 0 }
-};
-
-#include "win64-nasm.c"
-#include "win64-gas.c"
-
-static const yasm_stdmac win64_objfmt_stdmacs[] = {
- { "nasm", "nasm", win64_nasm_stdmac },
- { "gas", "nasm", win64_gas_stdmac },
- { NULL, NULL, NULL }
-};
-
-/* Define objfmt structure -- see objfmt.h for details */
-yasm_objfmt_module yasm_win64_LTX_objfmt = {
- "Win64",
- "win64",
- "obj",
- 64,
- 1,
- winXX_objfmt_dbgfmt_keywords,
- "null",
- win64_objfmt_directives,
- win64_objfmt_stdmacs,
- win64_objfmt_create,
- coff_objfmt_output,
- coff_objfmt_destroy,
- coff_objfmt_add_default_section,
- coff_objfmt_init_new_section,
- coff_objfmt_section_switch,
- win64_objfmt_get_special_sym
-};
-yasm_objfmt_module yasm_x64_LTX_objfmt = {
- "Win64",
- "x64",
- "obj",
- 64,
- 1,
- winXX_objfmt_dbgfmt_keywords,
- "null",
- win64_objfmt_directives,
- win64_objfmt_stdmacs,
- win64_objfmt_create,
- coff_objfmt_output,
- coff_objfmt_destroy,
- coff_objfmt_add_default_section,
- coff_objfmt_init_new_section,
- coff_objfmt_section_switch,
- win64_objfmt_get_special_sym
-};
+
+ /* Force all syms for win64 because they're needed for relocations.
+ * FIXME: Not *all* syms need to be output, only the ones needed for
+ * relocation. Find a way to do that someday.
+ */
+ all_syms |= objfmt_coff->win64;
+
+ info.strtab_offset = 4;
+ info.object = object;
+ info.objfmt_coff = objfmt_coff;
+ info.errwarns = errwarns;
+ info.f = f;
+ info.buf = yasm_xmalloc(REGULAR_OUTBUF_SIZE);
+
+ /* Allocate space for headers by seeking forward */
+ if (fseek(f, (long)(20+40*(objfmt_coff->parse_scnum-1)), SEEK_SET) < 0) {
+ yasm__fatal(N_("could not seek on output file"));
+ /*@notreached@*/
+ return;
+ }
+
+ /* Finalize symbol table (assign index to each symbol) */
+ info.indx = 0;
+ info.all_syms = all_syms;
+ yasm_symtab_traverse(object->symtab, &info, coff_objfmt_count_sym);
+ symtab_count = info.indx;
+
+ /* Section data/relocs */
+ if (COFF_SET_VMA) {
+ /* If we're setting the VMA, we need to do a first section pass to
+ * determine each section's addr value before actually outputting
+ * relocations, as a relocation's section address is added into the
+ * addends in the generated code.
+ */
+ info.addr = 0;
+ if (yasm_object_sections_traverse(object, &info,
+ coff_objfmt_set_section_addr))
+ return;
+ }
+ info.addr = 0;
+ if (yasm_object_sections_traverse(object, &info,
+ coff_objfmt_output_section))
+ return;
+
+ /* Symbol table */
+ pos = ftell(f);
+ if (pos == -1) {
+ yasm__fatal(N_("could not get file position on output file"));
+ /*@notreached@*/
+ return;
+ }
+ symtab_pos = (unsigned long)pos;
+ yasm_symtab_traverse(object->symtab, &info, coff_objfmt_output_sym);
+
+ /* String table */
+ yasm_fwrite_32_l(info.strtab_offset, f); /* total length */
+ yasm_object_sections_traverse(object, &info, coff_objfmt_output_sectstr);
+ yasm_symtab_traverse(object->symtab, &info, coff_objfmt_output_str);
+
+ /* Write headers */
+ if (fseek(f, 0, SEEK_SET) < 0) {
+ yasm__fatal(N_("could not seek on output file"));
+ /*@notreached@*/
+ return;
+ }
+
+ localbuf = info.buf;
+ YASM_WRITE_16_L(localbuf, objfmt_coff->machine); /* magic number */
+ YASM_WRITE_16_L(localbuf, objfmt_coff->parse_scnum-1);/* number of sects */
+ if (getenv("YASM_TEST_SUITE"))
+ ts = 0;
+ else
+ ts = (unsigned long)time(NULL);
+ YASM_WRITE_32_L(localbuf, ts); /* time/date stamp */
+ YASM_WRITE_32_L(localbuf, symtab_pos); /* file ptr to symtab */
+ YASM_WRITE_32_L(localbuf, symtab_count); /* number of symtabs */
+ YASM_WRITE_16_L(localbuf, 0); /* size of optional header (none) */
+ /* flags */
+ flags = 0;
+ if (strcmp(yasm_dbgfmt_keyword(object->dbgfmt), "null")==0)
+ flags = COFF_F_LNNO;
+ if (!all_syms)
+ flags |= COFF_F_LSYMS;
+ if (objfmt_coff->machine != COFF_MACHINE_AMD64)
+ flags |= COFF_F_AR32WR;
+ YASM_WRITE_16_L(localbuf, flags);
+ fwrite(info.buf, 20, 1, f);
+
+ yasm_object_sections_traverse(object, &info, coff_objfmt_output_secthead);
+
+ yasm_xfree(info.buf);
+}
+
+static void
+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);
+}
+
+static yasm_section *
+coff_objfmt_add_default_section(yasm_object *object)
+{
+ yasm_objfmt_coff *objfmt_coff = (yasm_objfmt_coff *)object->objfmt;
+ yasm_section *retval;
+ coff_section_data *csd;
+ int isnew;
+
+ retval = yasm_object_get_general(object, ".text", 16, 1, 0, &isnew, 0);
+ if (isnew) {
+ csd = yasm_section_get_data(retval, &coff_section_data_cb);
+ csd->flags = COFF_STYP_TEXT;
+ if (objfmt_coff->win32)
+ csd->flags |= COFF_STYP_EXECUTE | COFF_STYP_READ;
+ yasm_section_set_default(retval, 1);
+ }
+ return retval;
+}
+
+struct coff_section_switch_data {
+ int isdefault;
+ int gasflags;
+ unsigned long flags;
+ unsigned long flags2;
+ /*@only@*/ /*@null@*/ yasm_intnum *align_intn;
+};
+
+/* GAS-style flags */
+static int
+coff_helper_gasflags(void *obj, yasm_valparam *vp, unsigned long line, void *d,
+ /*@unused@*/ uintptr_t arg)
+{
+ struct coff_section_switch_data *data =
+ (struct coff_section_switch_data *)d;
+ int alloc = 0, load = 0, readonly = 0, code = 0, datasect = 0;
+ int shared = 0;
+ const char *s = yasm_vp_string(vp);
+ size_t i;
+
+ if (!s) {
+ yasm_error_set(YASM_ERROR_VALUE, N_("non-string section attribute"));
+ return -1;
+ }
+
+ /* For GAS, default to read/write data */
+ if (data->isdefault)
+ data->flags = COFF_STYP_TEXT | COFF_STYP_READ | COFF_STYP_WRITE;
+
+ for (i=0; i<strlen(s); i++) {
+ switch (s[i]) {
+ case 'a':
+ break;
+ case 'b':
+ alloc = 1;
+ load = 0;
+ break;
+ case 'n':
+ load = 0;
+ break;
+ case 's':
+ shared = 1;
+ /*@fallthrough@*/
+ case 'd':
+ datasect = 1;
+ load = 1;
+ readonly = 0;
+ break;
+ case 'x':
+ code = 1;
+ load = 1;
+ break;
+ case 'r':
+ datasect = 1;
+ load = 1;
+ readonly = 1;
+ break;
+ case 'w':
+ readonly = 0;
+ break;
+ default:
+ yasm_warn_set(YASM_WARN_GENERAL,
+ N_("unrecognized section attribute: `%c'"),
+ s[i]);
+ }
+ }
+
+ if (code)
+ data->flags = COFF_STYP_TEXT | COFF_STYP_EXECUTE | COFF_STYP_READ;
+ else if (datasect)
+ data->flags = COFF_STYP_DATA | COFF_STYP_READ | COFF_STYP_WRITE;
+ else if (readonly)
+ data->flags = COFF_STYP_DATA | COFF_STYP_READ;
+ else if (load)
+ data->flags = COFF_STYP_TEXT;
+ else if (alloc)
+ data->flags = COFF_STYP_BSS;
+
+ if (shared)
+ data->flags |= COFF_STYP_SHARED;
+
+ data->gasflags = 1;
+ return 0;
+}
+
+static /*@observer@*/ /*@null@*/ yasm_section *
+coff_objfmt_section_switch(yasm_object *object, yasm_valparamhead *valparams,
+ /*@unused@*/ /*@null@*/
+ yasm_valparamhead *objext_valparams,
+ unsigned long line)
+{
+ yasm_objfmt_coff *objfmt_coff = (yasm_objfmt_coff *)object->objfmt;
+ yasm_valparam *vp;
+ yasm_section *retval;
+ int isnew;
+ int iscode = 0;
+ int flags_override;
+ const char *sectname;
+ char *realname;
+ int resonly = 0;
+ unsigned long align = 0;
+ coff_section_data *csd;
+
+ struct coff_section_switch_data data;
+
+ static const yasm_dir_help help[] = {
+ { "code", 0, yasm_dir_helper_flag_set,
+ offsetof(struct coff_section_switch_data, flags),
+ COFF_STYP_TEXT | COFF_STYP_EXECUTE | COFF_STYP_READ },
+ { "text", 0, yasm_dir_helper_flag_set,
+ offsetof(struct coff_section_switch_data, flags),
+ COFF_STYP_TEXT | COFF_STYP_EXECUTE | COFF_STYP_READ },
+ { "data", 0, yasm_dir_helper_flag_set,
+ offsetof(struct coff_section_switch_data, flags),
+ COFF_STYP_DATA | COFF_STYP_READ | COFF_STYP_WRITE },
+ { "rdata", 0, yasm_dir_helper_flag_set,
+ offsetof(struct coff_section_switch_data, flags),
+ COFF_STYP_DATA | COFF_STYP_READ },
+ { "bss", 0, yasm_dir_helper_flag_set,
+ offsetof(struct coff_section_switch_data, flags),
+ COFF_STYP_BSS | COFF_STYP_READ | COFF_STYP_WRITE },
+ { "info", 0, yasm_dir_helper_flag_set,
+ offsetof(struct coff_section_switch_data, flags),
+ COFF_STYP_INFO | COFF_STYP_DISCARD | COFF_STYP_READ },
+ { "gasflags", 1, coff_helper_gasflags, 0, 0 },
+ /* Win32 only below this point */
+ { "discard", 0, yasm_dir_helper_flag_or,
+ offsetof(struct coff_section_switch_data, flags), COFF_STYP_DISCARD},
+ { "nodiscard", 0, yasm_dir_helper_flag_and,
+ offsetof(struct coff_section_switch_data, flags), COFF_STYP_DISCARD},
+ { "cache", 0, yasm_dir_helper_flag_and,
+ offsetof(struct coff_section_switch_data, flags), COFF_STYP_NOCACHE},
+ { "nocache", 0, yasm_dir_helper_flag_or,
+ offsetof(struct coff_section_switch_data, flags), COFF_STYP_NOCACHE},
+ { "page", 0, yasm_dir_helper_flag_and,
+ offsetof(struct coff_section_switch_data, flags), COFF_STYP_NOPAGE },
+ { "nopage", 0, yasm_dir_helper_flag_or,
+ offsetof(struct coff_section_switch_data, flags), COFF_STYP_NOPAGE },
+ { "share", 0, yasm_dir_helper_flag_or,
+ offsetof(struct coff_section_switch_data, flags), COFF_STYP_SHARED },
+ { "noshare", 0, yasm_dir_helper_flag_and,
+ offsetof(struct coff_section_switch_data, flags), COFF_STYP_SHARED },
+ { "execute", 0, yasm_dir_helper_flag_or,
+ offsetof(struct coff_section_switch_data, flags), COFF_STYP_EXECUTE},
+ { "noexecute", 0, yasm_dir_helper_flag_and,
+ offsetof(struct coff_section_switch_data, flags), COFF_STYP_EXECUTE},
+ { "read", 0, yasm_dir_helper_flag_or,
+ offsetof(struct coff_section_switch_data, flags), COFF_STYP_READ },
+ { "noread", 0, yasm_dir_helper_flag_and,
+ offsetof(struct coff_section_switch_data, flags), COFF_STYP_READ },
+ { "write", 0, yasm_dir_helper_flag_or,
+ offsetof(struct coff_section_switch_data, flags), COFF_STYP_WRITE },
+ { "nowrite", 0, yasm_dir_helper_flag_and,
+ offsetof(struct coff_section_switch_data, flags), COFF_STYP_WRITE },
+ { "base", 0, yasm_dir_helper_flag_and,
+ offsetof(struct coff_section_switch_data, flags2), COFF_FLAG_NOBASE},
+ { "nobase", 0, yasm_dir_helper_flag_or,
+ offsetof(struct coff_section_switch_data, flags2), COFF_FLAG_NOBASE},
+ { "align", 1, yasm_dir_helper_intn,
+ offsetof(struct coff_section_switch_data, align_intn), 0 }
+ };
+
+ vp = yasm_vps_first(valparams);
+ sectname = yasm_vp_string(vp);
+ if (!sectname)
+ return NULL;
+ vp = yasm_vps_next(vp);
+
+ data.isdefault = 0;
+ data.gasflags = 0;
+ data.flags = 0;
+ data.flags2 = 0;
+ data.align_intn = NULL;
+
+ if (strcmp(sectname, ".data") == 0) {
+ data.flags = COFF_STYP_DATA | COFF_STYP_READ | COFF_STYP_WRITE;
+ if (objfmt_coff->win32) {
+ if (objfmt_coff->machine == COFF_MACHINE_AMD64)
+ align = 16;
+ else
+ align = 4;
+ }
+ } else if (strcmp(sectname, ".bss") == 0) {
+ data.flags = COFF_STYP_BSS | COFF_STYP_READ | COFF_STYP_WRITE;
+ if (objfmt_coff->win32) {
+ if (objfmt_coff->machine == COFF_MACHINE_AMD64)
+ align = 16;
+ else
+ align = 4;
+ }
+ resonly = 1;
+ } else if (strcmp(sectname, ".text") == 0) {
+ data.flags = COFF_STYP_TEXT | COFF_STYP_EXECUTE | COFF_STYP_READ;
+ if (objfmt_coff->win32)
+ align = 16;
+ } else if (strcmp(sectname, ".rdata") == 0
+ || strncmp(sectname, ".rodata", 7) == 0
+ || strncmp(sectname, ".rdata$", 7) == 0) {
+ data.flags = COFF_STYP_DATA | COFF_STYP_READ;
+ if (objfmt_coff->win32)
+ align = 8;
+ else
+ yasm_warn_set(YASM_WARN_GENERAL,
+ N_("Standard COFF does not support read-only data sections"));
+ } else if (strcmp(sectname, ".drectve") == 0) {
+ data.flags = COFF_STYP_INFO;
+ if (objfmt_coff->win32)
+ data.flags |= COFF_STYP_DISCARD | COFF_STYP_READ;
+ } else if (objfmt_coff->win64 && strcmp(sectname, ".pdata") == 0) {
+ data.flags = COFF_STYP_DATA | COFF_STYP_READ;
+ align = 4;
+ data.flags2 = COFF_FLAG_NOBASE;
+ } else if (objfmt_coff->win64 && strcmp(sectname, ".xdata") == 0) {
+ data.flags = COFF_STYP_DATA | COFF_STYP_READ;
+ align = 8;
+ data.flags2 = COFF_FLAG_NOBASE;
+ } else if (objfmt_coff->win32 && strcmp(sectname, ".sxdata") == 0) {
+ data.flags = COFF_STYP_INFO;
+ } else if (strcmp(sectname, ".comment") == 0) {
+ data.flags = COFF_STYP_INFO | COFF_STYP_DISCARD | COFF_STYP_READ;
+ } else if (yasm__strncasecmp(sectname, ".debug", 6)==0) {
+ data.flags = COFF_STYP_DATA | COFF_STYP_DISCARD | COFF_STYP_READ;
+ align = 1;
+ } else {
+ /* Default to code, but set a flag so if we get gasflags we can
+ * change it (NASM and GAS have different defaults).
+ */
+ data.isdefault = 1;
+ data.flags = COFF_STYP_TEXT | COFF_STYP_EXECUTE | COFF_STYP_READ;
+ }
+
+ flags_override = yasm_dir_helper(object, vp, line, help,
+ objfmt_coff->win32 ? NELEMS(help) : 7,
+ &data, yasm_dir_helper_valparam_warn);
+ if (flags_override < 0)
+ return NULL; /* error occurred */
+
+ if (data.flags & COFF_STYP_EXECUTE)
+ iscode = 1;
+
+ if (!objfmt_coff->win32)
+ data.flags &= ~COFF_STYP_WIN32_MASK;
+
+ if (data.align_intn) {
+ align = yasm_intnum_get_uint(data.align_intn);
+ yasm_intnum_destroy(data.align_intn);
+
+ /* Alignments must be a power of two. */
+ if (!is_exp2(align)) {
+ yasm_error_set(YASM_ERROR_VALUE,
+ N_("argument to `%s' is not a power of two"),
+ "align");
+ return NULL;
+ }
+
+ /* Check to see if alignment is supported size */
+ if (align > 8192) {
+ yasm_error_set(YASM_ERROR_VALUE,
+ N_("Win32 does not support alignments > 8192"));
+ return NULL;
+ }
+ }
+
+ realname = yasm__xstrdup(sectname);
+ if (strlen(sectname) > 8 && !objfmt_coff->win32) {
+ /* win32 format supports >8 character section names in object
+ * files via "/nnnn" (where nnnn is decimal offset into string table),
+ * so only warn for regular COFF.
+ */
+ yasm_warn_set(YASM_WARN_GENERAL,
+ N_("COFF section names limited to 8 characters: truncating"));
+ realname[8] = '\0';
+ }
+
+ retval = yasm_object_get_general(object, realname, align, iscode,
+ resonly, &isnew, line);
+ yasm_xfree(realname);
+
+ csd = yasm_section_get_data(retval, &coff_section_data_cb);
+
+ if (isnew || yasm_section_is_default(retval)) {
+ yasm_section_set_default(retval, 0);
+ csd->flags = data.flags;
+ csd->flags2 = data.flags2;
+ yasm_section_set_align(retval, align, line);
+ } else if (flags_override && !data.gasflags)
+ yasm_warn_set(YASM_WARN_GENERAL,
+ N_("section flags ignored on section redeclaration"));
+ return retval;
+}
+
+static /*@observer@*/ /*@null@*/ yasm_symrec *
+coff_objfmt_get_special_sym(yasm_object *object, const char *name,
+ const char *parser)
+{
+ return NULL;
+}
+
+static /*@observer@*/ /*@null@*/ yasm_symrec *
+win64_objfmt_get_special_sym(yasm_object *object, const char *name,
+ const char *parser)
+{
+ if (yasm__strcasecmp(name, "imagebase") == 0) {
+ yasm_objfmt_coff *objfmt_coff = (yasm_objfmt_coff *)object->objfmt;
+ return objfmt_coff->ssym_imagebase;
+ }
+ return NULL;
+}
+
+static void
+coff_section_data_destroy(void *data)
+{
+ yasm_xfree(data);
+}
+
+static void
+coff_section_data_print(void *data, FILE *f, int indent_level)
+{
+ coff_section_data *csd = (coff_section_data *)data;
+
+ fprintf(f, "%*ssym=\n", indent_level, "");
+ yasm_symrec_print(csd->sym, f, indent_level+1);
+ fprintf(f, "%*sscnum=%d\n", indent_level, "", csd->scnum);
+ fprintf(f, "%*sflags=", indent_level, "");
+ switch (csd->flags & COFF_STYP_STD_MASK) {
+ case COFF_STYP_TEXT:
+ fprintf(f, "TEXT");
+ break;
+ case COFF_STYP_DATA:
+ fprintf(f, "DATA");
+ break;
+ case COFF_STYP_BSS:
+ fprintf(f, "BSS");
+ break;
+ default:
+ fprintf(f, "UNKNOWN");
+ break;
+ }
+ fprintf(f, "\n%*saddr=0x%lx\n", indent_level, "", csd->addr);
+ fprintf(f, "%*sscnptr=0x%lx\n", indent_level, "", csd->scnptr);
+ fprintf(f, "%*ssize=%ld\n", indent_level, "", csd->size);
+ fprintf(f, "%*srelptr=0x%lx\n", indent_level, "", csd->relptr);
+ fprintf(f, "%*snreloc=%ld\n", indent_level, "", csd->nreloc);
+ fprintf(f, "%*srelocs:\n", indent_level, "");
+}
+
+static void
+coff_symrec_data_destroy(void *data)
+{
+ yasm_xfree(data);
+}
+
+static void
+coff_symrec_data_print(void *data, FILE *f, int indent_level)
+{
+ coff_symrec_data *csd = (coff_symrec_data *)data;
+
+ fprintf(f, "%*ssymtab index=%lu\n", indent_level, "", csd->index);
+ fprintf(f, "%*ssclass=%d\n", indent_level, "", csd->sclass);
+}
+
+static void
+dir_export(yasm_object *object, yasm_valparamhead *valparams,
+ yasm_valparamhead *objext_valparams, unsigned long line)
+{
+ yasm_valparam *vp;
+ /*@null@*/ const char *symname;
+ int isnew;
+ yasm_section *sect;
+ yasm_datavalhead dvs;
+
+ /* Reference exported symbol (to generate error if not declared) */
+ vp = yasm_vps_first(valparams);
+ symname = yasm_vp_id(vp);
+ if (symname)
+ yasm_symtab_use(object->symtab, symname, line);
+ else {
+ yasm_error_set(YASM_ERROR_SYNTAX,
+ N_("argument to EXPORT must be symbol name"));
+ return;
+ }
+
+ /* Add to end of linker directives */
+ sect = yasm_object_get_general(object, ".drectve", 0, 0, 0, &isnew, line);
+
+ /* Initialize directive section if needed */
+ if (isnew) {
+ coff_section_data *csd;
+ csd = yasm_section_get_data(sect, &coff_section_data_cb);
+ csd->flags = COFF_STYP_INFO | COFF_STYP_DISCARD | COFF_STYP_READ;
+ }
+
+ /* Add text as data bytecode */
+ yasm_dvs_initialize(&dvs);
+ yasm_dvs_append(&dvs, yasm_dv_create_string(yasm__xstrdup("-export:"),
+ strlen("-export:")));
+ yasm_dvs_append(&dvs, yasm_dv_create_string(yasm__xstrdup(symname),
+ strlen(symname)));
+ yasm_dvs_append(&dvs, yasm_dv_create_string(yasm__xstrdup(" "), 1));
+ yasm_section_bcs_append(sect, yasm_bc_create_data(&dvs, 1, 0, NULL, line));
+}
+
+static void
+dir_safeseh(yasm_object *object, yasm_valparamhead *valparams,
+ yasm_valparamhead *objext_valparams, unsigned long line)
+{
+ yasm_valparam *vp;
+ /*@null@*/ const char *symname;
+ yasm_symrec *sym;
+ int isnew;
+ yasm_section *sect;
+
+ /* Reference symbol (to generate error if not declared).
+ * Also, symbol must be externally visible, so force it.
+ */
+ vp = yasm_vps_first(valparams);
+ symname = yasm_vp_id(vp);
+ if (symname) {
+ coff_symrec_data *sym_data;
+ sym = yasm_symtab_use(object->symtab, symname, line);
+ sym_data = yasm_symrec_get_data(sym, &coff_symrec_data_cb);
+ if (!sym_data) {
+ sym_data = coff_objfmt_sym_set_data(sym, COFF_SCL_NULL, 0,
+ COFF_SYMTAB_AUX_NONE);
+ }
+ sym_data->forcevis = 1;
+ sym_data->type = 0x20; /* function */
+ } else {
+ yasm_error_set(YASM_ERROR_SYNTAX,
+ N_("argument to SAFESEH must be symbol name"));
+ return;
+ }
+
+ /*
+ * Add symbol number to end of .sxdata section.
+ */
+
+ sect = yasm_object_get_general(object, ".sxdata", 0, 0, 0, &isnew, line);
+
+ /* Initialize sxdata section if needed */
+ if (isnew) {
+ coff_section_data *csd;
+ csd = yasm_section_get_data(sect, &coff_section_data_cb);
+ csd->flags = COFF_STYP_INFO;
+ }
+
+ /* Add as sxdata bytecode */
+ yasm_section_bcs_append(sect,
+ yasm_bc_create_common(&win32_sxdata_bc_callback,
+ sym, line));
+}
+
+static void
+win32_sxdata_bc_destroy(void *contents)
+{
+ /* Contents is just the symbol pointer, so no need to delete */
+}
+
+static void
+win32_sxdata_bc_print(const void *contents, FILE *f, int indent_level)
+{
+ /* TODO */
+}
+
+static int
+win32_sxdata_bc_calc_len(yasm_bytecode *bc, yasm_bc_add_span_func add_span,
+ void *add_span_data)
+{
+ bc->len += 4;
+ return 0;
+}
+
+static int
+win32_sxdata_bc_tobytes(yasm_bytecode *bc, unsigned char **bufp,
+ unsigned char *bufstart, void *d,
+ yasm_output_value_func output_value,
+ yasm_output_reloc_func output_reloc)
+{
+ yasm_symrec *sym = (yasm_symrec *)bc->contents;
+ unsigned char *buf = *bufp;
+ coff_symrec_data *csymd;
+
+ csymd = yasm_symrec_get_data(sym, &coff_symrec_data_cb);
+ if (!csymd)
+ yasm_internal_error(N_("coff: no symbol data for SAFESEH symbol"));
+
+ YASM_WRITE_32_L(buf, csymd->index);
+
+ *bufp = buf;
+ return 0;
+}
+
+static void
+dir_ident(yasm_object *object, yasm_valparamhead *valparams,
+ yasm_valparamhead *objext_valparams, unsigned long line)
+{
+ yasm_objfmt_coff *objfmt_coff = (yasm_objfmt_coff *)object->objfmt;
+ yasm_valparamhead sect_vps;
+ yasm_datavalhead dvs;
+ yasm_section *comment;
+ const char *sectname;
+ yasm_valparam *vp, *vp2;
+
+ /* Accept, but do nothing with empty ident */
+ if (!valparams)
+ return;
+
+ vp = yasm_vps_first(valparams);
+ if (!vp)
+ return;
+
+ if (objfmt_coff->win32) {
+ /* Put ident data into .comment section for COFF, or .rdata$zzz
+ * to be compatible with the GNU linker, which doesn't ignore
+ * .comment (see binutils/gas/config/obj-coff.c:476-502).
+ */
+ sectname = ".rdata$zzz";
+ } else {
+ sectname = ".comment";
+ }
+ yasm_vps_initialize(&sect_vps);
+ vp2 = yasm_vp_create_id(NULL, yasm__xstrdup(sectname), '\0');
+ yasm_vps_append(&sect_vps, vp2);
+ comment = coff_objfmt_section_switch(object, &sect_vps, NULL, line);
+ yasm_vps_delete(&sect_vps);
+
+ /* To match GAS output, if the comment section is empty, put an
+ * initial 0 byte in the section.
+ */
+ if (yasm_section_bcs_first(comment) == yasm_section_bcs_last(comment)) {
+ yasm_dvs_initialize(&dvs);
+ yasm_dvs_append(&dvs, yasm_dv_create_expr(
+ yasm_expr_create_ident(yasm_expr_int(yasm_intnum_create_uint(0)),
+ line)));
+ yasm_section_bcs_append(comment,
+ yasm_bc_create_data(&dvs, 1, 0, object->arch, line));
+ }
+
+ yasm_dvs_initialize(&dvs);
+ do {
+ const char *s = yasm_vp_string(vp);
+ if (!s) {
+ yasm_error_set(YASM_ERROR_VALUE,
+ N_(".comment requires string parameters"));
+ yasm_dvs_delete(&dvs);
+ return;
+ }
+ yasm_dvs_append(&dvs,
+ yasm_dv_create_string(yasm__xstrdup(s), strlen(s)));
+ } while ((vp = yasm_vps_next(vp)));
+
+ yasm_section_bcs_append(comment,
+ yasm_bc_create_data(&dvs, 1, 1, object->arch, line));
+}
+
+static void
+dir_secrel32(yasm_object *object, yasm_valparamhead *valparams,
+ yasm_valparamhead *objext_valparams, unsigned long line)
+{
+ yasm_datavalhead dvs;
+ yasm_valparam *vp;
+
+ if (!object->cur_section) {
+ yasm_error_set(YASM_ERROR_SYNTAX,
+ N_(".secrel32 can only be used inside of a section"));
+ return;
+ }
+
+ vp = yasm_vps_first(valparams);
+ yasm_dvs_initialize(&dvs);
+ do {
+ yasm_expr *e = yasm_vp_expr(vp, object->symtab, line);
+ yasm_dataval *dv;
+ if (!e) {
+ yasm_error_set(YASM_ERROR_VALUE,
+ N_(".secrel32 requires expressions"));
+ yasm_dvs_delete(&dvs);
+ return;
+ }
+ dv = yasm_dv_create_expr(e);
+ yasm_dv_get_value(dv)->section_rel = 1;
+ yasm_dvs_append(&dvs, dv);
+ } while ((vp = yasm_vps_next(vp)));
+
+ yasm_section_bcs_append(object->cur_section,
+ yasm_bc_create_data(&dvs, 4, 0, object->arch, line));
+}
+
+static void
+dir_def(yasm_object *object, yasm_valparamhead *valparams,
+ yasm_valparamhead *objext_valparams, unsigned long line)
+{
+ yasm_objfmt_coff *objfmt_coff = (yasm_objfmt_coff *)object->objfmt;
+ yasm_valparam *vp;
+ const char *symname;
+ yasm_symrec *sym;
+ coff_symrec_data *sym_data;
+
+ if (objfmt_coff->def_sym) {
+ yasm_warn_set(YASM_WARN_GENERAL,
+ N_(".def pseudo-op used inside of .def/.endef; ignored"));
+ return;
+ }
+
+ vp = yasm_vps_first(valparams);
+ symname = yasm_vp_id(vp);
+ if (!symname) {
+ yasm_error_set(YASM_ERROR_SYNTAX,
+ N_("argument to SAFESEH must be symbol name"));
+ return;
+ }
+
+ sym = yasm_symtab_use(object->symtab, symname, line);
+ sym_data = yasm_symrec_get_data(sym, &coff_symrec_data_cb);
+ if (!sym_data) {
+ sym_data = coff_objfmt_sym_set_data(sym, COFF_SCL_NULL, 0,
+ COFF_SYMTAB_AUX_NONE);
+ }
+ objfmt_coff->def_sym = sym_data;
+}
+
+static void
+dir_scl(yasm_object *object, yasm_valparamhead *valparams,
+ yasm_valparamhead *objext_valparams, unsigned long line)
+{
+ yasm_objfmt_coff *objfmt_coff = (yasm_objfmt_coff *)object->objfmt;
+ yasm_intnum *intn = NULL;
+
+ if (!objfmt_coff->def_sym) {
+ yasm_warn_set(YASM_WARN_GENERAL,
+ N_("%s pseudo-op used outside of .def/.endef; ignored"),
+ ".scl");
+ return;
+ }
+
+ if (yasm_dir_helper_intn(object, yasm_vps_first(valparams), line,
+ &intn, 0) < 0)
+ return;
+ if (!intn)
+ return;
+ objfmt_coff->def_sym->sclass = yasm_intnum_get_uint(intn);
+ yasm_intnum_destroy(intn);
+}
+
+static void
+dir_type(yasm_object *object, yasm_valparamhead *valparams,
+ yasm_valparamhead *objext_valparams, unsigned long line)
+{
+ yasm_objfmt_coff *objfmt_coff = (yasm_objfmt_coff *)object->objfmt;
+ yasm_intnum *intn = NULL;
+
+ if (!objfmt_coff->def_sym) {
+ yasm_warn_set(YASM_WARN_GENERAL,
+ N_("%s pseudo-op used outside of .def/.endef; ignored"),
+ ".type");
+ return;
+ }
+
+ if (yasm_dir_helper_intn(object, yasm_vps_first(valparams), line,
+ &intn, 0) < 0)
+ return;
+ if (!intn)
+ return;
+ objfmt_coff->def_sym->type = yasm_intnum_get_uint(intn);
+ yasm_intnum_destroy(intn);
+}
+
+static void
+dir_endef(yasm_object *object, yasm_valparamhead *valparams,
+ yasm_valparamhead *objext_valparams, unsigned long line)
+{
+ yasm_objfmt_coff *objfmt_coff = (yasm_objfmt_coff *)object->objfmt;
+ if (!objfmt_coff->def_sym) {
+ yasm_warn_set(YASM_WARN_GENERAL,
+ N_(".endef pseudo-op used before .def; ignored"));
+ return;
+ }
+ objfmt_coff->def_sym = NULL;
+}
+
+static void
+dir_proc_frame(yasm_object *object, /*@null@*/ yasm_valparamhead *valparams,
+ yasm_valparamhead *objext_valparams, unsigned long line)
+{
+ yasm_objfmt_coff *objfmt_coff = (yasm_objfmt_coff *)object->objfmt;
+ yasm_valparam *vp = yasm_vps_first(valparams);
+ const char *name = yasm_vp_id(vp);
+
+ 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;
+ }
+ objfmt_coff->proc_frame = line;
+ objfmt_coff->done_prolog = 0;
+ objfmt_coff->unwind = yasm_win64__uwinfo_create();
+ objfmt_coff->unwind->proc = yasm_symtab_use(object->symtab, name, line);
+
+ /* Optional error handler */
+ vp = yasm_vps_next(vp);
+ if (!vp || !(name = yasm_vp_id(vp)))
+ return;
+ objfmt_coff->unwind->ehandler =
+ yasm_symtab_use(object->symtab, name, 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_object *object, const char *dirname, unsigned long line)
+{
+ if (!object->cur_section) {
+ yasm_error_set(YASM_ERROR_SYNTAX,
+ N_("[%s] can only be used inside of a section"),
+ dirname);
+ return NULL;
+ }
+ return yasm_symtab_define_curpos(object->symtab, "$",
+ yasm_section_bcs_last(object->cur_section), line);
+}
+
+static void
+dir_pushreg(yasm_object *object, yasm_valparamhead *valparams,
+ yasm_valparamhead *objext_valparams, unsigned long line)
+{
+ yasm_objfmt_coff *objfmt_coff = (yasm_objfmt_coff *)object->objfmt;
+ yasm_valparam *vp = yasm_vps_first(valparams);
+ coff_unwind_code *code;
+ const uintptr_t *reg;
+
+ if (!procframe_checkstate(objfmt_coff, "PUSHREG"))
+ return;
+
+ if (vp->type != YASM_PARAM_EXPR ||
+ !(reg = yasm_expr_get_reg(&vp->param.e, 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(object, "PUSHREG", 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_object *object, yasm_valparamhead *valparams,
+ yasm_valparamhead *objext_valparams, unsigned long line)
+{
+ yasm_objfmt_coff *objfmt_coff = (yasm_objfmt_coff *)object->objfmt;
+ yasm_valparam *vp = yasm_vps_first(valparams);
+ coff_unwind_code *code;
+ const uintptr_t *reg;
+ yasm_expr *off = NULL;
+
+ if (!procframe_checkstate(objfmt_coff, "SETFRAME"))
+ return;
+
+ if (vp->type != YASM_PARAM_EXPR ||
+ !(reg = yasm_expr_get_reg(&vp->param.e, 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)
+ off = yasm_vp_expr(vp, object->symtab, line);
+
+ /* Set the frame fields in the unwind info */
+ objfmt_coff->unwind->framereg = (unsigned long)(*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(object, "SETFRAME", line);
+ code->opcode = UWOP_SET_FPREG;
+ code->info = (unsigned int)(*reg & 0xF);
+ yasm_value_initialize(&code->off, off ? yasm_expr_copy(off) : NULL, 8);
+ SLIST_INSERT_HEAD(&objfmt_coff->unwind->codes, code, link);
+}
+
+static void
+dir_allocstack(yasm_object *object, yasm_valparamhead *valparams,
+ yasm_valparamhead *objext_valparams, unsigned long line)
+{
+ yasm_objfmt_coff *objfmt_coff = (yasm_objfmt_coff *)object->objfmt;
+ yasm_valparam *vp = yasm_vps_first(valparams);
+ /*@null@*/ /*@only@*/ yasm_expr *size;
+ coff_unwind_code *code;
+
+ if (!procframe_checkstate(objfmt_coff, "ALLOCSTACK"))
+ return;
+
+ size = yasm_vp_expr(vp, object->symtab, line);
+ if (!size) {
+ 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(object, "ALLOCSTACK", line);
+ code->opcode = UWOP_ALLOC_SMALL;
+ code->info = 0;
+ yasm_value_initialize(&code->off, size, 7);
+ SLIST_INSERT_HEAD(&objfmt_coff->unwind->codes, code, link);
+}
+
+static void
+dir_save_common(yasm_object *object, yasm_valparamhead *valparams,
+ unsigned long line, const char *name, int op)
+{
+ yasm_objfmt_coff *objfmt_coff = (yasm_objfmt_coff *)object->objfmt;
+ yasm_valparam *vp = yasm_vps_first(valparams);
+ coff_unwind_code *code;
+ const uintptr_t *reg;
+ /*@only@*/ /*@null@*/ yasm_expr *offset;
+
+ if (!procframe_checkstate(objfmt_coff, name))
+ return;
+
+ if (vp->type != YASM_PARAM_EXPR ||
+ !(reg = yasm_expr_get_reg(&vp->param.e, 0))) {
+ yasm_error_set(YASM_ERROR_SYNTAX,
+ N_("[%s] requires a register as the first parameter"),
+ name);
+ return;
+ }
+
+ vp = yasm_vps_next(vp);
+ offset = yasm_vp_expr(vp, object->symtab, line);
+ if (!offset) {
+ 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(object, name, line);
+ code->opcode = op;
+ code->info = (unsigned int)(*reg & 0xF);
+ yasm_value_initialize(&code->off, offset, 16);
+ SLIST_INSERT_HEAD(&objfmt_coff->unwind->codes, code, link);
+}
+
+static void
+dir_savereg(yasm_object *object, yasm_valparamhead *valparams,
+ yasm_valparamhead *objext_valparams, unsigned long line)
+{
+ dir_save_common(object, valparams, line, "SAVEREG", UWOP_SAVE_NONVOL);
+}
+
+static void
+dir_savexmm128(yasm_object *object, yasm_valparamhead *valparams,
+ yasm_valparamhead *objext_valparams, unsigned long line)
+{
+ dir_save_common(object, valparams, line, "SAVEXMM128", UWOP_SAVE_XMM128);
+}
+
+static void
+dir_pushframe(yasm_object *object, /*@null@*/ yasm_valparamhead *valparams,
+ yasm_valparamhead *objext_valparams, unsigned long line)
+{
+ yasm_objfmt_coff *objfmt_coff = (yasm_objfmt_coff *)object->objfmt;
+ 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(object, "PUSHFRAME", line);
+ code->opcode = UWOP_PUSH_MACHFRAME;
+ code->info = vp != NULL;
+ yasm_value_initialize(&code->off, NULL, 0);
+ SLIST_INSERT_HEAD(&objfmt_coff->unwind->codes, code, link);
+}
+
+static void
+dir_endprolog(yasm_object *object, /*@null@*/ yasm_valparamhead *valparams,
+ yasm_valparamhead *objext_valparams, unsigned long line)
+{
+ yasm_objfmt_coff *objfmt_coff = (yasm_objfmt_coff *)object->objfmt;
+ if (!procframe_checkstate(objfmt_coff, "ENDPROLOG"))
+ return;
+ objfmt_coff->done_prolog = line;
+
+ objfmt_coff->unwind->prolog = get_curpos(object, "ENDPROLOG", line);
+}
+
+static void
+dir_endproc_frame(yasm_object *object, /*@null@*/ yasm_valparamhead *valparams,
+ yasm_valparamhead *objext_valparams, unsigned long line)
+{
+ yasm_objfmt_coff *objfmt_coff = (yasm_objfmt_coff *)object->objfmt;
+ 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(object, "ENDPROC_FRAME", line);
+
+ /*
+ * Add unwind info to end of .xdata section.
+ */
+
+ sect = yasm_object_get_general(object, ".xdata", 0, 0, 0, &isnew, line);
+
+ /* Initialize xdata section if needed */
+ if (isnew) {
+ csd = yasm_section_get_data(sect, &coff_section_data_cb);
+ 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(object->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(object, ".pdata", 0, 0, 0, &isnew, line);
+
+ /* Initialize pdata section if needed */
+ if (isnew) {
+ csd = yasm_section_get_data(sect, &coff_section_data_cb);
+ 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;
+}
+
+/* Define valid debug formats to use with this object format */
+static const char *coff_objfmt_dbgfmt_keywords[] = {
+ "null",
+ "dwarf2",
+ NULL
+};
+
+static const yasm_directive coff_objfmt_directives[] = {
+ { ".ident", "gas", dir_ident, YASM_DIR_ANY },
+ { "ident", "nasm", dir_ident, YASM_DIR_ANY },
+ { ".def", "gas", dir_def, YASM_DIR_ID_REQUIRED },
+ { ".endef", "gas", dir_endef, YASM_DIR_ANY },
+ { ".scl", "gas", dir_scl, YASM_DIR_ARG_REQUIRED },
+ { ".type", "gas", dir_type, YASM_DIR_ARG_REQUIRED },
+ { ".secrel32", "gas", dir_secrel32, YASM_DIR_ARG_REQUIRED },
+ { NULL, NULL, NULL, 0 }
+};
+
+/* Define objfmt structure -- see objfmt.h for details */
+yasm_objfmt_module yasm_coff_LTX_objfmt = {
+ "COFF (DJGPP)",
+ "coff",
+ "o",
+ 32,
+ 0,
+ coff_objfmt_dbgfmt_keywords,
+ "null",
+ coff_objfmt_directives,
+ NULL, /* no standard macros */
+ coff_objfmt_create,
+ coff_objfmt_output,
+ coff_objfmt_destroy,
+ coff_objfmt_add_default_section,
+ coff_objfmt_init_new_section,
+ coff_objfmt_section_switch,
+ coff_objfmt_get_special_sym
+};
+
+/* Define valid debug formats to use with this object format */
+static const char *winXX_objfmt_dbgfmt_keywords[] = {
+ "null",
+ "dwarf2",
+ "cv8",
+ NULL
+};
+
+static const yasm_directive win32_objfmt_directives[] = {
+ { ".ident", "gas", dir_ident, YASM_DIR_ANY },
+ { "ident", "nasm", dir_ident, YASM_DIR_ANY },
+ { ".def", "gas", dir_def, YASM_DIR_ID_REQUIRED },
+ { ".endef", "gas", dir_endef, YASM_DIR_ANY },
+ { ".scl", "gas", dir_scl, YASM_DIR_ARG_REQUIRED },
+ { ".type", "gas", dir_type, YASM_DIR_ARG_REQUIRED },
+ { ".secrel32", "gas", dir_secrel32, YASM_DIR_ARG_REQUIRED },
+ { ".export", "gas", dir_export, YASM_DIR_ID_REQUIRED },
+ { "export", "nasm", dir_export, YASM_DIR_ID_REQUIRED },
+ { ".safeseh", "gas", dir_safeseh, YASM_DIR_ID_REQUIRED },
+ { "safeseh", "nasm", dir_safeseh, YASM_DIR_ID_REQUIRED },
+ { NULL, NULL, NULL, 0 }
+};
+
+static const char *win32_nasm_stdmac[] = {
+ "%imacro export 1+.nolist",
+ "[export %1]",
+ "%endmacro",
+ "%imacro safeseh 1+.nolist",
+ "[safeseh %1]",
+ "%endmacro",
+ NULL
+};
+
+static const yasm_stdmac win32_objfmt_stdmacs[] = {
+ { "nasm", "nasm", win32_nasm_stdmac },
+ { NULL, NULL, NULL }
+};
+
+/* Define objfmt structure -- see objfmt.h for details */
+yasm_objfmt_module yasm_win32_LTX_objfmt = {
+ "Win32",
+ "win32",
+ "obj",
+ 32,
+ 1,
+ winXX_objfmt_dbgfmt_keywords,
+ "null",
+ win32_objfmt_directives,
+ win32_objfmt_stdmacs,
+ win32_objfmt_create,
+ coff_objfmt_output,
+ coff_objfmt_destroy,
+ coff_objfmt_add_default_section,
+ coff_objfmt_init_new_section,
+ coff_objfmt_section_switch,
+ coff_objfmt_get_special_sym
+};
+
+static const yasm_directive win64_objfmt_directives[] = {
+ { ".ident", "gas", dir_ident, YASM_DIR_ANY },
+ { "ident", "nasm", dir_ident, YASM_DIR_ANY },
+ { ".def", "gas", dir_def, YASM_DIR_ID_REQUIRED },
+ { ".endef", "gas", dir_endef, YASM_DIR_ANY },
+ { ".scl", "gas", dir_scl, YASM_DIR_ARG_REQUIRED },
+ { ".type", "gas", dir_type, YASM_DIR_ARG_REQUIRED },
+ { ".secrel32", "gas", dir_secrel32, YASM_DIR_ARG_REQUIRED },
+ { ".export", "gas", dir_export, YASM_DIR_ID_REQUIRED },
+ { "export", "nasm", dir_export, YASM_DIR_ID_REQUIRED },
+ { ".proc_frame", "gas", dir_proc_frame, YASM_DIR_ID_REQUIRED },
+ { "proc_frame", "nasm", dir_proc_frame, YASM_DIR_ID_REQUIRED },
+ { ".pushreg", "gas", dir_pushreg, YASM_DIR_ARG_REQUIRED },
+ { "pushreg", "nasm", dir_pushreg, YASM_DIR_ARG_REQUIRED },
+ { ".setframe", "gas", dir_setframe, YASM_DIR_ARG_REQUIRED },
+ { "setframe", "nasm", dir_setframe, YASM_DIR_ARG_REQUIRED },
+ { ".allocstack", "gas", dir_allocstack, YASM_DIR_ARG_REQUIRED },
+ { "allocstack", "nasm", dir_allocstack, YASM_DIR_ARG_REQUIRED },
+ { ".savereg", "gas", dir_savereg, YASM_DIR_ARG_REQUIRED },
+ { "savereg", "nasm", dir_savereg, YASM_DIR_ARG_REQUIRED },
+ { ".savexmm128", "gas", dir_savexmm128, YASM_DIR_ARG_REQUIRED },
+ { "savexmm128", "nasm", dir_savexmm128, YASM_DIR_ARG_REQUIRED },
+ { ".pushframe", "gas", dir_pushframe, YASM_DIR_ANY },
+ { "pushframe", "nasm", dir_pushframe, YASM_DIR_ANY },
+ { ".endprolog", "gas", dir_endprolog, YASM_DIR_ANY },
+ { "endprolog", "nasm", dir_endprolog, YASM_DIR_ANY },
+ { ".endproc_frame", "gas", dir_endproc_frame, YASM_DIR_ANY },
+ { "endproc_frame", "nasm", dir_endproc_frame, YASM_DIR_ANY },
+ { NULL, NULL, NULL, 0 }
+};
+
+#include "win64-nasm.c"
+#include "win64-gas.c"
+
+static const yasm_stdmac win64_objfmt_stdmacs[] = {
+ { "nasm", "nasm", win64_nasm_stdmac },
+ { "gas", "nasm", win64_gas_stdmac },
+ { NULL, NULL, NULL }
+};
+
+/* Define objfmt structure -- see objfmt.h for details */
+yasm_objfmt_module yasm_win64_LTX_objfmt = {
+ "Win64",
+ "win64",
+ "obj",
+ 64,
+ 1,
+ winXX_objfmt_dbgfmt_keywords,
+ "null",
+ win64_objfmt_directives,
+ win64_objfmt_stdmacs,
+ win64_objfmt_create,
+ coff_objfmt_output,
+ coff_objfmt_destroy,
+ coff_objfmt_add_default_section,
+ coff_objfmt_init_new_section,
+ coff_objfmt_section_switch,
+ win64_objfmt_get_special_sym
+};
+yasm_objfmt_module yasm_x64_LTX_objfmt = {
+ "Win64",
+ "x64",
+ "obj",
+ 64,
+ 1,
+ winXX_objfmt_dbgfmt_keywords,
+ "null",
+ win64_objfmt_directives,
+ win64_objfmt_stdmacs,
+ win64_objfmt_create,
+ coff_objfmt_output,
+ coff_objfmt_destroy,
+ coff_objfmt_add_default_section,
+ coff_objfmt_init_new_section,
+ coff_objfmt_section_switch,
+ win64_objfmt_get_special_sym
+};
diff --git a/contrib/tools/yasm/modules/objfmts/coff/coff-objfmt.h b/contrib/tools/yasm/modules/objfmts/coff/coff-objfmt.h
index 10d88a0982..cdd581acb2 100644
--- a/contrib/tools/yasm/modules/objfmts/coff/coff-objfmt.h
+++ b/contrib/tools/yasm/modules/objfmts/coff/coff-objfmt.h
@@ -1,77 +1,77 @@
-/*
- * 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
+/*
+ * 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/contrib/tools/yasm/modules/objfmts/coff/win64-except.c b/contrib/tools/yasm/modules/objfmts/coff/win64-except.c
index 8c8ecbbc49..8fe585df8c 100644
--- a/contrib/tools/yasm/modules/objfmts/coff/win64-except.c
+++ b/contrib/tools/yasm/modules/objfmts/coff/win64-except.c
@@ -1,559 +1,559 @@
-/*
- * 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>
-
-#include <libyasm.h>
-
-#include "coff-objfmt.h"
-
-
-#define UNW_FLAG_EHANDLER 0x01
-#define UNW_FLAG_UHANDLER 0x02
-#define UNW_FLAG_CHAININFO 0x04
-
-/* 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, unsigned char *bufstart, 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, unsigned char *bufstart, 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,
- NULL,
- 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,
- NULL,
- 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_def_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_def_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,
- unsigned char *bufstart, 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-bufstart),
- bc, 1, d);
- buf += 1;
-
- /* Count of codes */
- output_value(&info->codes_count, buf, 1, (unsigned long)(buf-bufstart),
- 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"));
- /*@unreached@*/
- return 0;
- }
-
- 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,
- unsigned char *bufstart, 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-bufstart), 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;
- default:
- yasm_internal_error(N_("unrecognied unwind opcode"));
- /*@unreached@*/
- return 1;
- }
-
- /* 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;
-}
+/*
+ * 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>
+
+#include <libyasm.h>
+
+#include "coff-objfmt.h"
+
+
+#define UNW_FLAG_EHANDLER 0x01
+#define UNW_FLAG_UHANDLER 0x02
+#define UNW_FLAG_CHAININFO 0x04
+
+/* 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, unsigned char *bufstart, 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, unsigned char *bufstart, 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,
+ NULL,
+ 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,
+ NULL,
+ 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_def_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_def_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,
+ unsigned char *bufstart, 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-bufstart),
+ bc, 1, d);
+ buf += 1;
+
+ /* Count of codes */
+ output_value(&info->codes_count, buf, 1, (unsigned long)(buf-bufstart),
+ 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"));
+ /*@unreached@*/
+ return 0;
+ }
+
+ 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,
+ unsigned char *bufstart, 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-bufstart), 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;
+ default:
+ yasm_internal_error(N_("unrecognied unwind opcode"));
+ /*@unreached@*/
+ return 1;
+ }
+
+ /* 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;
+}