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