Home | History | Annotate | Download | only in coff
      1 /*
      2  * COFF (DJGPP) object format
      3  *
      4  *  Copyright (C) 2002-2007  Peter Johnson
      5  *
      6  * Redistribution and use in source and binary forms, with or without
      7  * modification, are permitted provided that the following conditions
      8  * are met:
      9  * 1. Redistributions of source code must retain the above copyright
     10  *    notice, this list of conditions and the following disclaimer.
     11  * 2. Redistributions in binary form must reproduce the above copyright
     12  *    notice, this list of conditions and the following disclaimer in the
     13  *    documentation and/or other materials provided with the distribution.
     14  *
     15  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND OTHER CONTRIBUTORS ``AS IS''
     16  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
     17  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
     18  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR OTHER CONTRIBUTORS BE
     19  * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
     20  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
     21  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
     22  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
     23  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
     24  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
     25  * POSSIBILITY OF SUCH DAMAGE.
     26  */
     27 #include <util.h>
     28 #include <time.h>
     29 
     30 #include <libyasm.h>
     31 
     32 #include "coff-objfmt.h"
     33 
     34 
     35 #define REGULAR_OUTBUF_SIZE     1024
     36 
     37 /* Defining this to 0 sets all section VMA's to 0 rather than as the same as
     38  * the LMA.  According to the DJGPP COFF Spec, this should be set to 1
     39  * (VMA=LMA), and indeed DJGPP's GCC output shows VMA=LMA.  However, NASM
     40  * outputs VMA=0 (as if this was 0), and GNU objdump output looks a lot nicer
     41  * with VMA=0.  Who's right?  This is #defined as changing this setting affects
     42  * several places in the code.
     43  */
     44 #define COFF_SET_VMA    (!objfmt_coff->win32)
     45 
     46 #define COFF_MACHINE_I386       0x014C
     47 #define COFF_MACHINE_AMD64      0x8664
     48 
     49 #define COFF_F_LNNO     0x0004      /* line number info NOT present */
     50 #define COFF_F_LSYMS    0x0008      /* local symbols NOT present */
     51 #define COFF_F_AR32WR   0x0100      /* 32-bit little endian file */
     52 
     53 typedef struct coff_reloc {
     54     yasm_reloc reloc;
     55     enum {
     56         COFF_RELOC_ABSOLUTE = 0,            /* absolute, no reloc needed */
     57 
     58         /* I386 relocations */
     59         COFF_RELOC_I386_ADDR16 = 0x1,       /* 16-bit absolute reference */
     60         COFF_RELOC_I386_REL16 = 0x2,        /* 16-bit PC-relative reference */
     61         COFF_RELOC_I386_ADDR32 = 0x6,       /* 32-bit absolute reference */
     62         COFF_RELOC_I386_ADDR32NB = 0x7,     /* 32-bit absolute ref w/o base */
     63         COFF_RELOC_I386_SEG12 = 0x9,        /* 16-bit absolute segment ref */
     64         COFF_RELOC_I386_SECTION = 0xA,      /* section index */
     65         COFF_RELOC_I386_SECREL = 0xB,       /* offset from start of segment */
     66         COFF_RELOC_I386_TOKEN = 0xC,        /* CLR metadata token */
     67         COFF_RELOC_I386_SECREL7 = 0xD,  /* 7-bit offset from base of sect */
     68         COFF_RELOC_I386_REL32 = 0x14,       /* 32-bit PC-relative reference */
     69 
     70         /* AMD64 relocations */
     71         COFF_RELOC_AMD64_ADDR64 = 0x1,      /* 64-bit address (VA) */
     72         COFF_RELOC_AMD64_ADDR32 = 0x2,      /* 32-bit address (VA) */
     73         COFF_RELOC_AMD64_ADDR32NB = 0x3,    /* 32-bit address w/o base (RVA) */
     74         COFF_RELOC_AMD64_REL32 = 0x4,       /* 32-bit relative (0 byte dist) */
     75         COFF_RELOC_AMD64_REL32_1 = 0x5,     /* 32-bit relative (1 byte dist) */
     76         COFF_RELOC_AMD64_REL32_2 = 0x6,     /* 32-bit relative (2 byte dist) */
     77         COFF_RELOC_AMD64_REL32_3 = 0x7,     /* 32-bit relative (3 byte dist) */
     78         COFF_RELOC_AMD64_REL32_4 = 0x8,     /* 32-bit relative (4 byte dist) */
     79         COFF_RELOC_AMD64_REL32_5 = 0x9,     /* 32-bit relative (5 byte dist) */
     80         COFF_RELOC_AMD64_SECTION = 0xA,     /* section index */
     81         COFF_RELOC_AMD64_SECREL = 0xB,  /* 32-bit offset from base of sect */
     82         COFF_RELOC_AMD64_SECREL7 = 0xC, /* 7-bit offset from base of sect */
     83         COFF_RELOC_AMD64_TOKEN = 0xD        /* CLR metadata token */
     84     } type;                         /* type of relocation */
     85 } coff_reloc;
     86 
     87 #define COFF_STYP_TEXT          0x00000020UL
     88 #define COFF_STYP_DATA          0x00000040UL
     89 #define COFF_STYP_BSS           0x00000080UL
     90 #define COFF_STYP_INFO          0x00000200UL
     91 #define COFF_STYP_STD_MASK      0x000003FFUL
     92 #define COFF_STYP_ALIGN_MASK    0x00F00000UL
     93 #define COFF_STYP_ALIGN_SHIFT   20
     94 #define COFF_STYP_NRELOC_OVFL   0x01000000UL
     95 #define COFF_STYP_DISCARD       0x02000000UL
     96 #define COFF_STYP_NOCACHE       0x04000000UL
     97 #define COFF_STYP_NOPAGE        0x08000000UL
     98 #define COFF_STYP_SHARED        0x10000000UL
     99 #define COFF_STYP_EXECUTE       0x20000000UL
    100 #define COFF_STYP_READ          0x40000000UL
    101 #define COFF_STYP_WRITE         0x80000000UL
    102 #define COFF_STYP_WIN32_MASK    0xFF000000UL
    103 
    104 #define COFF_FLAG_NOBASE        (1UL<<0)    /* Use no-base (NB) relocs */
    105 
    106 typedef struct coff_section_data {
    107     /*@dependent@*/ yasm_symrec *sym;   /* symbol created for this section */
    108     unsigned int scnum;     /* section number (1=first section) */
    109     unsigned long flags;    /* section flags (see COFF_STYP_* above) */
    110     unsigned long addr;     /* starting memory address (first section -> 0) */
    111     unsigned long scnptr;   /* file ptr to raw data */
    112     unsigned long size;     /* size of raw data (section data) in bytes */
    113     unsigned long relptr;   /* file ptr to relocation */
    114     unsigned long nreloc;   /* number of relocation entries >64k -> error */
    115     unsigned long flags2;   /* internal flags (see COFF_FLAG_* above) */
    116     unsigned long strtab_name;  /* strtab offset of name if name > 8 chars */
    117     int isdebug;            /* is a debug section? */
    118 } coff_section_data;
    119 
    120 typedef enum coff_symrec_sclass {
    121     COFF_SCL_EFCN = 0xff,       /* physical end of function     */
    122     COFF_SCL_NULL = 0,
    123     COFF_SCL_AUTO = 1,          /* automatic variable           */
    124     COFF_SCL_EXT = 2,           /* external symbol              */
    125     COFF_SCL_STAT = 3,          /* static                       */
    126     COFF_SCL_REG = 4,           /* register variable            */
    127     COFF_SCL_EXTDEF = 5,        /* external definition          */
    128     COFF_SCL_LABEL = 6,         /* label                        */
    129     COFF_SCL_ULABEL = 7,        /* undefined label              */
    130     COFF_SCL_MOS = 8,           /* member of structure          */
    131     COFF_SCL_ARG = 9,           /* function argument            */
    132     COFF_SCL_STRTAG = 10,       /* structure tag                */
    133     COFF_SCL_MOU = 11,          /* member of union              */
    134     COFF_SCL_UNTAG = 12,        /* union tag                    */
    135     COFF_SCL_TPDEF = 13,        /* type definition              */
    136     COFF_SCL_USTATIC = 14,      /* undefined static             */
    137     COFF_SCL_ENTAG = 15,        /* enumeration tag              */
    138     COFF_SCL_MOE = 16,          /* member of enumeration        */
    139     COFF_SCL_REGPARM = 17,      /* register parameter           */
    140     COFF_SCL_FIELD = 18,        /* bit field                    */
    141     COFF_SCL_AUTOARG = 19,      /* auto argument                */
    142     COFF_SCL_LASTENT = 20,      /* dummy entry (end of block)   */
    143     COFF_SCL_BLOCK = 100,       /* ".bb" or ".eb"               */
    144     COFF_SCL_FCN = 101,         /* ".bf" or ".ef"               */
    145     COFF_SCL_EOS = 102,         /* end of structure             */
    146     COFF_SCL_FILE = 103,        /* file name                    */
    147     COFF_SCL_LINE = 104,        /* line # reformatted as symbol table entry */
    148     COFF_SCL_ALIAS = 105,       /* duplicate tag                */
    149     COFF_SCL_HIDDEN = 106       /* ext symbol in dmert public lib */
    150 } coff_symrec_sclass;
    151 
    152 typedef union coff_symtab_auxent {
    153     /* no data needed for section symbol auxent, all info avail from sym */
    154     /*@owned@*/ char *fname;        /* filename aux entry */
    155 } coff_symtab_auxent;
    156 
    157 typedef enum coff_symtab_auxtype {
    158     COFF_SYMTAB_AUX_NONE = 0,
    159     COFF_SYMTAB_AUX_SECT,
    160     COFF_SYMTAB_AUX_FILE
    161 } coff_symtab_auxtype;
    162 
    163 typedef struct coff_symrec_data {
    164     int forcevis;                       /* force visibility in symbol table */
    165     unsigned long index;                /* assigned COFF symbol table index */
    166     unsigned int type;                  /* type */
    167     coff_symrec_sclass sclass;          /* storage class */
    168 
    169     int numaux;                 /* number of auxiliary entries */
    170     coff_symtab_auxtype auxtype;    /* type of aux entries */
    171     coff_symtab_auxent aux[1];  /* actually may be any size (including 0) */
    172 } coff_symrec_data;
    173 
    174 typedef struct yasm_objfmt_coff {
    175     yasm_objfmt_base objfmt;                /* base structure */
    176 
    177     unsigned int parse_scnum;               /* sect numbering in parser */
    178     int win32;                              /* nonzero for win32/64 output */
    179     int win64;                              /* nonzero for win64 output */
    180 
    181     unsigned int machine;                   /* COFF machine to use */
    182 
    183     coff_symrec_data *filesym_data;         /* Data for .file symbol */
    184 
    185     /* data for .def/.endef and related directives */
    186     coff_symrec_data *def_sym;              /* symbol specified by .def */
    187 
    188     /* data for win64 proc_frame and related directives */
    189     unsigned long proc_frame;   /* Line number of start of proc, or 0 */
    190     unsigned long done_prolog;  /* Line number of end of prologue, or 0 */
    191     /*@null@*/ coff_unwind_info *unwind;        /* Unwind info */
    192 
    193     yasm_symrec *ssym_imagebase;            /* ..imagebase symbol for win64 */
    194 } yasm_objfmt_coff;
    195 
    196 typedef struct coff_objfmt_output_info {
    197     yasm_object *object;
    198     yasm_objfmt_coff *objfmt_coff;
    199     yasm_errwarns *errwarns;
    200     /*@dependent@*/ FILE *f;
    201     /*@only@*/ unsigned char *buf;
    202     yasm_section *sect;
    203     /*@dependent@*/ coff_section_data *csd;
    204     unsigned long addr;                 /* start of next section */
    205 
    206     unsigned long indx;                 /* current symbol index */
    207     int all_syms;                       /* outputting all symbols? */
    208     unsigned long strtab_offset;        /* current string table offset */
    209 } coff_objfmt_output_info;
    210 
    211 static void coff_section_data_destroy(/*@only@*/ void *d);
    212 static void coff_section_data_print(void *data, FILE *f, int indent_level);
    213 
    214 static const yasm_assoc_data_callback coff_section_data_cb = {
    215     coff_section_data_destroy,
    216     coff_section_data_print
    217 };
    218 
    219 static void coff_symrec_data_destroy(/*@only@*/ void *d);
    220 static void coff_symrec_data_print(void *data, FILE *f, int indent_level);
    221 
    222 static const yasm_assoc_data_callback coff_symrec_data_cb = {
    223     coff_symrec_data_destroy,
    224     coff_symrec_data_print
    225 };
    226 
    227 /* Bytecode callback function prototypes */
    228 static void win32_sxdata_bc_destroy(void *contents);
    229 static void win32_sxdata_bc_print(const void *contents, FILE *f,
    230                                   int indent_level);
    231 static int win32_sxdata_bc_calc_len
    232     (yasm_bytecode *bc, yasm_bc_add_span_func add_span, void *add_span_data);
    233 static int win32_sxdata_bc_tobytes
    234     (yasm_bytecode *bc, unsigned char **bufp, unsigned char *bufstart, void *d,
    235      yasm_output_value_func output_value,
    236      /*@null@*/ yasm_output_reloc_func output_reloc);
    237 
    238 /* Bytecode callback structures */
    239 static const yasm_bytecode_callback win32_sxdata_bc_callback = {
    240     win32_sxdata_bc_destroy,
    241     win32_sxdata_bc_print,
    242     yasm_bc_finalize_common,
    243     NULL,
    244     win32_sxdata_bc_calc_len,
    245     yasm_bc_expand_common,
    246     win32_sxdata_bc_tobytes,
    247     0
    248 };
    249 
    250 yasm_objfmt_module yasm_coff_LTX_objfmt;
    251 yasm_objfmt_module yasm_win32_LTX_objfmt;
    252 yasm_objfmt_module yasm_win64_LTX_objfmt;
    253 
    254 
    255 static /*@dependent@*/ coff_symrec_data *
    256 coff_objfmt_sym_set_data(yasm_symrec *sym, coff_symrec_sclass sclass,
    257                          int numaux, coff_symtab_auxtype auxtype)
    258 {
    259     coff_symrec_data *sym_data;
    260 
    261     sym_data = yasm_xmalloc(sizeof(coff_symrec_data) +
    262                             (numaux-1)*sizeof(coff_symtab_auxent));
    263     sym_data->forcevis = 0;
    264     sym_data->index = 0;
    265     sym_data->type = 0;
    266     sym_data->sclass = sclass;
    267     sym_data->numaux = numaux;
    268     sym_data->auxtype = auxtype;
    269 
    270     yasm_symrec_add_data(sym, &coff_symrec_data_cb, sym_data);
    271 
    272     return sym_data;
    273 }
    274 
    275 static yasm_objfmt_coff *
    276 coff_common_create(yasm_object *object)
    277 {
    278     yasm_objfmt_coff *objfmt_coff = yasm_xmalloc(sizeof(yasm_objfmt_coff));
    279     yasm_symrec *filesym;
    280 
    281     /* Only support x86 arch */
    282     if (yasm__strcasecmp(yasm_arch_keyword(object->arch), "x86") != 0) {
    283         yasm_xfree(objfmt_coff);
    284         return NULL;
    285     }
    286 
    287     objfmt_coff->parse_scnum = 1;    /* section numbering starts at 1 */
    288 
    289     /* FIXME: misuse of NULL bytecode here; it works, but only barely. */
    290     filesym = yasm_symtab_define_special(object->symtab, ".file",
    291                                          YASM_SYM_GLOBAL);
    292     objfmt_coff->filesym_data =
    293         coff_objfmt_sym_set_data(filesym, COFF_SCL_FILE, 1,
    294                                  COFF_SYMTAB_AUX_FILE);
    295     /* Filename is set in coff_objfmt_output */
    296     objfmt_coff->filesym_data->aux[0].fname = NULL;
    297 
    298     objfmt_coff->proc_frame = 0;
    299     objfmt_coff->done_prolog = 0;
    300     objfmt_coff->unwind = NULL;
    301     objfmt_coff->ssym_imagebase = NULL;
    302 
    303     return objfmt_coff;
    304 }
    305 
    306 static yasm_objfmt *
    307 coff_objfmt_create(yasm_object *object)
    308 {
    309     yasm_objfmt_coff *objfmt_coff = coff_common_create(object);
    310 
    311     if (objfmt_coff) {
    312         /* Support x86 and amd64 machines of x86 arch */
    313         if (yasm__strcasecmp(yasm_arch_get_machine(object->arch), "x86") == 0)
    314             objfmt_coff->machine = COFF_MACHINE_I386;
    315         else if (yasm__strcasecmp(yasm_arch_get_machine(object->arch),
    316                                   "amd64") == 0)
    317             objfmt_coff->machine = COFF_MACHINE_AMD64;
    318         else {
    319             yasm_xfree(objfmt_coff);
    320             return NULL;
    321         }
    322 
    323         objfmt_coff->objfmt.module = &yasm_coff_LTX_objfmt;
    324         objfmt_coff->win32 = 0;
    325         objfmt_coff->win64 = 0;
    326     }
    327     return (yasm_objfmt *)objfmt_coff;
    328 }
    329 
    330 static yasm_objfmt *
    331 win32_objfmt_create(yasm_object *object)
    332 {
    333     yasm_objfmt_coff *objfmt_coff = coff_common_create(object);
    334 
    335     if (objfmt_coff) {
    336         /* Support x86 and amd64 machines of x86 arch.
    337          * (amd64 machine supported for backwards compatibility)
    338          */
    339         if (yasm__strcasecmp(yasm_arch_get_machine(object->arch),
    340                              "x86") == 0) {
    341             objfmt_coff->machine = COFF_MACHINE_I386;
    342             objfmt_coff->objfmt.module = &yasm_win32_LTX_objfmt;
    343             objfmt_coff->win64 = 0;
    344         } else if (yasm__strcasecmp(yasm_arch_get_machine(object->arch),
    345                                     "amd64") == 0) {
    346             objfmt_coff->machine = COFF_MACHINE_AMD64;
    347             objfmt_coff->objfmt.module = &yasm_win64_LTX_objfmt;
    348             objfmt_coff->win64 = 1;
    349         } else {
    350             yasm_xfree(objfmt_coff);
    351             return NULL;
    352         }
    353 
    354         objfmt_coff->win32 = 1;
    355         /* Define a @feat.00 symbol for win32 safeseh handling */
    356         if (!objfmt_coff->win64) {
    357             yasm_symrec *feat00;
    358             coff_symrec_data *sym_data;
    359             feat00 = yasm_symtab_define_equ(object->symtab, "@feat.00",
    360                 yasm_expr_create_ident(yasm_expr_int(
    361                     yasm_intnum_create_uint(1)), 0), 0);
    362             sym_data = coff_objfmt_sym_set_data(feat00, COFF_SCL_STAT, 0,
    363                                                 COFF_SYMTAB_AUX_NONE);
    364             sym_data->forcevis = 1;
    365         }
    366     }
    367     return (yasm_objfmt *)objfmt_coff;
    368 }
    369 
    370 static yasm_objfmt *
    371 win64_objfmt_create(yasm_object *object)
    372 {
    373     yasm_objfmt_coff *objfmt_coff = coff_common_create(object);
    374 
    375     if (objfmt_coff) {
    376         /* Support amd64 machine of x86 arch */
    377         if (yasm__strcasecmp(yasm_arch_get_machine(object->arch),
    378                              "amd64") == 0) {
    379             objfmt_coff->machine = COFF_MACHINE_AMD64;
    380         } else {
    381             yasm_xfree(objfmt_coff);
    382             return NULL;
    383         }
    384 
    385         objfmt_coff->objfmt.module = &yasm_win64_LTX_objfmt;
    386         objfmt_coff->win32 = 1;
    387         objfmt_coff->win64 = 1;
    388         objfmt_coff->ssym_imagebase =
    389             yasm_symtab_define_label(object->symtab, "..imagebase", NULL, 0, 0);
    390     }
    391     return (yasm_objfmt *)objfmt_coff;
    392 }
    393 
    394 static void
    395 coff_objfmt_init_new_section(yasm_section *sect, unsigned long line)
    396 {
    397     yasm_object *object = yasm_section_get_object(sect);
    398     const char *sectname = yasm_section_get_name(sect);
    399     yasm_objfmt_coff *objfmt_coff = (yasm_objfmt_coff *)object->objfmt;
    400     coff_section_data *data;
    401     yasm_symrec *sym;
    402 
    403     data = yasm_xmalloc(sizeof(coff_section_data));
    404     data->scnum = objfmt_coff->parse_scnum++;
    405     data->flags = 0;
    406     data->addr = 0;
    407     data->scnptr = 0;
    408     data->size = 0;
    409     data->relptr = 0;
    410     data->nreloc = 0;
    411     data->flags2 = 0;
    412     data->strtab_name = 0;
    413     data->isdebug = 0;
    414 
    415     if (yasm__strncasecmp(sectname, ".debug", 6)==0) {
    416         data->flags = COFF_STYP_DATA;
    417         if (objfmt_coff->win32)
    418             data->flags |= COFF_STYP_DISCARD|COFF_STYP_READ;
    419         data->isdebug = 1;
    420     } else
    421         data->flags = COFF_STYP_TEXT;
    422 
    423     yasm_section_add_data(sect, &coff_section_data_cb, data);
    424 
    425     sym = yasm_symtab_define_label(object->symtab, sectname,
    426                                    yasm_section_bcs_first(sect), 1, line);
    427     yasm_symrec_declare(sym, YASM_SYM_GLOBAL, line);
    428     coff_objfmt_sym_set_data(sym, COFF_SCL_STAT, 1, COFF_SYMTAB_AUX_SECT);
    429     data->sym = sym;
    430 }
    431 
    432 static int
    433 coff_objfmt_set_section_addr(yasm_section *sect, /*@null@*/ void *d)
    434 {
    435     /*@null@*/ coff_objfmt_output_info *info = (coff_objfmt_output_info *)d;
    436     /*@dependent@*/ /*@null@*/ coff_section_data *csd;
    437 
    438     assert(info != NULL);
    439     csd = yasm_section_get_data(sect, &coff_section_data_cb);
    440     assert(csd != NULL);
    441 
    442     csd->addr = info->addr;
    443     info->addr += yasm_bc_next_offset(yasm_section_bcs_last(sect));
    444 
    445     return 0;
    446 }
    447 
    448 static int
    449 coff_objfmt_output_value(yasm_value *value, unsigned char *buf,
    450                          unsigned int destsize, unsigned long offset,
    451                          yasm_bytecode *bc, int warn, /*@null@*/ void *d)
    452 {
    453     /*@null@*/ coff_objfmt_output_info *info = (coff_objfmt_output_info *)d;
    454     yasm_objfmt_coff *objfmt_coff;
    455     /*@only@*/ /*@null@*/ yasm_intnum *dist = NULL;
    456     /*@dependent@*/ /*@null@*/ yasm_intnum *intn;
    457     unsigned long intn_val, intn_minus;
    458     int retval;
    459     unsigned int valsize = value->size;
    460 
    461     assert(info != NULL);
    462     objfmt_coff = info->objfmt_coff;
    463 
    464     if (value->abs)
    465         value->abs = yasm_expr_simplify(value->abs, 1);
    466 
    467     /* Try to output constant and PC-relative section-local first.
    468      * Note this does NOT output any value with a SEG, WRT, external,
    469      * cross-section, or non-PC-relative reference (those are handled below).
    470      */
    471     switch (yasm_value_output_basic(value, buf, destsize, bc, warn,
    472                                     info->object->arch)) {
    473         case -1:
    474             return 1;
    475         case 0:
    476             break;
    477         default:
    478             return 0;
    479     }
    480 
    481     /* Handle other expressions, with relocation if necessary */
    482     if (value->rshift > 0
    483         || (value->seg_of && (value->wrt || value->curpos_rel))
    484         || (value->section_rel && (value->wrt || value->curpos_rel))) {
    485         yasm_error_set(YASM_ERROR_TOO_COMPLEX,
    486                        N_("coff: relocation too complex"));
    487         return 1;
    488     }
    489 
    490     intn_val = 0;
    491     intn_minus = 0;
    492     if (value->rel) {
    493         yasm_sym_vis vis = yasm_symrec_get_visibility(value->rel);
    494         /*@dependent@*/ /*@null@*/ yasm_symrec *sym = value->rel;
    495         unsigned long addr;
    496         coff_reloc *reloc;
    497         int nobase = info->csd->flags2 & COFF_FLAG_NOBASE;
    498 
    499         /* Sometimes we want the relocation to be generated against one
    500          * symbol but the value generated correspond to a different symbol.
    501          * This is done through (sym being referenced) WRT (sym used for
    502          * reloc).  Note both syms need to be in the same section!
    503          */
    504         if (value->wrt && value->wrt == objfmt_coff->ssym_imagebase)
    505             nobase = 1;
    506         else if (value->wrt) {
    507             /*@dependent@*/ /*@null@*/ yasm_bytecode *rel_precbc, *wrt_precbc;
    508 
    509             if (!yasm_symrec_get_label(sym, &rel_precbc)
    510                 || !yasm_symrec_get_label(value->wrt, &wrt_precbc)) {
    511                 yasm_error_set(YASM_ERROR_TOO_COMPLEX,
    512                                N_("coff: wrt expression too complex"));
    513                 return 1;
    514             }
    515             dist = yasm_calc_bc_dist(wrt_precbc, rel_precbc);
    516             if (!dist) {
    517                 yasm_error_set(YASM_ERROR_TOO_COMPLEX,
    518                                N_("coff: cannot wrt across sections"));
    519                 return 1;
    520             }
    521             sym = value->wrt;
    522         }
    523 
    524         if (vis & YASM_SYM_COMMON) {
    525             /* In standard COFF, COMMON symbols have their length added in */
    526             if (!objfmt_coff->win32) {
    527                 /*@dependent@*/ /*@null@*/ coff_symrec_data *csymd;
    528                 /*@dependent@*/ /*@null@*/ yasm_expr **csize_expr;
    529                 /*@dependent@*/ /*@null@*/ yasm_intnum *common_size;
    530 
    531                 csymd = yasm_symrec_get_data(sym, &coff_symrec_data_cb);
    532                 assert(csymd != NULL);
    533                 csize_expr = yasm_symrec_get_common_size(sym);
    534                 assert(csize_expr != NULL);
    535                 common_size = yasm_expr_get_intnum(csize_expr, 1);
    536                 if (!common_size) {
    537                     yasm_error_set(YASM_ERROR_TOO_COMPLEX,
    538                                    N_("coff: common size too complex"));
    539                     return 1;
    540                 }
    541 
    542                 if (yasm_intnum_sign(common_size) < 0) {
    543                     yasm_error_set(YASM_ERROR_VALUE,
    544                                    N_("coff: common size is negative"));
    545                     return 1;
    546                 }
    547 
    548                 intn_val += yasm_intnum_get_uint(common_size);
    549             }
    550         } else if (!(vis & YASM_SYM_EXTERN) && !objfmt_coff->win64) {
    551             /*@dependent@*/ /*@null@*/ yasm_bytecode *sym_precbc;
    552 
    553             /* Local symbols need relocation to their section's start */
    554             if (yasm_symrec_get_label(sym, &sym_precbc)) {
    555                 yasm_section *sym_sect = yasm_bc_get_section(sym_precbc);
    556                 /*@null@*/ coff_section_data *sym_csd;
    557                 sym_csd = yasm_section_get_data(sym_sect,
    558                                                 &coff_section_data_cb);
    559                 assert(sym_csd != NULL);
    560                 sym = sym_csd->sym;
    561                 intn_val = yasm_bc_next_offset(sym_precbc);
    562                 if (COFF_SET_VMA)
    563                     intn_val += sym_csd->addr;
    564             }
    565         }
    566 
    567         if (value->curpos_rel) {
    568             /* For standard COFF, need to adjust to start of section, e.g.
    569              * subtract out the bytecode offset.
    570              * For Win32 COFF, need to adjust based on value size and position.
    571              * For Win64 COFF that's IP-relative, adjust to next bytecode;
    572              * the difference between the offset+destsize and BC length is
    573              * taken care of by special relocation types.
    574              */
    575             if (objfmt_coff->win64 && value->ip_rel)
    576                 intn_val += bc->len*bc->mult_int;
    577             else if (objfmt_coff->win32)
    578                 intn_val += offset+destsize;
    579             else
    580                 intn_minus = bc->offset;
    581         }
    582 
    583         if (value->seg_of) {
    584             /* Segment generation; zero value. */
    585             intn_val = 0;
    586             intn_minus = 0;
    587         }
    588 
    589         /* Generate reloc */
    590         reloc = yasm_xmalloc(sizeof(coff_reloc));
    591         addr = bc->offset + offset;
    592         if (COFF_SET_VMA)
    593             addr += info->addr;
    594         reloc->reloc.addr = yasm_intnum_create_uint(addr);
    595         reloc->reloc.sym = sym;
    596 
    597         if (value->curpos_rel) {
    598             if (objfmt_coff->machine == COFF_MACHINE_I386) {
    599                 if (valsize == 32)
    600                     reloc->type = COFF_RELOC_I386_REL32;
    601                 else {
    602                     yasm_error_set(YASM_ERROR_TYPE,
    603                                    N_("coff: invalid relocation size"));
    604                     return 1;
    605                 }
    606             } else if (objfmt_coff->machine == COFF_MACHINE_AMD64) {
    607                 if (valsize != 32) {
    608                     yasm_error_set(YASM_ERROR_TYPE,
    609                                    N_("coff: invalid relocation size"));
    610                     return 1;
    611                 }
    612                 if (!value->ip_rel)
    613                     reloc->type = COFF_RELOC_AMD64_REL32;
    614                 else switch (bc->len*bc->mult_int - (offset+destsize)) {
    615                     case 0:
    616                         reloc->type = COFF_RELOC_AMD64_REL32;
    617                         break;
    618                     case 1:
    619                         reloc->type = COFF_RELOC_AMD64_REL32_1;
    620                         break;
    621                     case 2:
    622                         reloc->type = COFF_RELOC_AMD64_REL32_2;
    623                         break;
    624                     case 3:
    625                         reloc->type = COFF_RELOC_AMD64_REL32_3;
    626                         break;
    627                     case 4:
    628                         reloc->type = COFF_RELOC_AMD64_REL32_4;
    629                         break;
    630                     case 5:
    631                         reloc->type = COFF_RELOC_AMD64_REL32_5;
    632                         break;
    633                     default:
    634                         yasm_error_set(YASM_ERROR_TYPE,
    635                                        N_("coff: invalid relocation size"));
    636                         return 1;
    637                 }
    638             } else
    639                 yasm_internal_error(N_("coff objfmt: unrecognized machine"));
    640         } else if (value->seg_of) {
    641             if (objfmt_coff->machine == COFF_MACHINE_I386)
    642                 reloc->type = COFF_RELOC_I386_SECTION;
    643             else if (objfmt_coff->machine == COFF_MACHINE_AMD64)
    644                 reloc->type = COFF_RELOC_AMD64_SECTION;
    645             else
    646                 yasm_internal_error(N_("coff objfmt: unrecognized machine"));
    647         } else if (value->section_rel) {
    648             if (objfmt_coff->machine == COFF_MACHINE_I386)
    649                 reloc->type = COFF_RELOC_I386_SECREL;
    650             else if (objfmt_coff->machine == COFF_MACHINE_AMD64)
    651                 reloc->type = COFF_RELOC_AMD64_SECREL;
    652             else
    653                 yasm_internal_error(N_("coff objfmt: unrecognized machine"));
    654         } else {
    655             if (objfmt_coff->machine == COFF_MACHINE_I386) {
    656                 if (nobase)
    657                     reloc->type = COFF_RELOC_I386_ADDR32NB;
    658                 else
    659                     reloc->type = COFF_RELOC_I386_ADDR32;
    660             } else if (objfmt_coff->machine == COFF_MACHINE_AMD64) {
    661                 if (valsize == 32) {
    662                     if (nobase)
    663                         reloc->type = COFF_RELOC_AMD64_ADDR32NB;
    664                     else
    665                         reloc->type = COFF_RELOC_AMD64_ADDR32;
    666                 } else if (valsize == 64)
    667                     reloc->type = COFF_RELOC_AMD64_ADDR64;
    668                 else {
    669                     yasm_error_set(YASM_ERROR_TYPE,
    670                                    N_("coff: invalid relocation size"));
    671                     return 1;
    672                 }
    673             } else
    674                 yasm_internal_error(N_("coff objfmt: unrecognized machine"));
    675         }
    676         info->csd->nreloc++;
    677         yasm_section_add_reloc(info->sect, (yasm_reloc *)reloc, yasm_xfree);
    678     }
    679 
    680     /* Build up final integer output from intn_val, intn_minus, value->abs,
    681      * and dist.  We do all this at the end to avoid creating temporary
    682      * intnums above (except for dist).
    683      */
    684     if (intn_minus <= intn_val)
    685         intn = yasm_intnum_create_uint(intn_val-intn_minus);
    686     else {
    687         intn = yasm_intnum_create_uint(intn_minus-intn_val);
    688         yasm_intnum_calc(intn, YASM_EXPR_NEG, NULL);
    689     }
    690 
    691     if (value->abs) {
    692         yasm_intnum *intn2 = yasm_expr_get_intnum(&value->abs, 0);
    693         if (!intn2) {
    694             yasm_error_set(YASM_ERROR_TOO_COMPLEX,
    695                            N_("coff: relocation too complex"));
    696             yasm_intnum_destroy(intn);
    697             if (dist)
    698                 yasm_intnum_destroy(dist);
    699             return 1;
    700         }
    701         yasm_intnum_calc(intn, YASM_EXPR_ADD, intn2);
    702     }
    703 
    704     if (dist) {
    705         yasm_intnum_calc(intn, YASM_EXPR_ADD, dist);
    706         yasm_intnum_destroy(dist);
    707     }
    708 
    709     retval = yasm_arch_intnum_tobytes(info->object->arch, intn, buf, destsize,
    710                                       valsize, 0, bc, warn);
    711     yasm_intnum_destroy(intn);
    712     return retval;
    713 }
    714 
    715 static int
    716 coff_objfmt_output_bytecode(yasm_bytecode *bc, /*@null@*/ void *d)
    717 {
    718     /*@null@*/ coff_objfmt_output_info *info = (coff_objfmt_output_info *)d;
    719     /*@null@*/ /*@only@*/ unsigned char *bigbuf;
    720     unsigned long size = REGULAR_OUTBUF_SIZE;
    721     int gap;
    722 
    723     assert(info != NULL);
    724 
    725     bigbuf = yasm_bc_tobytes(bc, info->buf, &size, &gap, info,
    726                              coff_objfmt_output_value, NULL);
    727 
    728     /* Don't bother doing anything else if size ended up being 0. */
    729     if (size == 0) {
    730         if (bigbuf)
    731             yasm_xfree(bigbuf);
    732         return 0;
    733     }
    734 
    735     info->csd->size += size;
    736 
    737     /* Warn that gaps are converted to 0 and write out the 0's. */
    738     if (gap) {
    739         unsigned long left;
    740         yasm_warn_set(YASM_WARN_UNINIT_CONTENTS,
    741             N_("uninitialized space declared in code/data section: zeroing"));
    742         /* Write out in chunks */
    743         memset(info->buf, 0, REGULAR_OUTBUF_SIZE);
    744         left = size;
    745         while (left > REGULAR_OUTBUF_SIZE) {
    746             fwrite(info->buf, REGULAR_OUTBUF_SIZE, 1, info->f);
    747             left -= REGULAR_OUTBUF_SIZE;
    748         }
    749         fwrite(info->buf, left, 1, info->f);
    750     } else {
    751         /* Output buf (or bigbuf if non-NULL) to file */
    752         fwrite(bigbuf ? bigbuf : info->buf, (size_t)size, 1, info->f);
    753     }
    754 
    755     /* If bigbuf was allocated, free it */
    756     if (bigbuf)
    757         yasm_xfree(bigbuf);
    758 
    759     return 0;
    760 }
    761 
    762 static int
    763 coff_objfmt_output_section(yasm_section *sect, /*@null@*/ void *d)
    764 {
    765     /*@null@*/ coff_objfmt_output_info *info = (coff_objfmt_output_info *)d;
    766     /*@dependent@*/ /*@null@*/ coff_section_data *csd;
    767     long pos;
    768     coff_reloc *reloc;
    769     unsigned char *localbuf;
    770 
    771     assert(info != NULL);
    772     csd = yasm_section_get_data(sect, &coff_section_data_cb);
    773     assert(csd != NULL);
    774 
    775     /* Add to strtab if in win32 format and name > 8 chars */
    776     if (info->objfmt_coff->win32) {
    777         size_t namelen = strlen(yasm_section_get_name(sect));
    778         if (namelen > 8) {
    779             csd->strtab_name = info->strtab_offset;
    780             info->strtab_offset += (unsigned long)(namelen + 1);
    781         }
    782     }
    783 
    784     if (!csd->isdebug)
    785         csd->addr = info->addr;
    786 
    787     if ((csd->flags & COFF_STYP_STD_MASK) == COFF_STYP_BSS) {
    788         /* Don't output BSS sections.
    789          * TODO: Check for non-reserve bytecodes?
    790          */
    791         pos = 0;    /* position = 0 because it's not in the file */
    792         csd->size = yasm_bc_next_offset(yasm_section_bcs_last(sect));
    793     } else {
    794         pos = ftell(info->f);
    795         if (pos == -1) {
    796             yasm__fatal(N_("could not get file position on output file"));
    797             /*@notreached@*/
    798             return 1;
    799         }
    800 
    801         info->sect = sect;
    802         info->csd = csd;
    803         yasm_section_bcs_traverse(sect, info->errwarns, info,
    804                                   coff_objfmt_output_bytecode);
    805 
    806         /* Sanity check final section size */
    807         if (yasm_errwarns_num_errors(info->errwarns, 0) == 0 &&
    808             csd->size != yasm_bc_next_offset(yasm_section_bcs_last(sect)))
    809             yasm_internal_error(
    810                 N_("coff: section computed size did not match actual size"));
    811     }
    812 
    813     /* Empty?  Go on to next section */
    814     if (csd->size == 0)
    815         return 0;
    816 
    817     if (!csd->isdebug)
    818         info->addr += csd->size;
    819     csd->scnptr = (unsigned long)pos;
    820 
    821     /* No relocations to output?  Go on to next section */
    822     if (csd->nreloc == 0)
    823         return 0;
    824 
    825     pos = ftell(info->f);
    826     if (pos == -1) {
    827         yasm__fatal(N_("could not get file position on output file"));
    828         /*@notreached@*/
    829         return 1;
    830     }
    831     csd->relptr = (unsigned long)pos;
    832 
    833     /* If >=64K relocs (for Win32/64), we set a flag in the section header
    834      * (NRELOC_OVFL) and the first relocation contains the number of relocs.
    835      */
    836     if (csd->nreloc >= 64*1024 && info->objfmt_coff->win32) {
    837         localbuf = info->buf;
    838         YASM_WRITE_32_L(localbuf, csd->nreloc+1);   /* address of relocation */
    839         YASM_WRITE_32_L(localbuf, 0);           /* relocated symbol */
    840         YASM_WRITE_16_L(localbuf, 0);           /* type of relocation */
    841         fwrite(info->buf, 10, 1, info->f);
    842     }
    843 
    844     reloc = (coff_reloc *)yasm_section_relocs_first(sect);
    845     while (reloc) {
    846         /*@null@*/ coff_symrec_data *csymd;
    847         localbuf = info->buf;
    848 
    849         csymd = yasm_symrec_get_data(reloc->reloc.sym, &coff_symrec_data_cb);
    850         if (!csymd)
    851             yasm_internal_error(
    852                 N_("coff: no symbol data for relocated symbol"));
    853 
    854         yasm_intnum_get_sized(reloc->reloc.addr, localbuf, 4, 32, 0, 0, 0);
    855         localbuf += 4;                          /* address of relocation */
    856         YASM_WRITE_32_L(localbuf, csymd->index);    /* relocated symbol */
    857         YASM_WRITE_16_L(localbuf, reloc->type);     /* type of relocation */
    858         fwrite(info->buf, 10, 1, info->f);
    859 
    860         reloc = (coff_reloc *)yasm_section_reloc_next((yasm_reloc *)reloc);
    861     }
    862 
    863     return 0;
    864 }
    865 
    866 static int
    867 coff_objfmt_output_sectstr(yasm_section *sect, /*@null@*/ void *d)
    868 {
    869     /*@null@*/ coff_objfmt_output_info *info = (coff_objfmt_output_info *)d;
    870     const char *name;
    871     size_t len;
    872 
    873     /* Add to strtab if in win32 format and name > 8 chars */
    874     if (!info->objfmt_coff->win32)
    875        return 0;
    876 
    877     name = yasm_section_get_name(sect);
    878     len = strlen(name);
    879     if (len > 8)
    880         fwrite(name, len+1, 1, info->f);
    881     return 0;
    882 }
    883 
    884 static int
    885 coff_objfmt_output_secthead(yasm_section *sect, /*@null@*/ void *d)
    886 {
    887     /*@null@*/ coff_objfmt_output_info *info = (coff_objfmt_output_info *)d;
    888     yasm_objfmt_coff *objfmt_coff;
    889     /*@dependent@*/ /*@null@*/ coff_section_data *csd;
    890     unsigned char *localbuf;
    891     unsigned long align = yasm_section_get_align(sect);
    892 
    893     assert(info != NULL);
    894     objfmt_coff = info->objfmt_coff;
    895     csd = yasm_section_get_data(sect, &coff_section_data_cb);
    896     assert(csd != NULL);
    897 
    898     /* Check to see if alignment is supported size */
    899     if (align > 8192)
    900         align = 8192;
    901 
    902     /* Convert alignment into flags setting */
    903     csd->flags &= ~COFF_STYP_ALIGN_MASK;
    904     while (align != 0) {
    905         csd->flags += 1<<COFF_STYP_ALIGN_SHIFT;
    906         align >>= 1;
    907     }
    908 
    909     /* section name */
    910     localbuf = info->buf;
    911     if (strlen(yasm_section_get_name(sect)) > 8) {
    912         char namenum[30];
    913         sprintf(namenum, "/%ld", csd->strtab_name);
    914         strncpy((char *)localbuf, namenum, 8);
    915     } else
    916         strncpy((char *)localbuf, yasm_section_get_name(sect), 8);
    917     localbuf += 8;
    918     if (csd->isdebug) {
    919         YASM_WRITE_32_L(localbuf, 0);           /* physical address */
    920         YASM_WRITE_32_L(localbuf, 0);           /* virtual address */
    921     } else {
    922         YASM_WRITE_32_L(localbuf, csd->addr);   /* physical address */
    923         if (COFF_SET_VMA)
    924             YASM_WRITE_32_L(localbuf, csd->addr);/* virtual address */
    925         else
    926             YASM_WRITE_32_L(localbuf, 0);       /* virtual address */
    927     }
    928     YASM_WRITE_32_L(localbuf, csd->size);       /* section size */
    929     YASM_WRITE_32_L(localbuf, csd->scnptr);     /* file ptr to data */
    930     YASM_WRITE_32_L(localbuf, csd->relptr);     /* file ptr to relocs */
    931     YASM_WRITE_32_L(localbuf, 0);               /* file ptr to line nums */
    932     if (csd->nreloc >= 64*1024) {
    933         /* Win32/64 has special handling for this case. */
    934         if (objfmt_coff->win32)
    935             csd->flags |= COFF_STYP_NRELOC_OVFL;
    936         else {
    937             yasm_warn_set(YASM_WARN_GENERAL,
    938                           N_("too many relocations in section `%s'"),
    939                           yasm_section_get_name(sect));
    940             yasm_errwarn_propagate(info->errwarns, 0);
    941         }
    942         YASM_WRITE_16_L(localbuf, 0xFFFF);      /* max out */
    943     } else
    944         YASM_WRITE_16_L(localbuf, csd->nreloc); /* num of relocation entries */
    945     YASM_WRITE_16_L(localbuf, 0);               /* num of line number entries */
    946     YASM_WRITE_32_L(localbuf, csd->flags);      /* flags */
    947     fwrite(info->buf, 40, 1, info->f);
    948 
    949     return 0;
    950 }
    951 
    952 static int
    953 coff_objfmt_count_sym(yasm_symrec *sym, /*@null@*/ void *d)
    954 {
    955     /*@null@*/ coff_objfmt_output_info *info = (coff_objfmt_output_info *)d;
    956     yasm_sym_vis vis = yasm_symrec_get_visibility(sym);
    957     coff_symrec_data *sym_data;
    958 
    959     assert(info != NULL);
    960 
    961     sym_data = yasm_symrec_get_data(sym, &coff_symrec_data_cb);
    962 
    963     if (info->all_syms || vis != YASM_SYM_LOCAL || yasm_symrec_is_abs(sym) ||
    964         (sym_data && sym_data->forcevis)) {
    965         /* Save index in symrec data */
    966         if (!sym_data)
    967             sym_data = coff_objfmt_sym_set_data(sym, COFF_SCL_NULL, 0,
    968                                                 COFF_SYMTAB_AUX_NONE);
    969         /* Set storage class based on visibility if not already set */
    970         if (sym_data->sclass == COFF_SCL_NULL) {
    971             if (vis & (YASM_SYM_EXTERN|YASM_SYM_GLOBAL|YASM_SYM_COMMON))
    972                 sym_data->sclass = COFF_SCL_EXT;
    973             else
    974                 sym_data->sclass = COFF_SCL_STAT;
    975         }
    976 
    977         sym_data->index = info->indx;
    978 
    979         info->indx += sym_data->numaux + 1;
    980     }
    981     return 0;
    982 }
    983 
    984 static int
    985 coff_objfmt_output_sym(yasm_symrec *sym, /*@null@*/ void *d)
    986 {
    987     /*@null@*/ coff_objfmt_output_info *info = (coff_objfmt_output_info *)d;
    988     yasm_sym_vis vis = yasm_symrec_get_visibility(sym);
    989     int is_abs = yasm_symrec_is_abs(sym);
    990     /*@dependent@*/ /*@null@*/ coff_symrec_data *csymd;
    991     csymd = yasm_symrec_get_data(sym, &coff_symrec_data_cb);
    992 
    993     assert(info != NULL);
    994 
    995     /* Don't output local syms unless outputting all syms */
    996     if (info->all_syms || vis != YASM_SYM_LOCAL || is_abs ||
    997         (csymd && csymd->forcevis)) {
    998         /*@only*/ char *name;
    999         const yasm_expr *equ_val;
   1000         const yasm_intnum *intn;
   1001         unsigned char *localbuf;
   1002         size_t len;
   1003         int aux;
   1004         unsigned long value = 0;
   1005         unsigned int scnum = 0xfffe;    /* -2 = debugging symbol */
   1006         /*@dependent@*/ /*@null@*/ yasm_section *sect;
   1007         /*@dependent@*/ /*@null@*/ yasm_bytecode *precbc;
   1008         unsigned long scnlen = 0;   /* for sect auxent */
   1009         unsigned long nreloc = 0;   /* for sect auxent */
   1010         yasm_objfmt_coff *objfmt_coff = info->objfmt_coff;
   1011 
   1012         if (is_abs)
   1013             name = yasm__xstrdup(".absolut");
   1014         else
   1015             name = yasm_symrec_get_global_name(sym, info->object);
   1016         len = strlen(name);
   1017 
   1018         /* Get symrec's of_data (needed for storage class) */
   1019         if (!csymd)
   1020             yasm_internal_error(N_("coff: expected sym data to be present"));
   1021 
   1022         /* Look at symrec for value/scnum/etc. */
   1023         if (yasm_symrec_get_label(sym, &precbc)) {
   1024             if (precbc)
   1025                 sect = yasm_bc_get_section(precbc);
   1026             else
   1027                 sect = NULL;
   1028             /* it's a label: get value and offset.
   1029              * If there is not a section, leave as debugging symbol.
   1030              */
   1031             if (sect) {
   1032                 /*@dependent@*/ /*@null@*/ coff_section_data *csectd;
   1033                 csectd = yasm_section_get_data(sect, &coff_section_data_cb);
   1034                 if (csectd) {
   1035                     scnum = csectd->scnum;
   1036                     scnlen = csectd->size;
   1037                     nreloc = csectd->nreloc;
   1038                     if (COFF_SET_VMA)
   1039                         value = csectd->addr;
   1040                 } else
   1041                     yasm_internal_error(N_("didn't understand section"));
   1042                 if (precbc)
   1043                     value += yasm_bc_next_offset(precbc);
   1044             }
   1045         } else if ((equ_val = yasm_symrec_get_equ(sym))) {
   1046             yasm_expr *equ_val_copy = yasm_expr_copy(equ_val);
   1047             intn = yasm_expr_get_intnum(&equ_val_copy, 1);
   1048             if (!intn) {
   1049                 if (vis & YASM_SYM_GLOBAL) {
   1050                     yasm_error_set(YASM_ERROR_NOT_CONSTANT,
   1051                         N_("global EQU value not an integer expression"));
   1052                     yasm_errwarn_propagate(info->errwarns, equ_val->line);
   1053                 }
   1054             } else
   1055                 value = yasm_intnum_get_uint(intn);
   1056             yasm_expr_destroy(equ_val_copy);
   1057 
   1058             scnum = 0xffff;     /* -1 = absolute symbol */
   1059         } else {
   1060             if (vis & YASM_SYM_COMMON) {
   1061                 /*@dependent@*/ /*@null@*/ yasm_expr **csize_expr;
   1062                 csize_expr = yasm_symrec_get_common_size(sym);
   1063                 assert(csize_expr != NULL);
   1064                 intn = yasm_expr_get_intnum(csize_expr, 1);
   1065                 if (!intn) {
   1066                     yasm_error_set(YASM_ERROR_NOT_CONSTANT,
   1067                         N_("COMMON data size not an integer expression"));
   1068                     yasm_errwarn_propagate(info->errwarns,
   1069                                            (*csize_expr)->line);
   1070                 } else
   1071                     value = yasm_intnum_get_uint(intn);
   1072                 scnum = 0;
   1073             }
   1074             if (vis & YASM_SYM_EXTERN)
   1075                 scnum = 0;
   1076         }
   1077 
   1078         localbuf = info->buf;
   1079         if (len > 8) {
   1080             YASM_WRITE_32_L(localbuf, 0);       /* "zeros" field */
   1081             YASM_WRITE_32_L(localbuf, info->strtab_offset); /* strtab offset */
   1082             info->strtab_offset += (unsigned long)(len+1);
   1083         } else {
   1084             /* <8 chars, so no string table entry needed */
   1085             strncpy((char *)localbuf, name, 8);
   1086             localbuf += 8;
   1087         }
   1088         YASM_WRITE_32_L(localbuf, value);       /* value */
   1089         YASM_WRITE_16_L(localbuf, scnum);       /* section number */
   1090         YASM_WRITE_16_L(localbuf, csymd->type); /* type */
   1091         YASM_WRITE_8(localbuf, csymd->sclass);  /* storage class */
   1092         YASM_WRITE_8(localbuf, csymd->numaux);  /* number of aux entries */
   1093         fwrite(info->buf, 18, 1, info->f);
   1094         for (aux=0; aux<csymd->numaux; aux++) {
   1095             localbuf = info->buf;
   1096             memset(localbuf, 0, 18);
   1097             switch (csymd->auxtype) {
   1098                 case COFF_SYMTAB_AUX_NONE:
   1099                     break;
   1100                 case COFF_SYMTAB_AUX_SECT:
   1101                     YASM_WRITE_32_L(localbuf, scnlen);  /* section length */
   1102                     YASM_WRITE_16_L(localbuf, nreloc);  /* number relocs */
   1103                     YASM_WRITE_16_L(localbuf, 0);       /* number line nums */
   1104                     break;
   1105                 case COFF_SYMTAB_AUX_FILE:
   1106                     len = strlen(csymd->aux[0].fname);
   1107                     if (len > 14) {
   1108                         YASM_WRITE_32_L(localbuf, 0);
   1109                         YASM_WRITE_32_L(localbuf, info->strtab_offset);
   1110                         info->strtab_offset += (unsigned long)(len+1);
   1111                     } else
   1112                         strncpy((char *)localbuf, csymd->aux[0].fname, 14);
   1113                     break;
   1114                 default:
   1115                     yasm_internal_error(
   1116                         N_("coff: unrecognized aux symtab type"));
   1117             }
   1118             fwrite(info->buf, 18, 1, info->f);
   1119         }
   1120         yasm_xfree(name);
   1121     }
   1122     return 0;
   1123 }
   1124 
   1125 static int
   1126 coff_objfmt_output_str(yasm_symrec *sym, /*@null@*/ void *d)
   1127 {
   1128     /*@null@*/ coff_objfmt_output_info *info = (coff_objfmt_output_info *)d;
   1129     yasm_sym_vis vis = yasm_symrec_get_visibility(sym);
   1130     /*@dependent@*/ /*@null@*/ coff_symrec_data *csymd;
   1131     csymd = yasm_symrec_get_data(sym, &coff_symrec_data_cb);
   1132 
   1133     assert(info != NULL);
   1134 
   1135     /* Don't output local syms unless outputting all syms */
   1136     if (info->all_syms || vis != YASM_SYM_LOCAL ||
   1137         (csymd && csymd->forcevis)) {
   1138         /*@only@*/ char *name = yasm_symrec_get_global_name(sym, info->object);
   1139         size_t len = strlen(name);
   1140         int aux;
   1141 
   1142         if (!csymd)
   1143             yasm_internal_error(N_("coff: expected sym data to be present"));
   1144 
   1145         if (len > 8)
   1146             fwrite(name, len+1, 1, info->f);
   1147         for (aux=0; aux<csymd->numaux; aux++) {
   1148             switch (csymd->auxtype) {
   1149                 case COFF_SYMTAB_AUX_FILE:
   1150                     len = strlen(csymd->aux[0].fname);
   1151                     if (len > 14)
   1152                         fwrite(csymd->aux[0].fname, len+1, 1, info->f);
   1153                     break;
   1154                 default:
   1155                     break;
   1156             }
   1157         }
   1158         yasm_xfree(name);
   1159     }
   1160     return 0;
   1161 }
   1162 
   1163 static void
   1164 coff_objfmt_output(yasm_object *object, FILE *f, int all_syms,
   1165                    yasm_errwarns *errwarns)
   1166 {
   1167     yasm_objfmt_coff *objfmt_coff = (yasm_objfmt_coff *)object->objfmt;
   1168     coff_objfmt_output_info info;
   1169     unsigned char *localbuf;
   1170     long pos;
   1171     unsigned long symtab_pos;
   1172     unsigned long symtab_count;
   1173     unsigned int flags;
   1174     unsigned long ts;
   1175 
   1176     if (objfmt_coff->proc_frame) {
   1177         yasm_error_set_xref(objfmt_coff->proc_frame,
   1178                             N_("procedure started here"));
   1179         yasm_error_set(YASM_ERROR_GENERAL,
   1180                        N_("end of file in procedure frame"));
   1181         yasm_errwarn_propagate(errwarns, 0);
   1182         return;
   1183     }
   1184 
   1185     if (objfmt_coff->filesym_data->aux[0].fname)
   1186         yasm_xfree(objfmt_coff->filesym_data->aux[0].fname);
   1187     objfmt_coff->filesym_data->aux[0].fname =
   1188         yasm__xstrdup(object->src_filename);
   1189 
   1190     /* Force all syms for win64 because they're needed for relocations.
   1191      * FIXME: Not *all* syms need to be output, only the ones needed for
   1192      * relocation.  Find a way to do that someday.
   1193      */
   1194     all_syms |= objfmt_coff->win64;
   1195 
   1196     info.strtab_offset = 4;
   1197     info.object = object;
   1198     info.objfmt_coff = objfmt_coff;
   1199     info.errwarns = errwarns;
   1200     info.f = f;
   1201     info.buf = yasm_xmalloc(REGULAR_OUTBUF_SIZE);
   1202 
   1203     /* Allocate space for headers by seeking forward */
   1204     if (fseek(f, (long)(20+40*(objfmt_coff->parse_scnum-1)), SEEK_SET) < 0) {
   1205         yasm__fatal(N_("could not seek on output file"));
   1206         /*@notreached@*/
   1207         return;
   1208     }
   1209 
   1210     /* Finalize symbol table (assign index to each symbol) */
   1211     info.indx = 0;
   1212     info.all_syms = all_syms;
   1213     yasm_symtab_traverse(object->symtab, &info, coff_objfmt_count_sym);
   1214     symtab_count = info.indx;
   1215 
   1216     /* Section data/relocs */
   1217     if (COFF_SET_VMA) {
   1218         /* If we're setting the VMA, we need to do a first section pass to
   1219          * determine each section's addr value before actually outputting
   1220          * relocations, as a relocation's section address is added into the
   1221          * addends in the generated code.
   1222          */
   1223         info.addr = 0;
   1224         if (yasm_object_sections_traverse(object, &info,
   1225                                           coff_objfmt_set_section_addr))
   1226             return;
   1227     }
   1228     info.addr = 0;
   1229     if (yasm_object_sections_traverse(object, &info,
   1230                                       coff_objfmt_output_section))
   1231         return;
   1232 
   1233     /* Symbol table */
   1234     pos = ftell(f);
   1235     if (pos == -1) {
   1236         yasm__fatal(N_("could not get file position on output file"));
   1237         /*@notreached@*/
   1238         return;
   1239     }
   1240     symtab_pos = (unsigned long)pos;
   1241     yasm_symtab_traverse(object->symtab, &info, coff_objfmt_output_sym);
   1242 
   1243     /* String table */
   1244     yasm_fwrite_32_l(info.strtab_offset, f); /* total length */
   1245     yasm_object_sections_traverse(object, &info, coff_objfmt_output_sectstr);
   1246     yasm_symtab_traverse(object->symtab, &info, coff_objfmt_output_str);
   1247 
   1248     /* Write headers */
   1249     if (fseek(f, 0, SEEK_SET) < 0) {
   1250         yasm__fatal(N_("could not seek on output file"));
   1251         /*@notreached@*/
   1252         return;
   1253     }
   1254 
   1255     localbuf = info.buf;
   1256     YASM_WRITE_16_L(localbuf, objfmt_coff->machine);    /* magic number */
   1257     YASM_WRITE_16_L(localbuf, objfmt_coff->parse_scnum-1);/* number of sects */
   1258     if (getenv("YASM_TEST_SUITE"))
   1259         ts = 0;
   1260     else
   1261         ts = (unsigned long)time(NULL);
   1262     YASM_WRITE_32_L(localbuf, ts);                      /* time/date stamp */
   1263     YASM_WRITE_32_L(localbuf, symtab_pos);              /* file ptr to symtab */
   1264     YASM_WRITE_32_L(localbuf, symtab_count);            /* number of symtabs */
   1265     YASM_WRITE_16_L(localbuf, 0);       /* size of optional header (none) */
   1266     /* flags */
   1267     flags = 0;
   1268     if (strcmp(yasm_dbgfmt_keyword(object->dbgfmt), "null")==0)
   1269         flags = COFF_F_LNNO;
   1270     if (!all_syms)
   1271         flags |= COFF_F_LSYMS;
   1272     if (objfmt_coff->machine != COFF_MACHINE_AMD64)
   1273         flags |= COFF_F_AR32WR;
   1274     YASM_WRITE_16_L(localbuf, flags);
   1275     fwrite(info.buf, 20, 1, f);
   1276 
   1277     yasm_object_sections_traverse(object, &info, coff_objfmt_output_secthead);
   1278 
   1279     yasm_xfree(info.buf);
   1280 }
   1281 
   1282 static void
   1283 coff_objfmt_destroy(yasm_objfmt *objfmt)
   1284 {
   1285     yasm_objfmt_coff *objfmt_coff = (yasm_objfmt_coff *)objfmt;
   1286     if (objfmt_coff->filesym_data->aux[0].fname)
   1287         yasm_xfree(objfmt_coff->filesym_data->aux[0].fname);
   1288     if (objfmt_coff->unwind)
   1289         yasm_win64__uwinfo_destroy(objfmt_coff->unwind);
   1290     yasm_xfree(objfmt);
   1291 }
   1292 
   1293 static yasm_section *
   1294 coff_objfmt_add_default_section(yasm_object *object)
   1295 {
   1296     yasm_objfmt_coff *objfmt_coff = (yasm_objfmt_coff *)object->objfmt;
   1297     yasm_section *retval;
   1298     coff_section_data *csd;
   1299     int isnew;
   1300 
   1301     retval = yasm_object_get_general(object, ".text", 16, 1, 0, &isnew, 0);
   1302     if (isnew) {
   1303         csd = yasm_section_get_data(retval, &coff_section_data_cb);
   1304         csd->flags = COFF_STYP_TEXT;
   1305         if (objfmt_coff->win32)
   1306             csd->flags |= COFF_STYP_EXECUTE | COFF_STYP_READ;
   1307         yasm_section_set_default(retval, 1);
   1308     }
   1309     return retval;
   1310 }
   1311 
   1312 struct coff_section_switch_data {
   1313     int isdefault;
   1314     int gasflags;
   1315     unsigned long flags;
   1316     unsigned long flags2;
   1317     /*@only@*/ /*@null@*/ yasm_intnum *align_intn;
   1318 };
   1319 
   1320 /* GAS-style flags */
   1321 static int
   1322 coff_helper_gasflags(void *obj, yasm_valparam *vp, unsigned long line, void *d,
   1323                      /*@unused@*/ uintptr_t arg)
   1324 {
   1325     struct coff_section_switch_data *data =
   1326         (struct coff_section_switch_data *)d;
   1327     int alloc = 0, load = 0, readonly = 0, code = 0, datasect = 0;
   1328     int shared = 0;
   1329     const char *s = yasm_vp_string(vp);
   1330     size_t i;
   1331 
   1332     if (!s) {
   1333         yasm_error_set(YASM_ERROR_VALUE, N_("non-string section attribute"));
   1334         return -1;
   1335     }
   1336 
   1337     /* For GAS, default to read/write data */
   1338     if (data->isdefault)
   1339         data->flags = COFF_STYP_TEXT | COFF_STYP_READ | COFF_STYP_WRITE;
   1340 
   1341     for (i=0; i<strlen(s); i++) {
   1342         switch (s[i]) {
   1343             case 'a':
   1344                 break;
   1345             case 'b':
   1346                 alloc = 1;
   1347                 load = 0;
   1348                 break;
   1349             case 'n':
   1350                 load = 0;
   1351                 break;
   1352             case 's':
   1353                 shared = 1;
   1354                 /*@fallthrough@*/
   1355             case 'd':
   1356                 datasect = 1;
   1357                 load = 1;
   1358                 readonly = 0;
   1359             case 'x':
   1360                 code = 1;
   1361                 load = 1;
   1362                 break;
   1363             case 'r':
   1364                 datasect = 1;
   1365                 load = 1;
   1366                 readonly = 1;
   1367                 break;
   1368             case 'w':
   1369                 readonly = 0;
   1370                 break;
   1371             default:
   1372                 yasm_warn_set(YASM_WARN_GENERAL,
   1373                               N_("unrecognized section attribute: `%c'"),
   1374                               s[i]);
   1375         }
   1376     }
   1377 
   1378     if (code)
   1379         data->flags = COFF_STYP_TEXT | COFF_STYP_EXECUTE | COFF_STYP_READ;
   1380     else if (datasect)
   1381         data->flags = COFF_STYP_DATA | COFF_STYP_READ | COFF_STYP_WRITE;
   1382     else if (readonly)
   1383         data->flags = COFF_STYP_DATA | COFF_STYP_READ;
   1384     else if (load)
   1385         data->flags = COFF_STYP_TEXT;
   1386     else if (alloc)
   1387         data->flags = COFF_STYP_BSS;
   1388 
   1389     if (shared)
   1390         data->flags |= COFF_STYP_SHARED;
   1391 
   1392     data->gasflags = 1;
   1393     return 0;
   1394 }
   1395 
   1396 static /*@observer@*/ /*@null@*/ yasm_section *
   1397 coff_objfmt_section_switch(yasm_object *object, yasm_valparamhead *valparams,
   1398                             /*@unused@*/ /*@null@*/
   1399                             yasm_valparamhead *objext_valparams,
   1400                             unsigned long line)
   1401 {
   1402     yasm_objfmt_coff *objfmt_coff = (yasm_objfmt_coff *)object->objfmt;
   1403     yasm_valparam *vp;
   1404     yasm_section *retval;
   1405     int isnew;
   1406     int iscode = 0;
   1407     int flags_override;
   1408     const char *sectname;
   1409     char *realname;
   1410     int resonly = 0;
   1411     unsigned long align = 0;
   1412     coff_section_data *csd;
   1413 
   1414     struct coff_section_switch_data data;
   1415 
   1416     static const yasm_dir_help help[] = {
   1417         { "code", 0, yasm_dir_helper_flag_set,
   1418           offsetof(struct coff_section_switch_data, flags),
   1419           COFF_STYP_TEXT | COFF_STYP_EXECUTE | COFF_STYP_READ },
   1420         { "text", 0, yasm_dir_helper_flag_set,
   1421           offsetof(struct coff_section_switch_data, flags),
   1422           COFF_STYP_TEXT | COFF_STYP_EXECUTE | COFF_STYP_READ },
   1423         { "data", 0, yasm_dir_helper_flag_set,
   1424           offsetof(struct coff_section_switch_data, flags),
   1425           COFF_STYP_DATA | COFF_STYP_READ | COFF_STYP_WRITE },
   1426         { "rdata", 0, yasm_dir_helper_flag_set,
   1427           offsetof(struct coff_section_switch_data, flags),
   1428           COFF_STYP_DATA | COFF_STYP_READ },
   1429         { "bss", 0, yasm_dir_helper_flag_set,
   1430           offsetof(struct coff_section_switch_data, flags),
   1431           COFF_STYP_BSS | COFF_STYP_READ | COFF_STYP_WRITE },
   1432         { "info", 0, yasm_dir_helper_flag_set,
   1433           offsetof(struct coff_section_switch_data, flags),
   1434           COFF_STYP_INFO | COFF_STYP_DISCARD | COFF_STYP_READ },
   1435         { "gasflags", 1, coff_helper_gasflags, 0, 0 },
   1436         /* Win32 only below this point */
   1437         { "discard", 0, yasm_dir_helper_flag_or,
   1438           offsetof(struct coff_section_switch_data, flags), COFF_STYP_DISCARD},
   1439         { "nodiscard", 0, yasm_dir_helper_flag_and,
   1440           offsetof(struct coff_section_switch_data, flags), COFF_STYP_DISCARD},
   1441         { "cache", 0, yasm_dir_helper_flag_and,
   1442           offsetof(struct coff_section_switch_data, flags), COFF_STYP_NOCACHE},
   1443         { "nocache", 0, yasm_dir_helper_flag_or,
   1444           offsetof(struct coff_section_switch_data, flags), COFF_STYP_NOCACHE},
   1445         { "page", 0, yasm_dir_helper_flag_and,
   1446           offsetof(struct coff_section_switch_data, flags), COFF_STYP_NOPAGE },
   1447         { "nopage", 0, yasm_dir_helper_flag_or,
   1448           offsetof(struct coff_section_switch_data, flags), COFF_STYP_NOPAGE },
   1449         { "share", 0, yasm_dir_helper_flag_or,
   1450           offsetof(struct coff_section_switch_data, flags), COFF_STYP_SHARED },
   1451         { "noshare", 0, yasm_dir_helper_flag_and,
   1452           offsetof(struct coff_section_switch_data, flags), COFF_STYP_SHARED },
   1453         { "execute", 0, yasm_dir_helper_flag_or,
   1454           offsetof(struct coff_section_switch_data, flags), COFF_STYP_EXECUTE},
   1455         { "noexecute", 0, yasm_dir_helper_flag_and,
   1456           offsetof(struct coff_section_switch_data, flags), COFF_STYP_EXECUTE},
   1457         { "read", 0, yasm_dir_helper_flag_or,
   1458           offsetof(struct coff_section_switch_data, flags), COFF_STYP_READ },
   1459         { "noread", 0, yasm_dir_helper_flag_and,
   1460           offsetof(struct coff_section_switch_data, flags), COFF_STYP_READ },
   1461         { "write", 0, yasm_dir_helper_flag_or,
   1462           offsetof(struct coff_section_switch_data, flags), COFF_STYP_WRITE },
   1463         { "nowrite", 0, yasm_dir_helper_flag_and,
   1464           offsetof(struct coff_section_switch_data, flags), COFF_STYP_WRITE },
   1465         { "base", 0, yasm_dir_helper_flag_and,
   1466           offsetof(struct coff_section_switch_data, flags2), COFF_FLAG_NOBASE},
   1467         { "nobase", 0, yasm_dir_helper_flag_or,
   1468           offsetof(struct coff_section_switch_data, flags2), COFF_FLAG_NOBASE},
   1469         { "align", 1, yasm_dir_helper_intn,
   1470           offsetof(struct coff_section_switch_data, align_intn), 0 }
   1471     };
   1472 
   1473     vp = yasm_vps_first(valparams);
   1474     sectname = yasm_vp_string(vp);
   1475     if (!sectname)
   1476         return NULL;
   1477     vp = yasm_vps_next(vp);
   1478 
   1479     data.isdefault = 0;
   1480     data.gasflags = 0;
   1481     data.flags = 0;
   1482     data.flags2 = 0;
   1483     data.align_intn = NULL;
   1484 
   1485     if (strcmp(sectname, ".data") == 0) {
   1486         data.flags = COFF_STYP_DATA | COFF_STYP_READ | COFF_STYP_WRITE;
   1487         if (objfmt_coff->win32) {
   1488             if (objfmt_coff->machine == COFF_MACHINE_AMD64)
   1489                 align = 16;
   1490             else
   1491                 align = 4;
   1492         }
   1493     } else if (strcmp(sectname, ".bss") == 0) {
   1494         data.flags = COFF_STYP_BSS | COFF_STYP_READ | COFF_STYP_WRITE;
   1495         if (objfmt_coff->win32) {
   1496             if (objfmt_coff->machine == COFF_MACHINE_AMD64)
   1497                 align = 16;
   1498             else
   1499                 align = 4;
   1500         }
   1501         resonly = 1;
   1502     } else if (strcmp(sectname, ".text") == 0) {
   1503         data.flags = COFF_STYP_TEXT | COFF_STYP_EXECUTE | COFF_STYP_READ;
   1504         if (objfmt_coff->win32)
   1505             align = 16;
   1506     } else if (strcmp(sectname, ".rdata") == 0
   1507                || strncmp(sectname, ".rodata", 7) == 0
   1508                || strncmp(sectname, ".rdata$", 7) == 0) {
   1509         data.flags = COFF_STYP_DATA | COFF_STYP_READ;
   1510         if (objfmt_coff->win32)
   1511             align = 8;
   1512         else
   1513             yasm_warn_set(YASM_WARN_GENERAL,
   1514                 N_("Standard COFF does not support read-only data sections"));
   1515     } else if (strcmp(sectname, ".drectve") == 0) {
   1516         data.flags = COFF_STYP_INFO;
   1517         if (objfmt_coff->win32)
   1518             data.flags |= COFF_STYP_DISCARD | COFF_STYP_READ;
   1519     } else if (objfmt_coff->win64 && strcmp(sectname, ".pdata") == 0) {
   1520         data.flags = COFF_STYP_DATA | COFF_STYP_READ;
   1521         align = 4;
   1522         data.flags2 = COFF_FLAG_NOBASE;
   1523     } else if (objfmt_coff->win64 && strcmp(sectname, ".xdata") == 0) {
   1524         data.flags = COFF_STYP_DATA | COFF_STYP_READ;
   1525         align = 8;
   1526         data.flags2 = COFF_FLAG_NOBASE;
   1527     } else if (objfmt_coff->win32 && strcmp(sectname, ".sxdata") == 0) {
   1528         data.flags = COFF_STYP_INFO;
   1529     } else if (strcmp(sectname, ".comment") == 0) {
   1530         data.flags = COFF_STYP_INFO | COFF_STYP_DISCARD | COFF_STYP_READ;
   1531     } else if (yasm__strncasecmp(sectname, ".debug", 6)==0) {
   1532         data.flags = COFF_STYP_DATA | COFF_STYP_DISCARD | COFF_STYP_READ;
   1533         align = 1;
   1534     } else {
   1535         /* Default to code, but set a flag so if we get gasflags we can
   1536          * change it (NASM and GAS have different defaults).
   1537          */
   1538         data.isdefault = 1;
   1539         data.flags = COFF_STYP_TEXT | COFF_STYP_EXECUTE | COFF_STYP_READ;
   1540     }
   1541 
   1542     flags_override = yasm_dir_helper(object, vp, line, help,
   1543                                      objfmt_coff->win32 ? NELEMS(help) : 7,
   1544                                      &data, yasm_dir_helper_valparam_warn);
   1545     if (flags_override < 0)
   1546         return NULL;    /* error occurred */
   1547 
   1548     if (data.flags & COFF_STYP_EXECUTE)
   1549         iscode = 1;
   1550 
   1551     if (!objfmt_coff->win32)
   1552         data.flags &= ~COFF_STYP_WIN32_MASK;
   1553 
   1554     if (data.align_intn) {
   1555         align = yasm_intnum_get_uint(data.align_intn);
   1556         yasm_intnum_destroy(data.align_intn);
   1557 
   1558         /* Alignments must be a power of two. */
   1559         if (!is_exp2(align)) {
   1560             yasm_error_set(YASM_ERROR_VALUE,
   1561                            N_("argument to `%s' is not a power of two"),
   1562                            "align");
   1563             return NULL;
   1564         }
   1565 
   1566         /* Check to see if alignment is supported size */
   1567         if (align > 8192) {
   1568             yasm_error_set(YASM_ERROR_VALUE,
   1569                 N_("Win32 does not support alignments > 8192"));
   1570             return NULL;
   1571         }
   1572     }
   1573 
   1574     realname = yasm__xstrdup(sectname);
   1575     if (strlen(sectname) > 8 && !objfmt_coff->win32) {
   1576         /* win32 format supports >8 character section names in object
   1577          * files via "/nnnn" (where nnnn is decimal offset into string table),
   1578          * so only warn for regular COFF.
   1579          */
   1580         yasm_warn_set(YASM_WARN_GENERAL,
   1581             N_("COFF section names limited to 8 characters: truncating"));
   1582         realname[8] = '\0';
   1583     }
   1584 
   1585     retval = yasm_object_get_general(object, realname, align, iscode,
   1586                                      resonly, &isnew, line);
   1587     yasm_xfree(realname);
   1588 
   1589     csd = yasm_section_get_data(retval, &coff_section_data_cb);
   1590 
   1591     if (isnew || yasm_section_is_default(retval)) {
   1592         yasm_section_set_default(retval, 0);
   1593         csd->flags = data.flags;
   1594         csd->flags2 = data.flags2;
   1595         yasm_section_set_align(retval, align, line);
   1596     } else if (flags_override && !data.gasflags)
   1597         yasm_warn_set(YASM_WARN_GENERAL,
   1598                       N_("section flags ignored on section redeclaration"));
   1599     return retval;
   1600 }
   1601 
   1602 static /*@observer@*/ /*@null@*/ yasm_symrec *
   1603 coff_objfmt_get_special_sym(yasm_object *object, const char *name,
   1604                             const char *parser)
   1605 {
   1606     return NULL;
   1607 }
   1608 
   1609 static /*@observer@*/ /*@null@*/ yasm_symrec *
   1610 win64_objfmt_get_special_sym(yasm_object *object, const char *name,
   1611                              const char *parser)
   1612 {
   1613     if (yasm__strcasecmp(name, "imagebase") == 0) {
   1614         yasm_objfmt_coff *objfmt_coff = (yasm_objfmt_coff *)object->objfmt;
   1615         return objfmt_coff->ssym_imagebase;
   1616     }
   1617     return NULL;
   1618 }
   1619 
   1620 static void
   1621 coff_section_data_destroy(void *data)
   1622 {
   1623     yasm_xfree(data);
   1624 }
   1625 
   1626 static void
   1627 coff_section_data_print(void *data, FILE *f, int indent_level)
   1628 {
   1629     coff_section_data *csd = (coff_section_data *)data;
   1630 
   1631     fprintf(f, "%*ssym=\n", indent_level, "");
   1632     yasm_symrec_print(csd->sym, f, indent_level+1);
   1633     fprintf(f, "%*sscnum=%d\n", indent_level, "", csd->scnum);
   1634     fprintf(f, "%*sflags=", indent_level, "");
   1635     switch (csd->flags & COFF_STYP_STD_MASK) {
   1636         case COFF_STYP_TEXT:
   1637             fprintf(f, "TEXT");
   1638             break;
   1639         case COFF_STYP_DATA:
   1640             fprintf(f, "DATA");
   1641             break;
   1642         case COFF_STYP_BSS:
   1643             fprintf(f, "BSS");
   1644             break;
   1645         default:
   1646             fprintf(f, "UNKNOWN");
   1647             break;
   1648     }
   1649     fprintf(f, "\n%*saddr=0x%lx\n", indent_level, "", csd->addr);
   1650     fprintf(f, "%*sscnptr=0x%lx\n", indent_level, "", csd->scnptr);
   1651     fprintf(f, "%*ssize=%ld\n", indent_level, "", csd->size);
   1652     fprintf(f, "%*srelptr=0x%lx\n", indent_level, "", csd->relptr);
   1653     fprintf(f, "%*snreloc=%ld\n", indent_level, "", csd->nreloc);
   1654     fprintf(f, "%*srelocs:\n", indent_level, "");
   1655 }
   1656 
   1657 static void
   1658 coff_symrec_data_destroy(void *data)
   1659 {
   1660     yasm_xfree(data);
   1661 }
   1662 
   1663 static void
   1664 coff_symrec_data_print(void *data, FILE *f, int indent_level)
   1665 {
   1666     coff_symrec_data *csd = (coff_symrec_data *)data;
   1667 
   1668     fprintf(f, "%*ssymtab index=%lu\n", indent_level, "", csd->index);
   1669     fprintf(f, "%*ssclass=%d\n", indent_level, "", csd->sclass);
   1670 }
   1671 
   1672 static void
   1673 dir_export(yasm_object *object, yasm_valparamhead *valparams,
   1674            yasm_valparamhead *objext_valparams, unsigned long line)
   1675 {
   1676     yasm_valparam *vp;
   1677     /*@null@*/ const char *symname;
   1678     int isnew;
   1679     yasm_section *sect;
   1680     yasm_datavalhead dvs;
   1681 
   1682     /* Reference exported symbol (to generate error if not declared) */
   1683     vp = yasm_vps_first(valparams);
   1684     symname = yasm_vp_id(vp);
   1685     if (symname)
   1686         yasm_symtab_use(object->symtab, symname, line);
   1687     else {
   1688         yasm_error_set(YASM_ERROR_SYNTAX,
   1689                        N_("argument to EXPORT must be symbol name"));
   1690         return;
   1691     }
   1692 
   1693     /* Add to end of linker directives */
   1694     sect = yasm_object_get_general(object, ".drectve", 0, 0, 0, &isnew, line);
   1695 
   1696     /* Initialize directive section if needed */
   1697     if (isnew) {
   1698         coff_section_data *csd;
   1699         csd = yasm_section_get_data(sect, &coff_section_data_cb);
   1700         csd->flags = COFF_STYP_INFO | COFF_STYP_DISCARD | COFF_STYP_READ;
   1701     }
   1702 
   1703     /* Add text as data bytecode */
   1704     yasm_dvs_initialize(&dvs);
   1705     yasm_dvs_append(&dvs, yasm_dv_create_string(yasm__xstrdup("-export:"),
   1706                                                 strlen("-export:")));
   1707     yasm_dvs_append(&dvs, yasm_dv_create_string(yasm__xstrdup(symname),
   1708                                                 strlen(symname)));
   1709     yasm_dvs_append(&dvs, yasm_dv_create_string(yasm__xstrdup(" "), 1));
   1710     yasm_section_bcs_append(sect, yasm_bc_create_data(&dvs, 1, 0, NULL, line));
   1711 }
   1712 
   1713 static void
   1714 dir_safeseh(yasm_object *object, yasm_valparamhead *valparams,
   1715             yasm_valparamhead *objext_valparams, unsigned long line)
   1716 {
   1717     yasm_valparam *vp;
   1718     /*@null@*/ const char *symname;
   1719     yasm_symrec *sym;
   1720     int isnew;
   1721     yasm_section *sect;
   1722 
   1723     /* Reference symbol (to generate error if not declared).
   1724      * Also, symbol must be externally visible, so force it.
   1725      */
   1726     vp = yasm_vps_first(valparams);
   1727     symname = yasm_vp_id(vp);
   1728     if (symname) {
   1729         coff_symrec_data *sym_data;
   1730         sym = yasm_symtab_use(object->symtab, symname, line);
   1731         sym_data = yasm_symrec_get_data(sym, &coff_symrec_data_cb);
   1732         if (!sym_data) {
   1733             sym_data = coff_objfmt_sym_set_data(sym, COFF_SCL_NULL, 0,
   1734                                                 COFF_SYMTAB_AUX_NONE);
   1735         }
   1736         sym_data->forcevis = 1;
   1737         sym_data->type = 0x20; /* function */
   1738     } else {
   1739         yasm_error_set(YASM_ERROR_SYNTAX,
   1740                        N_("argument to SAFESEH must be symbol name"));
   1741         return;
   1742     }
   1743 
   1744     /*
   1745      * Add symbol number to end of .sxdata section.
   1746      */
   1747 
   1748     sect = yasm_object_get_general(object, ".sxdata", 0, 0, 0, &isnew, line);
   1749 
   1750     /* Initialize sxdata section if needed */
   1751     if (isnew) {
   1752         coff_section_data *csd;
   1753         csd = yasm_section_get_data(sect, &coff_section_data_cb);
   1754         csd->flags = COFF_STYP_INFO;
   1755     }
   1756 
   1757     /* Add as sxdata bytecode */
   1758     yasm_section_bcs_append(sect,
   1759                             yasm_bc_create_common(&win32_sxdata_bc_callback,
   1760                                                   sym, line));
   1761 }
   1762 
   1763 static void
   1764 win32_sxdata_bc_destroy(void *contents)
   1765 {
   1766     /* Contents is just the symbol pointer, so no need to delete */
   1767 }
   1768 
   1769 static void
   1770 win32_sxdata_bc_print(const void *contents, FILE *f, int indent_level)
   1771 {
   1772     /* TODO */
   1773 }
   1774 
   1775 static int
   1776 win32_sxdata_bc_calc_len(yasm_bytecode *bc, yasm_bc_add_span_func add_span,
   1777                          void *add_span_data)
   1778 {
   1779     bc->len += 4;
   1780     return 0;
   1781 }
   1782 
   1783 static int
   1784 win32_sxdata_bc_tobytes(yasm_bytecode *bc, unsigned char **bufp,
   1785                         unsigned char *bufstart, void *d,
   1786                         yasm_output_value_func output_value,
   1787                         yasm_output_reloc_func output_reloc)
   1788 {
   1789     yasm_symrec *sym = (yasm_symrec *)bc->contents;
   1790     unsigned char *buf = *bufp;
   1791     coff_symrec_data *csymd;
   1792 
   1793     csymd = yasm_symrec_get_data(sym, &coff_symrec_data_cb);
   1794     if (!csymd)
   1795         yasm_internal_error(N_("coff: no symbol data for SAFESEH symbol"));
   1796 
   1797     YASM_WRITE_32_L(buf, csymd->index);
   1798 
   1799     *bufp = buf;
   1800     return 0;
   1801 }
   1802 
   1803 static void
   1804 dir_ident(yasm_object *object, yasm_valparamhead *valparams,
   1805           yasm_valparamhead *objext_valparams, unsigned long line)
   1806 {
   1807     yasm_objfmt_coff *objfmt_coff = (yasm_objfmt_coff *)object->objfmt;
   1808     yasm_valparamhead sect_vps;
   1809     yasm_datavalhead dvs;
   1810     yasm_section *comment;
   1811     const char *sectname;
   1812     yasm_valparam *vp, *vp2;
   1813 
   1814     /* Accept, but do nothing with empty ident */
   1815     if (!valparams)
   1816         return;
   1817 
   1818     vp = yasm_vps_first(valparams);
   1819     if (!vp)
   1820         return;
   1821 
   1822     if (objfmt_coff->win32) {
   1823         /* Put ident data into .comment section for COFF, or .rdata$zzz
   1824          * to be compatible with the GNU linker, which doesn't ignore
   1825          * .comment (see binutils/gas/config/obj-coff.c:476-502).
   1826          */
   1827         sectname = ".rdata$zzz";
   1828     } else {
   1829         sectname = ".comment";
   1830     }
   1831     yasm_vps_initialize(&sect_vps);
   1832     vp2 = yasm_vp_create_id(NULL, yasm__xstrdup(sectname), '\0');
   1833     yasm_vps_append(&sect_vps, vp2);
   1834     comment = coff_objfmt_section_switch(object, &sect_vps, NULL, line);
   1835     yasm_vps_delete(&sect_vps);
   1836 
   1837     /* To match GAS output, if the comment section is empty, put an
   1838      * initial 0 byte in the section.
   1839      */
   1840     if (yasm_section_bcs_first(comment) == yasm_section_bcs_last(comment)) {
   1841         yasm_dvs_initialize(&dvs);
   1842         yasm_dvs_append(&dvs, yasm_dv_create_expr(
   1843             yasm_expr_create_ident(yasm_expr_int(yasm_intnum_create_uint(0)),
   1844                                    line)));
   1845         yasm_section_bcs_append(comment,
   1846             yasm_bc_create_data(&dvs, 1, 0, object->arch, line));
   1847     }
   1848 
   1849     yasm_dvs_initialize(&dvs);
   1850     do {
   1851         const char *s = yasm_vp_string(vp);
   1852         if (!s) {
   1853             yasm_error_set(YASM_ERROR_VALUE,
   1854                            N_(".comment requires string parameters"));
   1855             yasm_dvs_delete(&dvs);
   1856             return;
   1857         }
   1858         yasm_dvs_append(&dvs,
   1859                         yasm_dv_create_string(yasm__xstrdup(s), strlen(s)));
   1860     } while ((vp = yasm_vps_next(vp)));
   1861 
   1862     yasm_section_bcs_append(comment,
   1863         yasm_bc_create_data(&dvs, 1, 1, object->arch, line));
   1864 }
   1865 
   1866 static void
   1867 dir_secrel32(yasm_object *object, yasm_valparamhead *valparams,
   1868              yasm_valparamhead *objext_valparams, unsigned long line)
   1869 {
   1870     yasm_datavalhead dvs;
   1871     yasm_valparam *vp;
   1872 
   1873     if (!object->cur_section) {
   1874         yasm_error_set(YASM_ERROR_SYNTAX,
   1875                        N_(".secrel32 can only be used inside of a section"));
   1876         return;
   1877     }
   1878 
   1879     vp = yasm_vps_first(valparams);
   1880     yasm_dvs_initialize(&dvs);
   1881     do {
   1882         yasm_expr *e = yasm_vp_expr(vp, object->symtab, line);
   1883         yasm_dataval *dv;
   1884         if (!e) {
   1885             yasm_error_set(YASM_ERROR_VALUE,
   1886                            N_(".secrel32 requires expressions"));
   1887             yasm_dvs_delete(&dvs);
   1888             return;
   1889         }
   1890         dv = yasm_dv_create_expr(e);
   1891         yasm_dv_get_value(dv)->section_rel = 1;
   1892         yasm_dvs_append(&dvs, dv);
   1893     } while ((vp = yasm_vps_next(vp)));
   1894 
   1895     yasm_section_bcs_append(object->cur_section,
   1896         yasm_bc_create_data(&dvs, 4, 0, object->arch, line));
   1897 }
   1898 
   1899 static void
   1900 dir_def(yasm_object *object, yasm_valparamhead *valparams,
   1901         yasm_valparamhead *objext_valparams, unsigned long line)
   1902 {
   1903     yasm_objfmt_coff *objfmt_coff = (yasm_objfmt_coff *)object->objfmt;
   1904     yasm_valparam *vp;
   1905     const char *symname;
   1906     yasm_symrec *sym;
   1907     coff_symrec_data *sym_data;
   1908 
   1909     if (objfmt_coff->def_sym) {
   1910         yasm_warn_set(YASM_WARN_GENERAL,
   1911                       N_(".def pseudo-op used inside of .def/.endef; ignored"));
   1912         return;
   1913     }
   1914 
   1915     vp = yasm_vps_first(valparams);
   1916     symname = yasm_vp_id(vp);
   1917     if (!symname) {
   1918         yasm_error_set(YASM_ERROR_SYNTAX,
   1919                        N_("argument to SAFESEH must be symbol name"));
   1920         return;
   1921     }
   1922 
   1923     sym = yasm_symtab_use(object->symtab, symname, line);
   1924     sym_data = yasm_symrec_get_data(sym, &coff_symrec_data_cb);
   1925     if (!sym_data) {
   1926         sym_data = coff_objfmt_sym_set_data(sym, COFF_SCL_NULL, 0,
   1927                                             COFF_SYMTAB_AUX_NONE);
   1928     }
   1929     objfmt_coff->def_sym = sym_data;
   1930 }
   1931 
   1932 static void
   1933 dir_scl(yasm_object *object, yasm_valparamhead *valparams,
   1934         yasm_valparamhead *objext_valparams, unsigned long line)
   1935 {
   1936     yasm_objfmt_coff *objfmt_coff = (yasm_objfmt_coff *)object->objfmt;
   1937     yasm_intnum *intn = NULL;
   1938 
   1939     if (!objfmt_coff->def_sym) {
   1940         yasm_warn_set(YASM_WARN_GENERAL,
   1941                       N_("%s pseudo-op used outside of .def/.endef; ignored"),
   1942                       ".scl");
   1943         return;
   1944     }
   1945 
   1946     if (yasm_dir_helper_intn(object, yasm_vps_first(valparams), line,
   1947                              &intn, 0) < 0)
   1948         return;
   1949     if (!intn)
   1950         return;
   1951     objfmt_coff->def_sym->sclass = yasm_intnum_get_uint(intn);
   1952     yasm_intnum_destroy(intn);
   1953 }
   1954 
   1955 static void
   1956 dir_type(yasm_object *object, yasm_valparamhead *valparams,
   1957          yasm_valparamhead *objext_valparams, unsigned long line)
   1958 {
   1959     yasm_objfmt_coff *objfmt_coff = (yasm_objfmt_coff *)object->objfmt;
   1960     yasm_intnum *intn = NULL;
   1961 
   1962     if (!objfmt_coff->def_sym) {
   1963         yasm_warn_set(YASM_WARN_GENERAL,
   1964                       N_("%s pseudo-op used outside of .def/.endef; ignored"),
   1965                       ".type");
   1966         return;
   1967     }
   1968 
   1969     if (yasm_dir_helper_intn(object, yasm_vps_first(valparams), line,
   1970                              &intn, 0) < 0)
   1971         return;
   1972     if (!intn)
   1973         return;
   1974     objfmt_coff->def_sym->type = yasm_intnum_get_uint(intn);
   1975     yasm_intnum_destroy(intn);
   1976 }
   1977 
   1978 static void
   1979 dir_endef(yasm_object *object, yasm_valparamhead *valparams,
   1980           yasm_valparamhead *objext_valparams, unsigned long line)
   1981 {
   1982     yasm_objfmt_coff *objfmt_coff = (yasm_objfmt_coff *)object->objfmt;
   1983     if (!objfmt_coff->def_sym) {
   1984         yasm_warn_set(YASM_WARN_GENERAL,
   1985                       N_(".endef pseudo-op used before .def; ignored"));
   1986         return;
   1987     }
   1988     objfmt_coff->def_sym = NULL;
   1989 }
   1990 
   1991 static void
   1992 dir_proc_frame(yasm_object *object, /*@null@*/ yasm_valparamhead *valparams,
   1993                yasm_valparamhead *objext_valparams, unsigned long line)
   1994 {
   1995     yasm_objfmt_coff *objfmt_coff = (yasm_objfmt_coff *)object->objfmt;
   1996     yasm_valparam *vp = yasm_vps_first(valparams);
   1997     const char *name = yasm_vp_id(vp);
   1998 
   1999     if (objfmt_coff->proc_frame) {
   2000         yasm_error_set_xref(objfmt_coff->proc_frame,
   2001                             N_("previous procedure started here"));
   2002         yasm_error_set(YASM_ERROR_SYNTAX,
   2003             N_("nested procedures not supported (didn't use [ENDPROC_FRAME]?)"));
   2004         return;
   2005     }
   2006     objfmt_coff->proc_frame = line;
   2007     objfmt_coff->done_prolog = 0;
   2008     objfmt_coff->unwind = yasm_win64__uwinfo_create();
   2009     objfmt_coff->unwind->proc = yasm_symtab_use(object->symtab, name, line);
   2010 
   2011     /* Optional error handler */
   2012     vp = yasm_vps_next(vp);
   2013     if (!vp || !(name = yasm_vp_id(vp)))
   2014         return;
   2015     objfmt_coff->unwind->ehandler =
   2016         yasm_symtab_use(object->symtab, name, line);
   2017 }
   2018 
   2019 static int
   2020 procframe_checkstate(yasm_objfmt_coff *objfmt_coff, const char *dirname)
   2021 {
   2022     if (!objfmt_coff->proc_frame) {
   2023         yasm_error_set(YASM_ERROR_SYNTAX,
   2024                        N_("[%s] without preceding [PROC_FRAME]"), dirname);
   2025         return 0;
   2026     }
   2027     if (objfmt_coff->done_prolog) {
   2028         yasm_error_set_xref(objfmt_coff->done_prolog,
   2029                             N_("prologue ended here"));
   2030         yasm_error_set(YASM_ERROR_SYNTAX, N_("[%s] after end of prologue"),
   2031                        dirname);
   2032         return 0;
   2033     }
   2034     if (!objfmt_coff->unwind)
   2035         yasm_internal_error(N_("unwind info not present"));
   2036     return 1;
   2037 }
   2038 
   2039 /* Get current assembly position.
   2040  * XXX: There should be a better way to do this.
   2041  */
   2042 static yasm_symrec *
   2043 get_curpos(yasm_object *object, const char *dirname, unsigned long line)
   2044 {
   2045     if (!object->cur_section) {
   2046         yasm_error_set(YASM_ERROR_SYNTAX,
   2047                        N_("[%s] can only be used inside of a section"),
   2048                        dirname);
   2049         return NULL;
   2050     }
   2051     return yasm_symtab_define_curpos(object->symtab, "$",
   2052         yasm_section_bcs_last(object->cur_section), line);
   2053 }
   2054 
   2055 static void
   2056 dir_pushreg(yasm_object *object, yasm_valparamhead *valparams,
   2057             yasm_valparamhead *objext_valparams, unsigned long line)
   2058 {
   2059     yasm_objfmt_coff *objfmt_coff = (yasm_objfmt_coff *)object->objfmt;
   2060     yasm_valparam *vp = yasm_vps_first(valparams);
   2061     coff_unwind_code *code;
   2062     const uintptr_t *reg;
   2063 
   2064     if (!procframe_checkstate(objfmt_coff, "PUSHREG"))
   2065         return;
   2066 
   2067     if (vp->type != YASM_PARAM_EXPR ||
   2068         !(reg = yasm_expr_get_reg(&vp->param.e, 0))) {
   2069         yasm_error_set(YASM_ERROR_SYNTAX,
   2070                        N_("[%s] requires a register as the first parameter"),
   2071                        "PUSHREG");
   2072         return;
   2073     }
   2074 
   2075     /* Generate a PUSH_NONVOL unwind code. */
   2076     code = yasm_xmalloc(sizeof(coff_unwind_code));
   2077     code->proc = objfmt_coff->unwind->proc;
   2078     code->loc = get_curpos(object, "PUSHREG", line);
   2079     code->opcode = UWOP_PUSH_NONVOL;
   2080     code->info = (unsigned int)(*reg & 0xF);
   2081     yasm_value_initialize(&code->off, NULL, 0);
   2082     SLIST_INSERT_HEAD(&objfmt_coff->unwind->codes, code, link);
   2083 }
   2084 
   2085 static void
   2086 dir_setframe(yasm_object *object, yasm_valparamhead *valparams,
   2087              yasm_valparamhead *objext_valparams, unsigned long line)
   2088 {
   2089     yasm_objfmt_coff *objfmt_coff = (yasm_objfmt_coff *)object->objfmt;
   2090     yasm_valparam *vp = yasm_vps_first(valparams);
   2091     coff_unwind_code *code;
   2092     const uintptr_t *reg;
   2093     yasm_expr *off = NULL;
   2094 
   2095     if (!procframe_checkstate(objfmt_coff, "SETFRAME"))
   2096         return;
   2097 
   2098     if (vp->type != YASM_PARAM_EXPR ||
   2099         !(reg = yasm_expr_get_reg(&vp->param.e, 0))) {
   2100         yasm_error_set(YASM_ERROR_SYNTAX,
   2101                        N_("[%s] requires a register as the first parameter"),
   2102                        "SETFRAME");
   2103         return;
   2104     }
   2105 
   2106     vp = yasm_vps_next(vp);
   2107     if (vp)
   2108         off = yasm_vp_expr(vp, object->symtab, line);
   2109 
   2110     /* Set the frame fields in the unwind info */
   2111     objfmt_coff->unwind->framereg = (unsigned long)(*reg);
   2112     yasm_value_initialize(&objfmt_coff->unwind->frameoff, off, 8);
   2113 
   2114     /* Generate a SET_FPREG unwind code */
   2115     code = yasm_xmalloc(sizeof(coff_unwind_code));
   2116     code->proc = objfmt_coff->unwind->proc;
   2117     code->loc = get_curpos(object, "SETFRAME", line);
   2118     code->opcode = UWOP_SET_FPREG;
   2119     code->info = (unsigned int)(*reg & 0xF);
   2120     yasm_value_initialize(&code->off, off ? yasm_expr_copy(off) : NULL, 8);
   2121     SLIST_INSERT_HEAD(&objfmt_coff->unwind->codes, code, link);
   2122 }
   2123 
   2124 static void
   2125 dir_allocstack(yasm_object *object, yasm_valparamhead *valparams,
   2126                yasm_valparamhead *objext_valparams, unsigned long line)
   2127 {
   2128     yasm_objfmt_coff *objfmt_coff = (yasm_objfmt_coff *)object->objfmt;
   2129     yasm_valparam *vp = yasm_vps_first(valparams);
   2130     /*@null@*/ /*@only@*/ yasm_expr *size;
   2131     coff_unwind_code *code;
   2132 
   2133     if (!procframe_checkstate(objfmt_coff, "ALLOCSTACK"))
   2134         return;
   2135 
   2136     size = yasm_vp_expr(vp, object->symtab, line);
   2137     if (!size) {
   2138         yasm_error_set(YASM_ERROR_SYNTAX, N_("[%s] requires a size"),
   2139                        "ALLOCSTACK");
   2140         return;
   2141     }
   2142 
   2143     /* Generate an ALLOC_SMALL unwind code; this will get enlarged to an
   2144      * ALLOC_LARGE if necessary.
   2145      */
   2146     code = yasm_xmalloc(sizeof(coff_unwind_code));
   2147     code->proc = objfmt_coff->unwind->proc;
   2148     code->loc = get_curpos(object, "ALLOCSTACK", line);
   2149     code->opcode = UWOP_ALLOC_SMALL;
   2150     code->info = 0;
   2151     yasm_value_initialize(&code->off, size, 7);
   2152     SLIST_INSERT_HEAD(&objfmt_coff->unwind->codes, code, link);
   2153 }
   2154 
   2155 static void
   2156 dir_save_common(yasm_object *object, yasm_valparamhead *valparams,
   2157                 unsigned long line, const char *name, int op)
   2158 {
   2159     yasm_objfmt_coff *objfmt_coff = (yasm_objfmt_coff *)object->objfmt;
   2160     yasm_valparam *vp = yasm_vps_first(valparams);
   2161     coff_unwind_code *code;
   2162     const uintptr_t *reg;
   2163     /*@only@*/ /*@null@*/ yasm_expr *offset;
   2164 
   2165     if (!procframe_checkstate(objfmt_coff, name))
   2166         return;
   2167 
   2168     if (vp->type != YASM_PARAM_EXPR ||
   2169         !(reg = yasm_expr_get_reg(&vp->param.e, 0))) {
   2170         yasm_error_set(YASM_ERROR_SYNTAX,
   2171                        N_("[%s] requires a register as the first parameter"),
   2172                        name);
   2173         return;
   2174     }
   2175 
   2176     vp = yasm_vps_next(vp);
   2177     offset = yasm_vp_expr(vp, object->symtab, line);
   2178     if (!offset) {
   2179         yasm_error_set(YASM_ERROR_SYNTAX,
   2180                        N_("[%s] requires an offset as the second parameter"),
   2181                        name);
   2182         return;
   2183     }
   2184 
   2185     /* Generate a SAVE_XXX unwind code; this will get enlarged to a
   2186      * SAVE_XXX_FAR if necessary.
   2187      */
   2188     code = yasm_xmalloc(sizeof(coff_unwind_code));
   2189     code->proc = objfmt_coff->unwind->proc;
   2190     code->loc = get_curpos(object, name, line);
   2191     code->opcode = op;
   2192     code->info = (unsigned int)(*reg & 0xF);
   2193     yasm_value_initialize(&code->off, offset, 16);
   2194     SLIST_INSERT_HEAD(&objfmt_coff->unwind->codes, code, link);
   2195 }
   2196 
   2197 static void
   2198 dir_savereg(yasm_object *object, yasm_valparamhead *valparams,
   2199             yasm_valparamhead *objext_valparams, unsigned long line)
   2200 {
   2201     dir_save_common(object, valparams, line, "SAVEREG", UWOP_SAVE_NONVOL);
   2202 }
   2203 
   2204 static void
   2205 dir_savexmm128(yasm_object *object, yasm_valparamhead *valparams,
   2206                yasm_valparamhead *objext_valparams, unsigned long line)
   2207 {
   2208     dir_save_common(object, valparams, line, "SAVEXMM128", UWOP_SAVE_XMM128);
   2209 }
   2210 
   2211 static void
   2212 dir_pushframe(yasm_object *object, /*@null@*/ yasm_valparamhead *valparams,
   2213               yasm_valparamhead *objext_valparams, unsigned long line)
   2214 {
   2215     yasm_objfmt_coff *objfmt_coff = (yasm_objfmt_coff *)object->objfmt;
   2216     yasm_valparam *vp = yasm_vps_first(valparams);
   2217     coff_unwind_code *code;
   2218 
   2219     if (!procframe_checkstate(objfmt_coff, "PUSHFRAME"))
   2220         return;
   2221 
   2222     /* Generate a PUSH_MACHFRAME unwind code.  If there's any parameter,
   2223      * we set info to 1.  Otherwise we set info to 0.
   2224      */
   2225     code = yasm_xmalloc(sizeof(coff_unwind_code));
   2226     code->proc = objfmt_coff->unwind->proc;
   2227     code->loc = get_curpos(object, "PUSHFRAME", line);
   2228     code->opcode = UWOP_PUSH_MACHFRAME;
   2229     code->info = vp != NULL;
   2230     yasm_value_initialize(&code->off, NULL, 0);
   2231     SLIST_INSERT_HEAD(&objfmt_coff->unwind->codes, code, link);
   2232 }
   2233 
   2234 static void
   2235 dir_endprolog(yasm_object *object, /*@null@*/ yasm_valparamhead *valparams,
   2236               yasm_valparamhead *objext_valparams, unsigned long line)
   2237 {
   2238     yasm_objfmt_coff *objfmt_coff = (yasm_objfmt_coff *)object->objfmt;
   2239     if (!procframe_checkstate(objfmt_coff, "ENDPROLOG"))
   2240         return;
   2241     objfmt_coff->done_prolog = line;
   2242 
   2243     objfmt_coff->unwind->prolog = get_curpos(object, "ENDPROLOG", line);
   2244 }
   2245 
   2246 static void
   2247 dir_endproc_frame(yasm_object *object, /*@null@*/ yasm_valparamhead *valparams,
   2248                   yasm_valparamhead *objext_valparams, unsigned long line)
   2249 {
   2250     yasm_objfmt_coff *objfmt_coff = (yasm_objfmt_coff *)object->objfmt;
   2251     yasm_section *sect;
   2252     coff_section_data *csd;
   2253     yasm_datavalhead dvs;
   2254     int isnew;
   2255     /*@dependent@*/ yasm_symrec *curpos, *unwindpos, *proc_sym, *xdata_sym;
   2256 
   2257     if (!objfmt_coff->proc_frame) {
   2258         yasm_error_set(YASM_ERROR_SYNTAX,
   2259                        N_("[%s] without preceding [PROC_FRAME]"),
   2260                        "ENDPROC_FRAME");
   2261         return;
   2262     }
   2263     if (!objfmt_coff->done_prolog) {
   2264         yasm_error_set_xref(objfmt_coff->proc_frame,
   2265                             N_("procedure started here"));
   2266         yasm_error_set(YASM_ERROR_SYNTAX,
   2267                        N_("ended procedure without ending prologue"),
   2268                        "ENDPROC_FRAME");
   2269         objfmt_coff->proc_frame = 0;
   2270         yasm_win64__uwinfo_destroy(objfmt_coff->unwind);
   2271         objfmt_coff->unwind = NULL;
   2272         return;
   2273     }
   2274     if (!objfmt_coff->unwind)
   2275         yasm_internal_error(N_("unwind info not present"));
   2276 
   2277     proc_sym = objfmt_coff->unwind->proc;
   2278 
   2279     curpos = get_curpos(object, "ENDPROC_FRAME", line);
   2280 
   2281     /*
   2282      * Add unwind info to end of .xdata section.
   2283      */
   2284 
   2285     sect = yasm_object_get_general(object, ".xdata", 0, 0, 0, &isnew, line);
   2286 
   2287     /* Initialize xdata section if needed */
   2288     if (isnew) {
   2289         csd = yasm_section_get_data(sect, &coff_section_data_cb);
   2290         csd->flags = COFF_STYP_DATA | COFF_STYP_READ;
   2291         yasm_section_set_align(sect, 8, line);
   2292     }
   2293 
   2294     /* Get current position in .xdata section */
   2295     unwindpos = yasm_symtab_define_curpos(object->symtab, "$",
   2296         yasm_section_bcs_last(sect), line);
   2297     /* Get symbol for .xdata as we'll want to reference it with WRT */
   2298     csd = yasm_section_get_data(sect, &coff_section_data_cb);
   2299     xdata_sym = csd->sym;
   2300 
   2301     /* Add unwind info.  Use line number of start of procedure. */
   2302     yasm_win64__unwind_generate(sect, objfmt_coff->unwind,
   2303                                 objfmt_coff->proc_frame);
   2304     objfmt_coff->unwind = NULL; /* generate keeps the unwind pointer */
   2305 
   2306     /*
   2307      * Add function lookup to end of .pdata section.
   2308      */
   2309 
   2310     sect = yasm_object_get_general(object, ".pdata", 0, 0, 0, &isnew, line);
   2311 
   2312     /* Initialize pdata section if needed */
   2313     if (isnew) {
   2314         csd = yasm_section_get_data(sect, &coff_section_data_cb);
   2315         csd->flags = COFF_STYP_DATA | COFF_STYP_READ;
   2316         csd->flags2 = COFF_FLAG_NOBASE;
   2317         yasm_section_set_align(sect, 4, line);
   2318     }
   2319 
   2320     /* Add function structure as data bytecode */
   2321     yasm_dvs_initialize(&dvs);
   2322     yasm_dvs_append(&dvs, yasm_dv_create_expr(
   2323         yasm_expr_create_ident(yasm_expr_sym(proc_sym), line)));
   2324     yasm_dvs_append(&dvs, yasm_dv_create_expr(
   2325         yasm_expr_create(YASM_EXPR_WRT, yasm_expr_sym(curpos),
   2326                          yasm_expr_sym(proc_sym), line)));
   2327     yasm_dvs_append(&dvs, yasm_dv_create_expr(
   2328         yasm_expr_create(YASM_EXPR_WRT, yasm_expr_sym(unwindpos),
   2329                          yasm_expr_sym(xdata_sym), line)));
   2330     yasm_section_bcs_append(sect, yasm_bc_create_data(&dvs, 4, 0, NULL, line));
   2331 
   2332     objfmt_coff->proc_frame = 0;
   2333     objfmt_coff->done_prolog = 0;
   2334 }
   2335 
   2336 /* Define valid debug formats to use with this object format */
   2337 static const char *coff_objfmt_dbgfmt_keywords[] = {
   2338     "null",
   2339     "dwarf2",
   2340     NULL
   2341 };
   2342 
   2343 static const yasm_directive coff_objfmt_directives[] = {
   2344     { ".ident",         "gas",  dir_ident,      YASM_DIR_ANY },
   2345     { "ident",          "nasm", dir_ident,      YASM_DIR_ANY },
   2346     { ".def",           "gas",  dir_def,        YASM_DIR_ID_REQUIRED },
   2347     { ".endef",         "gas",  dir_endef,      YASM_DIR_ANY },
   2348     { ".scl",           "gas",  dir_scl,        YASM_DIR_ARG_REQUIRED },
   2349     { ".type",          "gas",  dir_type,       YASM_DIR_ARG_REQUIRED },
   2350     { ".secrel32",      "gas",  dir_secrel32,   YASM_DIR_ARG_REQUIRED },
   2351     { NULL, NULL, NULL, 0 }
   2352 };
   2353 
   2354 /* Define objfmt structure -- see objfmt.h for details */
   2355 yasm_objfmt_module yasm_coff_LTX_objfmt = {
   2356     "COFF (DJGPP)",
   2357     "coff",
   2358     "o",
   2359     32,
   2360     0,
   2361     coff_objfmt_dbgfmt_keywords,
   2362     "null",
   2363     coff_objfmt_directives,
   2364     NULL,   /* no standard macros */
   2365     coff_objfmt_create,
   2366     coff_objfmt_output,
   2367     coff_objfmt_destroy,
   2368     coff_objfmt_add_default_section,
   2369     coff_objfmt_init_new_section,
   2370     coff_objfmt_section_switch,
   2371     coff_objfmt_get_special_sym
   2372 };
   2373 
   2374 /* Define valid debug formats to use with this object format */
   2375 static const char *winXX_objfmt_dbgfmt_keywords[] = {
   2376     "null",
   2377     "dwarf2",
   2378     "cv8",
   2379     NULL
   2380 };
   2381 
   2382 static const yasm_directive win32_objfmt_directives[] = {
   2383     { ".ident",         "gas",  dir_ident,      YASM_DIR_ANY },
   2384     { "ident",          "nasm", dir_ident,      YASM_DIR_ANY },
   2385     { ".def",           "gas",  dir_def,        YASM_DIR_ID_REQUIRED },
   2386     { ".endef",         "gas",  dir_endef,      YASM_DIR_ANY },
   2387     { ".scl",           "gas",  dir_scl,        YASM_DIR_ARG_REQUIRED },
   2388     { ".type",          "gas",  dir_type,       YASM_DIR_ARG_REQUIRED },
   2389     { ".secrel32",      "gas",  dir_secrel32,   YASM_DIR_ARG_REQUIRED },
   2390     { ".export",        "gas",  dir_export,     YASM_DIR_ID_REQUIRED },
   2391     { "export",         "nasm", dir_export,     YASM_DIR_ID_REQUIRED },
   2392     { ".safeseh",       "gas",  dir_safeseh,    YASM_DIR_ID_REQUIRED },
   2393     { "safeseh",        "nasm", dir_safeseh,    YASM_DIR_ID_REQUIRED },
   2394     { NULL, NULL, NULL, 0 }
   2395 };
   2396 
   2397 static const char *win32_nasm_stdmac[] = {
   2398     "%imacro export 1+.nolist",
   2399     "[export %1]",
   2400     "%endmacro",
   2401     "%imacro safeseh 1+.nolist",
   2402     "[safeseh %1]",
   2403     "%endmacro",
   2404     NULL
   2405 };
   2406 
   2407 static const yasm_stdmac win32_objfmt_stdmacs[] = {
   2408     { "nasm", "nasm", win32_nasm_stdmac },
   2409     { NULL, NULL, NULL }
   2410 };
   2411 
   2412 /* Define objfmt structure -- see objfmt.h for details */
   2413 yasm_objfmt_module yasm_win32_LTX_objfmt = {
   2414     "Win32",
   2415     "win32",
   2416     "obj",
   2417     32,
   2418     1,
   2419     winXX_objfmt_dbgfmt_keywords,
   2420     "null",
   2421     win32_objfmt_directives,
   2422     win32_objfmt_stdmacs,
   2423     win32_objfmt_create,
   2424     coff_objfmt_output,
   2425     coff_objfmt_destroy,
   2426     coff_objfmt_add_default_section,
   2427     coff_objfmt_init_new_section,
   2428     coff_objfmt_section_switch,
   2429     coff_objfmt_get_special_sym
   2430 };
   2431 
   2432 static const yasm_directive win64_objfmt_directives[] = {
   2433     { ".ident",         "gas",  dir_ident,      YASM_DIR_ANY },
   2434     { "ident",          "nasm", dir_ident,      YASM_DIR_ANY },
   2435     { ".def",           "gas",  dir_def,        YASM_DIR_ID_REQUIRED },
   2436     { ".endef",         "gas",  dir_endef,      YASM_DIR_ANY },
   2437     { ".scl",           "gas",  dir_scl,        YASM_DIR_ARG_REQUIRED },
   2438     { ".type",          "gas",  dir_type,       YASM_DIR_ARG_REQUIRED },
   2439     { ".secrel32",      "gas",  dir_secrel32,   YASM_DIR_ARG_REQUIRED },
   2440     { ".export",        "gas",  dir_export,     YASM_DIR_ID_REQUIRED },
   2441     { "export",         "nasm", dir_export,     YASM_DIR_ID_REQUIRED },
   2442     { ".proc_frame",    "gas",  dir_proc_frame, YASM_DIR_ID_REQUIRED },
   2443     { "proc_frame",     "nasm", dir_proc_frame, YASM_DIR_ID_REQUIRED },
   2444     { ".pushreg",       "gas",  dir_pushreg,    YASM_DIR_ARG_REQUIRED },
   2445     { "pushreg",        "nasm", dir_pushreg,    YASM_DIR_ARG_REQUIRED },
   2446     { ".setframe",      "gas",  dir_setframe,   YASM_DIR_ARG_REQUIRED },
   2447     { "setframe",       "nasm", dir_setframe,   YASM_DIR_ARG_REQUIRED },
   2448     { ".allocstack",    "gas",  dir_allocstack, YASM_DIR_ARG_REQUIRED },
   2449     { "allocstack",     "nasm", dir_allocstack, YASM_DIR_ARG_REQUIRED },
   2450     { ".savereg",       "gas",  dir_savereg,    YASM_DIR_ARG_REQUIRED },
   2451     { "savereg",        "nasm", dir_savereg,    YASM_DIR_ARG_REQUIRED },
   2452     { ".savexmm128",    "gas",  dir_savexmm128, YASM_DIR_ARG_REQUIRED },
   2453     { "savexmm128",     "nasm", dir_savexmm128, YASM_DIR_ARG_REQUIRED },
   2454     { ".pushframe",     "gas",  dir_pushframe,  YASM_DIR_ANY },
   2455     { "pushframe",      "nasm", dir_pushframe,  YASM_DIR_ANY },
   2456     { ".endprolog",     "gas",  dir_endprolog,  YASM_DIR_ANY },
   2457     { "endprolog",      "nasm", dir_endprolog,  YASM_DIR_ANY },
   2458     { ".endproc_frame", "gas",  dir_endproc_frame, YASM_DIR_ANY },
   2459     { "endproc_frame",  "nasm", dir_endproc_frame, YASM_DIR_ANY },
   2460     { NULL, NULL, NULL, 0 }
   2461 };
   2462 
   2463 #include "win64-nasm.c"
   2464 #include "win64-gas.c"
   2465 
   2466 static const yasm_stdmac win64_objfmt_stdmacs[] = {
   2467     { "nasm", "nasm", win64_nasm_stdmac },
   2468     { "gas", "nasm", win64_gas_stdmac },
   2469     { NULL, NULL, NULL }
   2470 };
   2471 
   2472 /* Define objfmt structure -- see objfmt.h for details */
   2473 yasm_objfmt_module yasm_win64_LTX_objfmt = {
   2474     "Win64",
   2475     "win64",
   2476     "obj",
   2477     64,
   2478     1,
   2479     winXX_objfmt_dbgfmt_keywords,
   2480     "null",
   2481     win64_objfmt_directives,
   2482     win64_objfmt_stdmacs,
   2483     win64_objfmt_create,
   2484     coff_objfmt_output,
   2485     coff_objfmt_destroy,
   2486     coff_objfmt_add_default_section,
   2487     coff_objfmt_init_new_section,
   2488     coff_objfmt_section_switch,
   2489     win64_objfmt_get_special_sym
   2490 };
   2491 yasm_objfmt_module yasm_x64_LTX_objfmt = {
   2492     "Win64",
   2493     "x64",
   2494     "obj",
   2495     64,
   2496     1,
   2497     winXX_objfmt_dbgfmt_keywords,
   2498     "null",
   2499     win64_objfmt_directives,
   2500     win64_objfmt_stdmacs,
   2501     win64_objfmt_create,
   2502     coff_objfmt_output,
   2503     coff_objfmt_destroy,
   2504     coff_objfmt_add_default_section,
   2505     coff_objfmt_init_new_section,
   2506     coff_objfmt_section_switch,
   2507     win64_objfmt_get_special_sym
   2508 };
   2509