1 /* 2 * Extended Dynamic Object format 3 * 4 * Copyright (C) 2004-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 29 #include <libyasm.h> 30 31 32 #define REGULAR_OUTBUF_SIZE 1024 33 34 #define XDF_MAGIC 0x87654322 35 36 #define XDF_SYM_EXTERN 1 37 #define XDF_SYM_GLOBAL 2 38 #define XDF_SYM_EQU 4 39 40 typedef struct xdf_reloc { 41 yasm_reloc reloc; 42 /*@null@*/ yasm_symrec *base; /* base symbol (for WRT) */ 43 enum { 44 XDF_RELOC_REL = 1, /* relative to segment */ 45 XDF_RELOC_WRT = 2, /* relative to symbol */ 46 XDF_RELOC_RIP = 4, /* RIP-relative */ 47 XDF_RELOC_SEG = 8 /* segment containing symbol */ 48 } type; /* type of relocation */ 49 enum { 50 XDF_RELOC_8 = 1, 51 XDF_RELOC_16 = 2, 52 XDF_RELOC_32 = 4, 53 XDF_RELOC_64 = 8 54 } size; /* size of relocation */ 55 unsigned int shift; /* relocation shift (0,4,8,16,24,32) */ 56 } xdf_reloc; 57 58 typedef struct xdf_section_data { 59 /*@dependent@*/ yasm_symrec *sym; /* symbol created for this section */ 60 yasm_intnum *addr; /* starting memory address */ 61 yasm_intnum *vaddr; /* starting virtual address */ 62 long scnum; /* section number (0=first section) */ 63 enum { 64 XDF_SECT_ABSOLUTE = 0x01, 65 XDF_SECT_FLAT = 0x02, 66 XDF_SECT_BSS = 0x04, 67 XDF_SECT_EQU = 0x08, 68 XDF_SECT_USE_16 = 0x10, 69 XDF_SECT_USE_32 = 0x20, 70 XDF_SECT_USE_64 = 0x40 71 } flags; /* section flags */ 72 unsigned long scnptr; /* file ptr to raw data */ 73 unsigned long size; /* size of raw data (section data) in bytes */ 74 unsigned long relptr; /* file ptr to relocation */ 75 unsigned long nreloc; /* number of relocation entries >64k -> error */ 76 } xdf_section_data; 77 78 typedef struct xdf_symrec_data { 79 unsigned long index; /* assigned XDF symbol table index */ 80 } xdf_symrec_data; 81 82 typedef struct yasm_objfmt_xdf { 83 yasm_objfmt_base objfmt; /* base structure */ 84 85 long parse_scnum; /* sect numbering in parser */ 86 } yasm_objfmt_xdf; 87 88 typedef struct xdf_objfmt_output_info { 89 yasm_object *object; 90 yasm_objfmt_xdf *objfmt_xdf; 91 yasm_errwarns *errwarns; 92 /*@dependent@*/ FILE *f; 93 /*@only@*/ unsigned char *buf; 94 yasm_section *sect; 95 /*@dependent@*/ xdf_section_data *xsd; 96 97 unsigned long indx; /* current symbol index */ 98 int all_syms; /* outputting all symbols? */ 99 unsigned long strtab_offset; /* current string table offset */ 100 } xdf_objfmt_output_info; 101 102 static void xdf_section_data_destroy(/*@only@*/ void *d); 103 static void xdf_section_data_print(void *data, FILE *f, int indent_level); 104 105 static const yasm_assoc_data_callback xdf_section_data_cb = { 106 xdf_section_data_destroy, 107 xdf_section_data_print 108 }; 109 110 static void xdf_symrec_data_destroy(/*@only@*/ void *d); 111 static void xdf_symrec_data_print(void *data, FILE *f, int indent_level); 112 113 static const yasm_assoc_data_callback xdf_symrec_data_cb = { 114 xdf_symrec_data_destroy, 115 xdf_symrec_data_print 116 }; 117 118 yasm_objfmt_module yasm_xdf_LTX_objfmt; 119 120 121 static yasm_objfmt * 122 xdf_objfmt_create(yasm_object *object) 123 { 124 yasm_objfmt_xdf *objfmt_xdf = yasm_xmalloc(sizeof(yasm_objfmt_xdf)); 125 126 /* Only support x86 arch */ 127 if (yasm__strcasecmp(yasm_arch_keyword(object->arch), "x86") != 0) { 128 yasm_xfree(objfmt_xdf); 129 return NULL; 130 } 131 132 /* Support x86 and amd64 machines of x86 arch */ 133 if (yasm__strcasecmp(yasm_arch_get_machine(object->arch), "x86") && 134 yasm__strcasecmp(yasm_arch_get_machine(object->arch), "amd64")) { 135 yasm_xfree(objfmt_xdf); 136 return NULL; 137 } 138 139 objfmt_xdf->parse_scnum = 0; /* section numbering starts at 0 */ 140 141 objfmt_xdf->objfmt.module = &yasm_xdf_LTX_objfmt; 142 143 return (yasm_objfmt *)objfmt_xdf; 144 } 145 146 static int 147 xdf_objfmt_output_value(yasm_value *value, unsigned char *buf, 148 unsigned int destsize, unsigned long offset, 149 yasm_bytecode *bc, int warn, /*@null@*/ void *d) 150 { 151 /*@null@*/ xdf_objfmt_output_info *info = (xdf_objfmt_output_info *)d; 152 yasm_objfmt_xdf *objfmt_xdf; 153 /*@dependent@*/ /*@null@*/ yasm_intnum *intn; 154 unsigned long intn_minus; 155 int retval; 156 unsigned int valsize = value->size; 157 158 assert(info != NULL); 159 objfmt_xdf = info->objfmt_xdf; 160 161 if (value->abs) 162 value->abs = yasm_expr_simplify(value->abs, 1); 163 164 /* Try to output constant and PC-relative section-local first. 165 * Note this does NOT output any value with a SEG, WRT, external, 166 * cross-section, or non-PC-relative reference (those are handled below). 167 */ 168 switch (yasm_value_output_basic(value, buf, destsize, bc, warn, 169 info->object->arch)) { 170 case -1: 171 return 1; 172 case 0: 173 break; 174 default: 175 return 0; 176 } 177 178 if (value->section_rel) { 179 yasm_error_set(YASM_ERROR_TOO_COMPLEX, 180 N_("xdf: relocation too complex")); 181 return 1; 182 } 183 184 intn_minus = 0; 185 if (value->rel) { 186 xdf_reloc *reloc; 187 188 reloc = yasm_xmalloc(sizeof(xdf_reloc)); 189 reloc->reloc.addr = yasm_intnum_create_uint(bc->offset + offset); 190 reloc->reloc.sym = value->rel; 191 reloc->base = NULL; 192 reloc->size = valsize/8; 193 reloc->shift = value->rshift; 194 195 if (value->seg_of) 196 reloc->type = XDF_RELOC_SEG; 197 else if (value->wrt) { 198 reloc->base = value->wrt; 199 reloc->type = XDF_RELOC_WRT; 200 } else if (value->curpos_rel) { 201 reloc->type = XDF_RELOC_RIP; 202 /* Adjust to start of section, so subtract out the bytecode 203 * offset. 204 */ 205 intn_minus = bc->offset; 206 } else 207 reloc->type = XDF_RELOC_REL; 208 info->xsd->nreloc++; 209 yasm_section_add_reloc(info->sect, (yasm_reloc *)reloc, yasm_xfree); 210 } 211 212 if (intn_minus > 0) { 213 intn = yasm_intnum_create_uint(intn_minus); 214 yasm_intnum_calc(intn, YASM_EXPR_NEG, NULL); 215 } else 216 intn = yasm_intnum_create_uint(0); 217 218 if (value->abs) { 219 yasm_intnum *intn2 = yasm_expr_get_intnum(&value->abs, 0); 220 if (!intn2) { 221 yasm_error_set(YASM_ERROR_TOO_COMPLEX, 222 N_("xdf: relocation too complex")); 223 yasm_intnum_destroy(intn); 224 return 1; 225 } 226 yasm_intnum_calc(intn, YASM_EXPR_ADD, intn2); 227 } 228 229 retval = yasm_arch_intnum_tobytes(info->object->arch, intn, buf, destsize, 230 valsize, 0, bc, warn); 231 yasm_intnum_destroy(intn); 232 return retval; 233 } 234 235 static int 236 xdf_objfmt_output_bytecode(yasm_bytecode *bc, /*@null@*/ void *d) 237 { 238 /*@null@*/ xdf_objfmt_output_info *info = (xdf_objfmt_output_info *)d; 239 /*@null@*/ /*@only@*/ unsigned char *bigbuf; 240 unsigned long size = REGULAR_OUTBUF_SIZE; 241 int gap; 242 243 assert(info != NULL); 244 245 bigbuf = yasm_bc_tobytes(bc, info->buf, &size, &gap, info, 246 xdf_objfmt_output_value, NULL); 247 248 /* Don't bother doing anything else if size ended up being 0. */ 249 if (size == 0) { 250 if (bigbuf) 251 yasm_xfree(bigbuf); 252 return 0; 253 } 254 255 info->xsd->size += size; 256 257 /* Warn that gaps are converted to 0 and write out the 0's. */ 258 if (gap) { 259 unsigned long left; 260 yasm_warn_set(YASM_WARN_UNINIT_CONTENTS, 261 N_("uninitialized space: zeroing")); 262 /* Write out in chunks */ 263 memset(info->buf, 0, REGULAR_OUTBUF_SIZE); 264 left = size; 265 while (left > REGULAR_OUTBUF_SIZE) { 266 fwrite(info->buf, REGULAR_OUTBUF_SIZE, 1, info->f); 267 left -= REGULAR_OUTBUF_SIZE; 268 } 269 fwrite(info->buf, left, 1, info->f); 270 } else { 271 /* Output buf (or bigbuf if non-NULL) to file */ 272 fwrite(bigbuf ? bigbuf : info->buf, (size_t)size, 1, info->f); 273 } 274 275 /* If bigbuf was allocated, free it */ 276 if (bigbuf) 277 yasm_xfree(bigbuf); 278 279 return 0; 280 } 281 282 static int 283 xdf_objfmt_output_section(yasm_section *sect, /*@null@*/ void *d) 284 { 285 /*@null@*/ xdf_objfmt_output_info *info = (xdf_objfmt_output_info *)d; 286 /*@dependent@*/ /*@null@*/ xdf_section_data *xsd; 287 long pos; 288 xdf_reloc *reloc; 289 290 assert(info != NULL); 291 xsd = yasm_section_get_data(sect, &xdf_section_data_cb); 292 assert(xsd != NULL); 293 294 if (xsd->flags & XDF_SECT_BSS) { 295 /* Don't output BSS sections. 296 * TODO: Check for non-reserve bytecodes? 297 */ 298 pos = 0; /* position = 0 because it's not in the file */ 299 xsd->size = yasm_bc_next_offset(yasm_section_bcs_last(sect)); 300 } else { 301 pos = ftell(info->f); 302 if (pos == -1) { 303 yasm__fatal(N_("could not get file position on output file")); 304 /*@notreached@*/ 305 return 1; 306 } 307 308 info->sect = sect; 309 info->xsd = xsd; 310 yasm_section_bcs_traverse(sect, info->errwarns, info, 311 xdf_objfmt_output_bytecode); 312 313 /* Sanity check final section size */ 314 if (xsd->size != yasm_bc_next_offset(yasm_section_bcs_last(sect))) 315 yasm_internal_error( 316 N_("xdf: section computed size did not match actual size")); 317 } 318 319 /* Empty? Go on to next section */ 320 if (xsd->size == 0) 321 return 0; 322 323 xsd->scnptr = (unsigned long)pos; 324 325 /* No relocations to output? Go on to next section */ 326 if (xsd->nreloc == 0) 327 return 0; 328 329 pos = ftell(info->f); 330 if (pos == -1) { 331 yasm__fatal(N_("could not get file position on output file")); 332 /*@notreached@*/ 333 return 1; 334 } 335 xsd->relptr = (unsigned long)pos; 336 337 reloc = (xdf_reloc *)yasm_section_relocs_first(sect); 338 while (reloc) { 339 unsigned char *localbuf = info->buf; 340 /*@null@*/ xdf_symrec_data *xsymd; 341 342 xsymd = yasm_symrec_get_data(reloc->reloc.sym, &xdf_symrec_data_cb); 343 if (!xsymd) 344 yasm_internal_error( 345 N_("xdf: no symbol data for relocated symbol")); 346 347 yasm_intnum_get_sized(reloc->reloc.addr, localbuf, 4, 32, 0, 0, 0); 348 localbuf += 4; /* address of relocation */ 349 YASM_WRITE_32_L(localbuf, xsymd->index); /* relocated symbol */ 350 if (reloc->base) { 351 xsymd = yasm_symrec_get_data(reloc->base, &xdf_symrec_data_cb); 352 if (!xsymd) 353 yasm_internal_error( 354 N_("xdf: no symbol data for relocated base symbol")); 355 YASM_WRITE_32_L(localbuf, xsymd->index); /* base symbol */ 356 } else { 357 if (reloc->type == XDF_RELOC_WRT) 358 yasm_internal_error( 359 N_("xdf: no base symbol for WRT relocation")); 360 YASM_WRITE_32_L(localbuf, 0); /* no base symbol */ 361 } 362 YASM_WRITE_8(localbuf, reloc->type); /* type of relocation */ 363 YASM_WRITE_8(localbuf, reloc->size); /* size of relocation */ 364 YASM_WRITE_8(localbuf, reloc->shift); /* relocation shift */ 365 YASM_WRITE_8(localbuf, 0); /* flags */ 366 fwrite(info->buf, 16, 1, info->f); 367 368 reloc = (xdf_reloc *)yasm_section_reloc_next((yasm_reloc *)reloc); 369 } 370 371 return 0; 372 } 373 374 static int 375 xdf_objfmt_output_secthead(yasm_section *sect, /*@null@*/ void *d) 376 { 377 /*@null@*/ xdf_objfmt_output_info *info = (xdf_objfmt_output_info *)d; 378 yasm_objfmt_xdf *objfmt_xdf; 379 /*@dependent@*/ /*@null@*/ xdf_section_data *xsd; 380 /*@null@*/ xdf_symrec_data *xsymd; 381 unsigned char *localbuf; 382 383 assert(info != NULL); 384 objfmt_xdf = info->objfmt_xdf; 385 xsd = yasm_section_get_data(sect, &xdf_section_data_cb); 386 assert(xsd != NULL); 387 388 localbuf = info->buf; 389 xsymd = yasm_symrec_get_data(xsd->sym, &xdf_symrec_data_cb); 390 assert(xsymd != NULL); 391 392 YASM_WRITE_32_L(localbuf, xsymd->index); /* section name symbol */ 393 if (xsd->addr) { 394 yasm_intnum_get_sized(xsd->addr, localbuf, 8, 64, 0, 0, 0); 395 localbuf += 8; /* physical address */ 396 } else { 397 YASM_WRITE_32_L(localbuf, 0); 398 YASM_WRITE_32_L(localbuf, 0); 399 } 400 if (xsd->vaddr) { 401 yasm_intnum_get_sized(xsd->vaddr, localbuf, 8, 64, 0, 0, 0); 402 localbuf += 8; /* virtual address */ 403 } else if (xsd->addr) { 404 yasm_intnum_get_sized(xsd->addr, localbuf, 8, 64, 0, 0, 0); 405 localbuf += 8; /* VA=PA */ 406 } else { 407 YASM_WRITE_32_L(localbuf, 0); 408 YASM_WRITE_32_L(localbuf, 0); 409 } 410 YASM_WRITE_16_L(localbuf, yasm_section_get_align(sect)); /* alignment */ 411 YASM_WRITE_16_L(localbuf, xsd->flags); /* flags */ 412 YASM_WRITE_32_L(localbuf, xsd->scnptr); /* file ptr to data */ 413 YASM_WRITE_32_L(localbuf, xsd->size); /* section size */ 414 YASM_WRITE_32_L(localbuf, xsd->relptr); /* file ptr to relocs */ 415 YASM_WRITE_32_L(localbuf, xsd->nreloc); /* num of relocation entries */ 416 fwrite(info->buf, 40, 1, info->f); 417 418 return 0; 419 } 420 421 static int 422 xdf_objfmt_count_sym(yasm_symrec *sym, /*@null@*/ void *d) 423 { 424 /*@null@*/ xdf_objfmt_output_info *info = (xdf_objfmt_output_info *)d; 425 yasm_sym_vis vis = yasm_symrec_get_visibility(sym); 426 assert(info != NULL); 427 if (vis & YASM_SYM_COMMON) { 428 yasm_error_set(YASM_ERROR_GENERAL, 429 N_("XDF object format does not support common variables")); 430 yasm_errwarn_propagate(info->errwarns, yasm_symrec_get_decl_line(sym)); 431 return 0; 432 } 433 if (info->all_syms || 434 (vis != YASM_SYM_LOCAL && !(vis & YASM_SYM_DLOCAL))) { 435 /* Save index in symrec data */ 436 xdf_symrec_data *sym_data = yasm_xmalloc(sizeof(xdf_symrec_data)); 437 sym_data->index = info->indx; 438 yasm_symrec_add_data(sym, &xdf_symrec_data_cb, sym_data); 439 440 info->indx++; 441 } 442 return 0; 443 } 444 445 static int 446 xdf_objfmt_output_sym(yasm_symrec *sym, /*@null@*/ void *d) 447 { 448 /*@null@*/ xdf_objfmt_output_info *info = (xdf_objfmt_output_info *)d; 449 yasm_sym_vis vis = yasm_symrec_get_visibility(sym); 450 451 assert(info != NULL); 452 453 if (info->all_syms || vis != YASM_SYM_LOCAL) { 454 /*@only@*/ char *name = yasm_symrec_get_global_name(sym, info->object); 455 const yasm_expr *equ_val; 456 const yasm_intnum *intn; 457 size_t len = strlen(name); 458 unsigned long value = 0; 459 long scnum = -3; /* -3 = debugging symbol */ 460 /*@dependent@*/ /*@null@*/ yasm_section *sect; 461 /*@dependent@*/ /*@null@*/ yasm_bytecode *precbc; 462 unsigned long flags = 0; 463 unsigned char *localbuf; 464 465 if (vis & YASM_SYM_GLOBAL) 466 flags = XDF_SYM_GLOBAL; 467 468 /* Look at symrec for value/scnum/etc. */ 469 if (yasm_symrec_get_label(sym, &precbc)) { 470 if (precbc) 471 sect = yasm_bc_get_section(precbc); 472 else 473 sect = NULL; 474 /* it's a label: get value and offset. 475 * If there is not a section, leave as debugging symbol. 476 */ 477 if (sect) { 478 /*@dependent@*/ /*@null@*/ xdf_section_data *csectd; 479 csectd = yasm_section_get_data(sect, &xdf_section_data_cb); 480 if (csectd) 481 scnum = csectd->scnum; 482 else 483 yasm_internal_error(N_("didn't understand section")); 484 if (precbc) 485 value += yasm_bc_next_offset(precbc); 486 } 487 } else if ((equ_val = yasm_symrec_get_equ(sym))) { 488 yasm_expr *equ_val_copy = yasm_expr_copy(equ_val); 489 intn = yasm_expr_get_intnum(&equ_val_copy, 1); 490 if (!intn) { 491 if (vis & YASM_SYM_GLOBAL) { 492 yasm_error_set(YASM_ERROR_NOT_CONSTANT, 493 N_("global EQU value not an integer expression")); 494 yasm_errwarn_propagate(info->errwarns, equ_val->line); 495 } 496 } else 497 value = yasm_intnum_get_uint(intn); 498 yasm_expr_destroy(equ_val_copy); 499 500 flags |= XDF_SYM_EQU; 501 scnum = -2; /* -2 = absolute symbol */ 502 } else { 503 if (vis & YASM_SYM_EXTERN) { 504 flags = XDF_SYM_EXTERN; 505 scnum = -1; 506 } 507 } 508 509 localbuf = info->buf; 510 YASM_WRITE_32_L(localbuf, scnum); /* section number */ 511 YASM_WRITE_32_L(localbuf, value); /* value */ 512 YASM_WRITE_32_L(localbuf, info->strtab_offset); 513 info->strtab_offset += (unsigned long)(len+1); 514 YASM_WRITE_32_L(localbuf, flags); /* flags */ 515 fwrite(info->buf, 16, 1, info->f); 516 yasm_xfree(name); 517 } 518 return 0; 519 } 520 521 static int 522 xdf_objfmt_output_str(yasm_symrec *sym, /*@null@*/ void *d) 523 { 524 /*@null@*/ xdf_objfmt_output_info *info = (xdf_objfmt_output_info *)d; 525 yasm_sym_vis vis = yasm_symrec_get_visibility(sym); 526 527 assert(info != NULL); 528 529 if (info->all_syms || vis != YASM_SYM_LOCAL) { 530 /*@only@*/ char *name = yasm_symrec_get_global_name(sym, info->object); 531 size_t len = strlen(name); 532 fwrite(name, len+1, 1, info->f); 533 yasm_xfree(name); 534 } 535 return 0; 536 } 537 538 static void 539 xdf_objfmt_output(yasm_object *object, FILE *f, int all_syms, 540 yasm_errwarns *errwarns) 541 { 542 yasm_objfmt_xdf *objfmt_xdf = (yasm_objfmt_xdf *)object->objfmt; 543 xdf_objfmt_output_info info; 544 unsigned char *localbuf; 545 unsigned long symtab_count = 0; 546 547 info.object = object; 548 info.objfmt_xdf = objfmt_xdf; 549 info.errwarns = errwarns; 550 info.f = f; 551 info.buf = yasm_xmalloc(REGULAR_OUTBUF_SIZE); 552 553 /* Allocate space for headers by seeking forward */ 554 if (fseek(f, (long)(16+40*(objfmt_xdf->parse_scnum)), SEEK_SET) < 0) { 555 yasm__fatal(N_("could not seek on output file")); 556 /*@notreached@*/ 557 return; 558 } 559 560 /* Get number of symbols */ 561 info.indx = 0; 562 info.all_syms = 1; /* force all syms into symbol table */ 563 yasm_symtab_traverse(object->symtab, &info, xdf_objfmt_count_sym); 564 symtab_count = info.indx; 565 566 /* Get file offset of start of string table */ 567 info.strtab_offset = 16+40*(objfmt_xdf->parse_scnum)+16*symtab_count; 568 569 /* Output symbol table */ 570 yasm_symtab_traverse(object->symtab, &info, xdf_objfmt_output_sym); 571 572 /* Output string table */ 573 yasm_symtab_traverse(object->symtab, &info, xdf_objfmt_output_str); 574 575 /* Section data/relocs */ 576 if (yasm_object_sections_traverse(object, &info, 577 xdf_objfmt_output_section)) 578 return; 579 580 /* Write headers */ 581 if (fseek(f, 0, SEEK_SET) < 0) { 582 yasm__fatal(N_("could not seek on output file")); 583 /*@notreached@*/ 584 return; 585 } 586 587 localbuf = info.buf; 588 YASM_WRITE_32_L(localbuf, XDF_MAGIC); /* magic number */ 589 YASM_WRITE_32_L(localbuf, objfmt_xdf->parse_scnum); /* number of sects */ 590 YASM_WRITE_32_L(localbuf, symtab_count); /* number of symtabs */ 591 /* size of sect headers + symbol table + strings */ 592 YASM_WRITE_32_L(localbuf, info.strtab_offset-16); 593 fwrite(info.buf, 16, 1, f); 594 595 yasm_object_sections_traverse(object, &info, xdf_objfmt_output_secthead); 596 597 yasm_xfree(info.buf); 598 } 599 600 static void 601 xdf_objfmt_destroy(yasm_objfmt *objfmt) 602 { 603 yasm_xfree(objfmt); 604 } 605 606 static void 607 xdf_objfmt_init_new_section(yasm_section *sect, unsigned long line) 608 { 609 yasm_object *object = yasm_section_get_object(sect); 610 const char *sectname = yasm_section_get_name(sect); 611 yasm_objfmt_xdf *objfmt_xdf = (yasm_objfmt_xdf *)object->objfmt; 612 xdf_section_data *data; 613 yasm_symrec *sym; 614 615 data = yasm_xmalloc(sizeof(xdf_section_data)); 616 data->scnum = objfmt_xdf->parse_scnum++; 617 data->flags = 0; 618 data->addr = NULL; 619 data->vaddr = NULL; 620 data->scnptr = 0; 621 data->size = 0; 622 data->relptr = 0; 623 data->nreloc = 0; 624 yasm_section_add_data(sect, &xdf_section_data_cb, data); 625 626 sym = yasm_symtab_define_label(object->symtab, sectname, 627 yasm_section_bcs_first(sect), 1, line); 628 data->sym = sym; 629 } 630 631 static yasm_section * 632 xdf_objfmt_add_default_section(yasm_object *object) 633 { 634 yasm_section *retval; 635 int isnew; 636 637 retval = yasm_object_get_general(object, ".text", 0, 1, 0, &isnew, 0); 638 if (isnew) 639 yasm_section_set_default(retval, 1); 640 return retval; 641 } 642 643 static int 644 xdf_helper_use(void *obj, yasm_valparam *vp, unsigned long line, void *d, 645 uintptr_t bits) 646 { 647 yasm_object *object = (yasm_object *)obj; 648 unsigned long *flags = (unsigned long *)d; 649 *flags &= ~(XDF_SECT_USE_16|XDF_SECT_USE_32|XDF_SECT_USE_64); 650 switch (bits) { 651 case 16: *flags |= XDF_SECT_USE_16; break; 652 case 32: *flags |= XDF_SECT_USE_32; break; 653 case 64: *flags |= XDF_SECT_USE_64; break; 654 }; 655 yasm_arch_set_var(object->arch, "mode_bits", bits); 656 return 0; 657 } 658 659 static /*@observer@*/ /*@null@*/ yasm_section * 660 xdf_objfmt_section_switch(yasm_object *object, yasm_valparamhead *valparams, 661 /*@unused@*/ /*@null@*/ 662 yasm_valparamhead *objext_valparams, 663 unsigned long line) 664 { 665 yasm_valparam *vp; 666 yasm_section *retval; 667 int isnew; 668 int flags_override = 0; 669 const char *sectname; 670 int resonly = 0; 671 xdf_section_data *xsd; 672 unsigned long align = 0; 673 674 struct xdf_section_switch_data { 675 /*@only@*/ /*@null@*/ yasm_intnum *absaddr; 676 /*@only@*/ /*@null@*/ yasm_intnum *vaddr; 677 /*@only@*/ /*@null@*/ yasm_intnum *align_intn; 678 unsigned long flags; 679 } data; 680 681 static const yasm_dir_help help[] = { 682 { "use16", 0, xdf_helper_use, 683 offsetof(struct xdf_section_switch_data, flags), 16 }, 684 { "use32", 0, xdf_helper_use, 685 offsetof(struct xdf_section_switch_data, flags), 32 }, 686 { "use64", 0, xdf_helper_use, 687 offsetof(struct xdf_section_switch_data, flags), 64 }, 688 { "bss", 0, yasm_dir_helper_flag_or, 689 offsetof(struct xdf_section_switch_data, flags), XDF_SECT_BSS }, 690 { "flat", 0, yasm_dir_helper_flag_or, 691 offsetof(struct xdf_section_switch_data, flags), XDF_SECT_FLAT }, 692 { "absolute", 1, yasm_dir_helper_intn, 693 offsetof(struct xdf_section_switch_data, absaddr), 0 }, 694 { "virtual", 1, yasm_dir_helper_intn, 695 offsetof(struct xdf_section_switch_data, vaddr), 0 }, 696 { "align", 1, yasm_dir_helper_intn, 697 offsetof(struct xdf_section_switch_data, align_intn), 0 } 698 }; 699 700 data.absaddr = NULL; 701 data.vaddr = NULL; 702 data.align_intn = NULL; 703 data.flags = 0; 704 705 vp = yasm_vps_first(valparams); 706 sectname = yasm_vp_string(vp); 707 if (!sectname) 708 return NULL; 709 vp = yasm_vps_next(vp); 710 711 flags_override = yasm_dir_helper(object, vp, line, help, NELEMS(help), 712 &data, yasm_dir_helper_valparam_warn); 713 if (flags_override < 0) 714 return NULL; /* error occurred */ 715 716 if (data.absaddr) 717 data.flags |= XDF_SECT_ABSOLUTE; 718 if (data.align_intn) { 719 align = yasm_intnum_get_uint(data.align_intn); 720 yasm_intnum_destroy(data.align_intn); 721 722 /* Alignments must be a power of two. */ 723 if (!is_exp2(align)) { 724 yasm_error_set(YASM_ERROR_VALUE, 725 N_("argument to `%s' is not a power of two"), 726 "align"); 727 if (data.vaddr) 728 yasm_intnum_destroy(data.vaddr); 729 if (data.absaddr) 730 yasm_intnum_destroy(data.absaddr); 731 return NULL; 732 } 733 734 /* Check to see if alignment is supported size */ 735 if (align > 4096) { 736 yasm_error_set(YASM_ERROR_VALUE, 737 N_("XDF does not support alignments > 4096")); 738 if (data.vaddr) 739 yasm_intnum_destroy(data.vaddr); 740 if (data.absaddr) 741 yasm_intnum_destroy(data.absaddr); 742 return NULL; 743 } 744 } 745 746 retval = yasm_object_get_general(object, sectname, align, 1, resonly, 747 &isnew, line); 748 749 xsd = yasm_section_get_data(retval, &xdf_section_data_cb); 750 751 if (isnew || yasm_section_is_default(retval)) { 752 yasm_section_set_default(retval, 0); 753 xsd->flags = data.flags; 754 if (data.absaddr) { 755 if (xsd->addr) 756 yasm_intnum_destroy(xsd->addr); 757 xsd->addr = data.absaddr; 758 } 759 if (data.vaddr) { 760 if (xsd->vaddr) 761 yasm_intnum_destroy(xsd->vaddr); 762 xsd->vaddr = data.vaddr; 763 } 764 yasm_section_set_align(retval, align, line); 765 } else if (flags_override) 766 yasm_warn_set(YASM_WARN_GENERAL, 767 N_("section flags ignored on section redeclaration")); 768 return retval; 769 } 770 771 static /*@observer@*/ /*@null@*/ yasm_symrec * 772 xdf_objfmt_get_special_sym(yasm_object *object, const char *name, 773 const char *parser) 774 { 775 return NULL; 776 } 777 778 static void 779 xdf_section_data_destroy(void *data) 780 { 781 xdf_section_data *xsd = (xdf_section_data *)data; 782 if (xsd->addr) 783 yasm_intnum_destroy(xsd->addr); 784 if (xsd->vaddr) 785 yasm_intnum_destroy(xsd->vaddr); 786 yasm_xfree(data); 787 } 788 789 static void 790 xdf_section_data_print(void *data, FILE *f, int indent_level) 791 { 792 xdf_section_data *xsd = (xdf_section_data *)data; 793 794 fprintf(f, "%*ssym=\n", indent_level, ""); 795 yasm_symrec_print(xsd->sym, f, indent_level+1); 796 fprintf(f, "%*sscnum=%ld\n", indent_level, "", xsd->scnum); 797 fprintf(f, "%*sflags=0x%x\n", indent_level, "", xsd->flags); 798 fprintf(f, "%*saddr=", indent_level, ""); 799 yasm_intnum_print(xsd->addr, f); 800 fprintf(f, "%*svaddr=", indent_level, ""); 801 yasm_intnum_print(xsd->vaddr, f); 802 fprintf(f, "%*sscnptr=0x%lx\n", indent_level, "", xsd->scnptr); 803 fprintf(f, "%*ssize=%ld\n", indent_level, "", xsd->size); 804 fprintf(f, "%*srelptr=0x%lx\n", indent_level, "", xsd->relptr); 805 fprintf(f, "%*snreloc=%ld\n", indent_level, "", xsd->nreloc); 806 } 807 808 static void 809 xdf_symrec_data_destroy(void *data) 810 { 811 yasm_xfree(data); 812 } 813 814 static void 815 xdf_symrec_data_print(void *data, FILE *f, int indent_level) 816 { 817 xdf_symrec_data *xsd = (xdf_symrec_data *)data; 818 819 fprintf(f, "%*ssymtab index=%lu\n", indent_level, "", xsd->index); 820 } 821 822 /* Define valid debug formats to use with this object format */ 823 static const char *xdf_objfmt_dbgfmt_keywords[] = { 824 "null", 825 NULL 826 }; 827 828 /* Define objfmt structure -- see objfmt.h for details */ 829 yasm_objfmt_module yasm_xdf_LTX_objfmt = { 830 "Extended Dynamic Object", 831 "xdf", 832 "xdf", 833 32, 834 0, 835 xdf_objfmt_dbgfmt_keywords, 836 "null", 837 NULL, /* no directives */ 838 NULL, /* no standard macros */ 839 xdf_objfmt_create, 840 xdf_objfmt_output, 841 xdf_objfmt_destroy, 842 xdf_objfmt_add_default_section, 843 xdf_objfmt_init_new_section, 844 xdf_objfmt_section_switch, 845 xdf_objfmt_get_special_sym 846 }; 847