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(§_vps);
1832 vp2 = yasm_vp_create_id(NULL, yasm__xstrdup(sectname), '\0');
1833 yasm_vps_append(§_vps, vp2);
1834 comment = coff_objfmt_section_switch(object, §_vps, NULL, line);
1835 yasm_vps_delete(§_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