• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 *
coff_objfmt_sym_set_data(yasm_symrec * sym,coff_symrec_sclass sclass,int numaux,coff_symtab_auxtype auxtype)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 *
coff_common_create(yasm_object * object)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 *
coff_objfmt_create(yasm_object * object)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 *
win32_objfmt_create(yasm_object * object)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 *
win64_objfmt_create(yasm_object * object)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
coff_objfmt_init_new_section(yasm_section * sect,unsigned long line)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
coff_objfmt_set_section_addr(yasm_section * sect,void * d)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
coff_objfmt_output_value(yasm_value * value,unsigned char * buf,unsigned int destsize,unsigned long offset,yasm_bytecode * bc,int warn,void * d)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
coff_objfmt_output_bytecode(yasm_bytecode * bc,void * d)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
coff_objfmt_output_section(yasm_section * sect,void * d)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
coff_objfmt_output_sectstr(yasm_section * sect,void * d)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
coff_objfmt_output_secthead(yasm_section * sect,void * d)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
coff_objfmt_count_sym(yasm_symrec * sym,void * d)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
coff_objfmt_output_sym(yasm_symrec * sym,void * d)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
coff_objfmt_output_str(yasm_symrec * sym,void * d)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
coff_objfmt_output(yasm_object * object,FILE * f,int all_syms,yasm_errwarns * errwarns)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
coff_objfmt_destroy(yasm_objfmt * objfmt)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 *
coff_objfmt_add_default_section(yasm_object * object)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
coff_helper_gasflags(void * obj,yasm_valparam * vp,unsigned long line,void * d,uintptr_t arg)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 *
coff_objfmt_section_switch(yasm_object * object,yasm_valparamhead * valparams,yasm_valparamhead * objext_valparams,unsigned long line)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 *
coff_objfmt_get_special_sym(yasm_object * object,const char * name,const char * parser)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 *
win64_objfmt_get_special_sym(yasm_object * object,const char * name,const char * parser)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
coff_section_data_destroy(void * data)1621 coff_section_data_destroy(void *data)
1622 {
1623     yasm_xfree(data);
1624 }
1625 
1626 static void
coff_section_data_print(void * data,FILE * f,int indent_level)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
coff_symrec_data_destroy(void * data)1658 coff_symrec_data_destroy(void *data)
1659 {
1660     yasm_xfree(data);
1661 }
1662 
1663 static void
coff_symrec_data_print(void * data,FILE * f,int indent_level)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
dir_export(yasm_object * object,yasm_valparamhead * valparams,yasm_valparamhead * objext_valparams,unsigned long line)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
dir_safeseh(yasm_object * object,yasm_valparamhead * valparams,yasm_valparamhead * objext_valparams,unsigned long line)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
win32_sxdata_bc_destroy(void * contents)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
win32_sxdata_bc_print(const void * contents,FILE * f,int indent_level)1770 win32_sxdata_bc_print(const void *contents, FILE *f, int indent_level)
1771 {
1772     /* TODO */
1773 }
1774 
1775 static int
win32_sxdata_bc_calc_len(yasm_bytecode * bc,yasm_bc_add_span_func add_span,void * add_span_data)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
win32_sxdata_bc_tobytes(yasm_bytecode * bc,unsigned char ** bufp,unsigned char * bufstart,void * d,yasm_output_value_func output_value,yasm_output_reloc_func output_reloc)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
dir_ident(yasm_object * object,yasm_valparamhead * valparams,yasm_valparamhead * objext_valparams,unsigned long line)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
dir_secrel32(yasm_object * object,yasm_valparamhead * valparams,yasm_valparamhead * objext_valparams,unsigned long line)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
dir_def(yasm_object * object,yasm_valparamhead * valparams,yasm_valparamhead * objext_valparams,unsigned long line)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
dir_scl(yasm_object * object,yasm_valparamhead * valparams,yasm_valparamhead * objext_valparams,unsigned long line)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
dir_type(yasm_object * object,yasm_valparamhead * valparams,yasm_valparamhead * objext_valparams,unsigned long line)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
dir_endef(yasm_object * object,yasm_valparamhead * valparams,yasm_valparamhead * objext_valparams,unsigned long line)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
dir_proc_frame(yasm_object * object,yasm_valparamhead * valparams,yasm_valparamhead * objext_valparams,unsigned long line)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
procframe_checkstate(yasm_objfmt_coff * objfmt_coff,const char * dirname)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 *
get_curpos(yasm_object * object,const char * dirname,unsigned long line)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
dir_pushreg(yasm_object * object,yasm_valparamhead * valparams,yasm_valparamhead * objext_valparams,unsigned long line)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
dir_setframe(yasm_object * object,yasm_valparamhead * valparams,yasm_valparamhead * objext_valparams,unsigned long line)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
dir_allocstack(yasm_object * object,yasm_valparamhead * valparams,yasm_valparamhead * objext_valparams,unsigned long line)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
dir_save_common(yasm_object * object,yasm_valparamhead * valparams,unsigned long line,const char * name,int op)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
dir_savereg(yasm_object * object,yasm_valparamhead * valparams,yasm_valparamhead * objext_valparams,unsigned long line)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
dir_savexmm128(yasm_object * object,yasm_valparamhead * valparams,yasm_valparamhead * objext_valparams,unsigned long line)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
dir_pushframe(yasm_object * object,yasm_valparamhead * valparams,yasm_valparamhead * objext_valparams,unsigned long line)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
dir_endprolog(yasm_object * object,yasm_valparamhead * valparams,yasm_valparamhead * objext_valparams,unsigned long line)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
dir_endproc_frame(yasm_object * object,yasm_valparamhead * valparams,yasm_valparamhead * objext_valparams,unsigned long line)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