1 /* 2 * Relocatable Dynamic Object File Format (RDOFF) version 2 format 3 * 4 * Copyright (C) 2006-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 RDF_MAGIC "RDOFF2" 35 36 /* Maximum size of an import/export label (including trailing zero) */ 37 #define EXIM_LABEL_MAX 64 38 39 /* Maximum size of library or module name (including trailing zero) */ 40 #define MODLIB_NAME_MAX 128 41 42 /* Maximum number of segments that we can handle in one file */ 43 #define RDF_MAXSEGS 64 44 45 /* Record types that may present the RDOFF header */ 46 #define RDFREC_GENERIC 0 47 #define RDFREC_RELOC 1 48 #define RDFREC_IMPORT 2 49 #define RDFREC_GLOBAL 3 50 #define RDFREC_DLL 4 51 #define RDFREC_BSS 5 52 #define RDFREC_SEGRELOC 6 53 #define RDFREC_FARIMPORT 7 54 #define RDFREC_MODNAME 8 55 #define RDFREC_COMMON 10 56 57 /* Flags for ExportRec/ImportRec */ 58 #define SYM_DATA 1 59 #define SYM_FUNCTION 2 60 61 /* Flags for ExportRec */ 62 #define SYM_GLOBAL 4 63 64 /* Flags for ImportRec */ 65 #define SYM_IMPORT 8 66 #define SYM_FAR 16 67 68 typedef struct rdf_reloc { 69 yasm_reloc reloc; 70 enum { 71 RDF_RELOC_NORM, /* normal */ 72 RDF_RELOC_REL, /* relative to current position */ 73 RDF_RELOC_SEG /* segment containing symbol */ 74 } type; /* type of relocation */ 75 unsigned int size; 76 unsigned int refseg; 77 } rdf_reloc; 78 79 typedef struct rdf_section_data { 80 /*@dependent@*/ yasm_symrec *sym; /* symbol created for this section */ 81 long scnum; /* section number (0=first section) */ 82 enum { 83 RDF_SECT_BSS = 0, 84 RDF_SECT_CODE = 1, 85 RDF_SECT_DATA = 2, 86 RDF_SECT_COMMENT = 3, 87 RDF_SECT_LCOMMENT = 4, 88 RDF_SECT_PCOMMENT = 5, 89 RDF_SECT_SYMDEBUG = 6, 90 RDF_SECT_LINEDEBUG = 7 91 } type; /* section type */ 92 unsigned int reserved; /* reserved data */ 93 unsigned long size; /* size of raw data (section data) in bytes */ 94 95 unsigned char *raw_data; /* raw section data, only used during output */ 96 } rdf_section_data; 97 98 typedef struct rdf_symrec_data { 99 unsigned int segment; /* assigned RDF "segment" index */ 100 } rdf_symrec_data; 101 102 typedef STAILQ_HEAD(xdf_str_head, xdf_str) xdf_str_head; 103 typedef struct xdf_str { 104 STAILQ_ENTRY(xdf_str) link; 105 /*@owned@*/ char *str; 106 } xdf_str; 107 108 typedef struct yasm_objfmt_rdf { 109 yasm_objfmt_base objfmt; /* base structure */ 110 111 long parse_scnum; /* sect numbering in parser */ 112 113 /*@owned@*/ xdf_str_head module_names; 114 /*@owned@*/ xdf_str_head library_names; 115 } yasm_objfmt_rdf; 116 117 typedef struct rdf_objfmt_output_info { 118 yasm_object *object; 119 yasm_objfmt_rdf *objfmt_rdf; 120 yasm_errwarns *errwarns; 121 /*@dependent@*/ FILE *f; 122 /*@only@*/ unsigned char *buf; 123 yasm_section *sect; 124 /*@dependent@*/ rdf_section_data *rsd; 125 126 unsigned long indx; /* symbol "segment" (extern/common only) */ 127 128 unsigned long bss_size; /* total BSS size */ 129 } rdf_objfmt_output_info; 130 131 static void rdf_section_data_destroy(/*@only@*/ void *d); 132 static void rdf_section_data_print(void *data, FILE *f, int indent_level); 133 134 static const yasm_assoc_data_callback rdf_section_data_cb = { 135 rdf_section_data_destroy, 136 rdf_section_data_print 137 }; 138 139 static void rdf_symrec_data_destroy(/*@only@*/ void *d); 140 static void rdf_symrec_data_print(void *data, FILE *f, int indent_level); 141 142 static const yasm_assoc_data_callback rdf_symrec_data_cb = { 143 rdf_symrec_data_destroy, 144 rdf_symrec_data_print 145 }; 146 147 yasm_objfmt_module yasm_rdf_LTX_objfmt; 148 149 150 static /*@dependent@*/ rdf_symrec_data * 151 rdf_objfmt_sym_set_data(yasm_symrec *sym, unsigned int segment) 152 { 153 rdf_symrec_data *rsymd = yasm_xmalloc(sizeof(rdf_symrec_data)); 154 155 rsymd->segment = segment; 156 157 yasm_symrec_add_data(sym, &rdf_symrec_data_cb, rsymd); 158 return rsymd; 159 } 160 161 static yasm_objfmt * 162 rdf_objfmt_create(yasm_object *object) 163 { 164 yasm_objfmt_rdf *objfmt_rdf = yasm_xmalloc(sizeof(yasm_objfmt_rdf)); 165 166 /* We theoretically support all arches, so don't check. 167 * Really we only support byte-addressable ones. 168 */ 169 170 objfmt_rdf->parse_scnum = 0; /* section numbering starts at 0 */ 171 172 STAILQ_INIT(&objfmt_rdf->module_names); 173 STAILQ_INIT(&objfmt_rdf->library_names); 174 175 objfmt_rdf->objfmt.module = &yasm_rdf_LTX_objfmt; 176 177 return (yasm_objfmt *)objfmt_rdf; 178 } 179 180 static int 181 rdf_objfmt_output_value(yasm_value *value, unsigned char *buf, 182 unsigned int destsize, unsigned long offset, 183 yasm_bytecode *bc, int warn, /*@null@*/ void *d) 184 { 185 /*@null@*/ rdf_objfmt_output_info *info = (rdf_objfmt_output_info *)d; 186 yasm_objfmt_rdf *objfmt_rdf; 187 /*@dependent@*/ /*@null@*/ yasm_intnum *intn; 188 unsigned long intn_minus; 189 unsigned long intn_plus; 190 int retval; 191 unsigned int valsize = value->size; 192 193 assert(info != NULL); 194 objfmt_rdf = info->objfmt_rdf; 195 196 if (value->abs) 197 value->abs = yasm_expr_simplify(value->abs, 1); 198 199 /* Try to output constant and PC-relative section-local first. 200 * Note this does NOT output any value with a SEG, WRT, external, 201 * cross-section, or non-PC-relative reference (those are handled below). 202 */ 203 switch (yasm_value_output_basic(value, buf, destsize, bc, warn, 204 info->object->arch)) { 205 case -1: 206 return 1; 207 case 0: 208 break; 209 default: 210 return 0; 211 } 212 213 if (value->section_rel) { 214 yasm_error_set(YASM_ERROR_TOO_COMPLEX, 215 N_("rdf: relocation too complex")); 216 return 1; 217 } 218 219 if (value->rel && value->wrt) { 220 yasm_error_set(YASM_ERROR_TOO_COMPLEX, 221 N_("rdf: WRT not supported")); 222 return 1; 223 } 224 225 intn_minus = 0; 226 intn_plus = 0; 227 if (value->rel) { 228 rdf_reloc *reloc; 229 /*@null@*/ rdf_symrec_data *rsymd; 230 /*@dependent@*/ yasm_bytecode *precbc; 231 232 reloc = yasm_xmalloc(sizeof(rdf_reloc)); 233 reloc->reloc.addr = yasm_intnum_create_uint(bc->offset + offset); 234 reloc->reloc.sym = value->rel; 235 reloc->size = valsize/8; 236 237 if (value->seg_of) 238 reloc->type = RDF_RELOC_SEG; 239 else if (value->curpos_rel) { 240 reloc->type = RDF_RELOC_REL; 241 /* Adjust to start of section, so subtract out the bytecode 242 * offset. 243 */ 244 intn_minus = bc->offset; 245 } else 246 reloc->type = RDF_RELOC_NORM; 247 248 if (yasm_symrec_get_label(value->rel, &precbc)) { 249 /* local, set the value to be the offset, and the refseg to the 250 * segment number. 251 */ 252 /*@dependent@*/ /*@null@*/ rdf_section_data *csectd; 253 /*@dependent@*/ yasm_section *sect; 254 255 sect = yasm_bc_get_section(precbc); 256 csectd = yasm_section_get_data(sect, &rdf_section_data_cb); 257 if (!csectd) 258 yasm_internal_error(N_("didn't understand section")); 259 reloc->refseg = csectd->scnum; 260 intn_plus = yasm_bc_next_offset(precbc); 261 } else { 262 /* must be common/external */ 263 rsymd = yasm_symrec_get_data(reloc->reloc.sym, 264 &rdf_symrec_data_cb); 265 if (!rsymd) 266 yasm_internal_error( 267 N_("rdf: no symbol data for relocated symbol")); 268 reloc->refseg = rsymd->segment; 269 } 270 271 yasm_section_add_reloc(info->sect, (yasm_reloc *)reloc, yasm_xfree); 272 } 273 274 if (intn_minus > 0) { 275 intn = yasm_intnum_create_uint(intn_minus); 276 yasm_intnum_calc(intn, YASM_EXPR_NEG, NULL); 277 } else 278 intn = yasm_intnum_create_uint(intn_plus); 279 280 if (value->abs) { 281 yasm_intnum *intn2 = yasm_expr_get_intnum(&value->abs, 0); 282 if (!intn2) { 283 yasm_error_set(YASM_ERROR_TOO_COMPLEX, 284 N_("rdf: relocation too complex")); 285 yasm_intnum_destroy(intn); 286 return 1; 287 } 288 yasm_intnum_calc(intn, YASM_EXPR_ADD, intn2); 289 } 290 291 retval = yasm_arch_intnum_tobytes(info->object->arch, intn, buf, destsize, 292 valsize, 0, bc, warn); 293 yasm_intnum_destroy(intn); 294 return retval; 295 } 296 297 static int 298 rdf_objfmt_output_bytecode(yasm_bytecode *bc, /*@null@*/ void *d) 299 { 300 /*@null@*/ rdf_objfmt_output_info *info = (rdf_objfmt_output_info *)d; 301 /*@null@*/ /*@only@*/ unsigned char *bigbuf; 302 unsigned long size = REGULAR_OUTBUF_SIZE; 303 int gap; 304 305 assert(info != NULL); 306 307 bigbuf = yasm_bc_tobytes(bc, info->buf, &size, &gap, info, 308 rdf_objfmt_output_value, NULL); 309 310 /* Don't bother doing anything else if size ended up being 0. */ 311 if (size == 0) { 312 if (bigbuf) 313 yasm_xfree(bigbuf); 314 return 0; 315 } 316 317 /* Warn that gaps are converted to 0 and write out the 0's. */ 318 if (gap) { 319 yasm_warn_set(YASM_WARN_UNINIT_CONTENTS, 320 N_("uninitialized space: zeroing")); 321 /* Write out in chunks */ 322 memset(&info->rsd->raw_data[info->rsd->size], 0, size); 323 } else { 324 /* Output buf (or bigbuf if non-NULL) to file */ 325 memcpy(&info->rsd->raw_data[info->rsd->size], 326 bigbuf ? bigbuf : info->buf, (size_t)size); 327 } 328 329 info->rsd->size += size; 330 331 /* If bigbuf was allocated, free it */ 332 if (bigbuf) 333 yasm_xfree(bigbuf); 334 335 return 0; 336 } 337 338 static int 339 rdf_objfmt_output_section_mem(yasm_section *sect, /*@null@*/ void *d) 340 { 341 /*@null@*/ rdf_objfmt_output_info *info = (rdf_objfmt_output_info *)d; 342 /*@dependent@*/ /*@null@*/ rdf_section_data *rsd; 343 unsigned long size; 344 345 assert(info != NULL); 346 rsd = yasm_section_get_data(sect, &rdf_section_data_cb); 347 assert(rsd != NULL); 348 349 size = yasm_bc_next_offset(yasm_section_bcs_last(sect)); 350 351 if (rsd->type == RDF_SECT_BSS) { 352 /* Don't output BSS sections, but remember length 353 * TODO: Check for non-reserve bytecodes? 354 */ 355 info->bss_size += size; 356 return 0; 357 } 358 359 /* Empty? Go on to next section */ 360 if (size == 0) 361 return 0; 362 363 /* See UGH comment in output() for why we're doing this */ 364 rsd->raw_data = yasm_xmalloc(size); 365 rsd->size = 0; 366 367 info->sect = sect; 368 info->rsd = rsd; 369 yasm_section_bcs_traverse(sect, info->errwarns, info, 370 rdf_objfmt_output_bytecode); 371 372 /* Sanity check final section size */ 373 if (rsd->size != size) 374 yasm_internal_error( 375 N_("rdf: section computed size did not match actual size")); 376 377 return 0; 378 } 379 380 static int 381 rdf_objfmt_output_section_reloc(yasm_section *sect, /*@null@*/ void *d) 382 { 383 /*@null@*/ rdf_objfmt_output_info *info = (rdf_objfmt_output_info *)d; 384 /*@dependent@*/ /*@null@*/ rdf_section_data *rsd; 385 rdf_reloc *reloc; 386 387 assert(info != NULL); 388 rsd = yasm_section_get_data(sect, &rdf_section_data_cb); 389 assert(rsd != NULL); 390 391 if (rsd->type == RDF_SECT_BSS) { 392 /* Don't output BSS sections. */ 393 return 0; 394 } 395 396 /* Empty? Go on to next section */ 397 if (rsd->size == 0) 398 return 0; 399 400 reloc = (rdf_reloc *)yasm_section_relocs_first(sect); 401 while (reloc) { 402 unsigned char *localbuf = info->buf; 403 404 if (reloc->type == RDF_RELOC_SEG) 405 YASM_WRITE_8(localbuf, RDFREC_SEGRELOC); 406 else 407 YASM_WRITE_8(localbuf, RDFREC_RELOC); 408 YASM_WRITE_8(localbuf, 8); /* record length */ 409 /* Section number, +0x40 if relative reloc */ 410 YASM_WRITE_8(localbuf, rsd->scnum + 411 (reloc->type == RDF_RELOC_REL ? 0x40 : 0)); 412 yasm_intnum_get_sized(reloc->reloc.addr, localbuf, 4, 32, 0, 0, 0); 413 localbuf += 4; /* offset of relocation */ 414 YASM_WRITE_8(localbuf, reloc->size); /* size of relocation */ 415 YASM_WRITE_16_L(localbuf, reloc->refseg); /* relocated symbol */ 416 fwrite(info->buf, 10, 1, info->f); 417 418 reloc = (rdf_reloc *)yasm_section_reloc_next((yasm_reloc *)reloc); 419 } 420 421 return 0; 422 } 423 424 static int 425 rdf_objfmt_output_section_file(yasm_section *sect, /*@null@*/ void *d) 426 { 427 /*@null@*/ rdf_objfmt_output_info *info = (rdf_objfmt_output_info *)d; 428 /*@dependent@*/ /*@null@*/ rdf_section_data *rsd; 429 unsigned char *localbuf; 430 431 assert(info != NULL); 432 rsd = yasm_section_get_data(sect, &rdf_section_data_cb); 433 assert(rsd != NULL); 434 435 if (rsd->type == RDF_SECT_BSS) { 436 /* Don't output BSS sections. */ 437 return 0; 438 } 439 440 /* Empty? Go on to next section */ 441 if (rsd->size == 0) 442 return 0; 443 444 /* Section header */ 445 localbuf = info->buf; 446 YASM_WRITE_16_L(localbuf, rsd->type); /* type */ 447 YASM_WRITE_16_L(localbuf, rsd->scnum); /* number */ 448 YASM_WRITE_16_L(localbuf, rsd->reserved); /* reserved */ 449 YASM_WRITE_32_L(localbuf, rsd->size); /* length */ 450 fwrite(info->buf, 10, 1, info->f); 451 452 /* Section data */ 453 fwrite(rsd->raw_data, rsd->size, 1, info->f); 454 455 /* Free section data */ 456 yasm_xfree(rsd->raw_data); 457 rsd->raw_data = NULL; 458 459 return 0; 460 } 461 462 #define FLAG_EXT 0x1000 463 #define FLAG_GLOB 0x2000 464 #define FLAG_SET 0x4000 465 #define FLAG_CLR 0x8000 466 #define FLAG_MASK 0x0fff 467 468 static int 469 rdf_helper_flag(void *obj, yasm_valparam *vp, unsigned long line, void *d, 470 uintptr_t flag) 471 { 472 yasm_symrec *sym = (yasm_symrec *)obj; 473 yasm_sym_vis vis = yasm_symrec_get_visibility(sym); 474 unsigned int *flags = (unsigned int *)d; 475 476 if (((vis & YASM_SYM_GLOBAL) && (flag & FLAG_GLOB)) || 477 ((vis & YASM_SYM_EXTERN) && (flag & FLAG_EXT))) { 478 if (flag & FLAG_SET) 479 *flags |= flag & FLAG_MASK; 480 else if (flag & FLAG_CLR) 481 *flags &= ~(flag & FLAG_MASK); 482 } 483 return 0; 484 } 485 486 static unsigned int 487 rdf_parse_flags(yasm_symrec *sym) 488 { 489 /*@dependent@*/ /*@null@*/ yasm_valparamhead *objext_valparams = 490 yasm_symrec_get_objext_valparams(sym); 491 unsigned int flags = 0; 492 493 static const yasm_dir_help help[] = { 494 { "data", 0, rdf_helper_flag, 0, 495 FLAG_EXT|FLAG_GLOB|FLAG_SET|SYM_DATA }, 496 { "object", 0, rdf_helper_flag, 0, 497 FLAG_EXT|FLAG_GLOB|FLAG_SET|SYM_DATA }, 498 { "proc", 0, rdf_helper_flag, 0, 499 FLAG_EXT|FLAG_GLOB|FLAG_SET|SYM_FUNCTION }, 500 { "function", 0, rdf_helper_flag, 0, 501 FLAG_EXT|FLAG_GLOB|FLAG_SET|SYM_FUNCTION }, 502 { "import", 0, rdf_helper_flag, 0, FLAG_EXT|FLAG_SET|SYM_IMPORT }, 503 { "export", 0, rdf_helper_flag, 0, FLAG_GLOB|FLAG_SET|SYM_GLOBAL }, 504 { "far", 0, rdf_helper_flag, 0, FLAG_EXT|FLAG_SET|SYM_FAR }, 505 { "near", 0, rdf_helper_flag, 0, FLAG_EXT|FLAG_CLR|SYM_FAR } 506 }; 507 508 if (!objext_valparams) 509 return 0; 510 511 yasm_dir_helper(sym, yasm_vps_first(objext_valparams), 0, help, 512 NELEMS(help), &flags, yasm_dir_helper_valparam_warn); 513 514 return flags; 515 } 516 517 static int 518 rdf_objfmt_output_sym(yasm_symrec *sym, /*@null@*/ void *d) 519 { 520 /*@null@*/ rdf_objfmt_output_info *info = (rdf_objfmt_output_info *)d; 521 yasm_sym_vis vis = yasm_symrec_get_visibility(sym); 522 /*@only@*/ char *name; 523 size_t len; 524 unsigned long value = 0; 525 unsigned int scnum = 0; 526 /*@dependent@*/ /*@null@*/ yasm_section *sect; 527 /*@dependent@*/ /*@null@*/ yasm_bytecode *precbc; 528 unsigned char *localbuf; 529 530 assert(info != NULL); 531 532 if (vis == YASM_SYM_LOCAL || vis == YASM_SYM_DLOCAL) 533 return 0; /* skip local syms */ 534 535 /* Look at symrec for value/scnum/etc. */ 536 if (yasm_symrec_get_label(sym, &precbc)) { 537 /*@dependent@*/ /*@null@*/ rdf_section_data *csectd; 538 539 if (precbc) 540 sect = yasm_bc_get_section(precbc); 541 else 542 sect = NULL; 543 if (!sect) 544 return 0; 545 546 /* it's a label: get value and offset. */ 547 csectd = yasm_section_get_data(sect, &rdf_section_data_cb); 548 if (csectd) 549 scnum = csectd->scnum; 550 else 551 yasm_internal_error(N_("didn't understand section")); 552 value = yasm_bc_next_offset(precbc); 553 } else if (yasm_symrec_get_equ(sym)) { 554 yasm_warn_set(YASM_WARN_GENERAL, 555 N_("rdf does not support exporting EQU/absolute values")); 556 yasm_errwarn_propagate(info->errwarns, yasm_symrec_get_decl_line(sym)); 557 return 0; 558 } 559 560 name = yasm_symrec_get_global_name(sym, info->object); 561 len = strlen(name); 562 563 if (len > EXIM_LABEL_MAX-1) { 564 yasm_warn_set(YASM_WARN_GENERAL, 565 N_("label name too long, truncating to %d bytes"), 566 EXIM_LABEL_MAX); 567 len = EXIM_LABEL_MAX-1; 568 } 569 570 localbuf = info->buf; 571 if (vis & YASM_SYM_GLOBAL) { 572 YASM_WRITE_8(localbuf, RDFREC_GLOBAL); 573 YASM_WRITE_8(localbuf, 6+len+1); /* record length */ 574 YASM_WRITE_8(localbuf, rdf_parse_flags(sym)); /* flags */ 575 YASM_WRITE_8(localbuf, scnum); /* segment referred to */ 576 YASM_WRITE_32_L(localbuf, value); /* offset */ 577 } else { 578 /* Save symbol segment in symrec data (for later reloc gen) */ 579 scnum = info->indx++; 580 rdf_objfmt_sym_set_data(sym, scnum); 581 582 if (vis & YASM_SYM_COMMON) { 583 /*@dependent@*/ /*@null@*/ yasm_expr **csize_expr; 584 const yasm_intnum *intn; 585 /*@dependent@*/ /*@null@*/ yasm_valparamhead *objext_valparams = 586 yasm_symrec_get_objext_valparams(sym); 587 unsigned long addralign = 0; 588 589 YASM_WRITE_8(localbuf, RDFREC_COMMON); 590 YASM_WRITE_8(localbuf, 8+len+1); /* record length */ 591 YASM_WRITE_16_L(localbuf, scnum); /* segment allocated */ 592 593 /* size */ 594 csize_expr = yasm_symrec_get_common_size(sym); 595 assert(csize_expr != NULL); 596 intn = yasm_expr_get_intnum(csize_expr, 1); 597 if (!intn) { 598 yasm_error_set(YASM_ERROR_NOT_CONSTANT, 599 N_("COMMON data size not an integer expression")); 600 } else 601 value = yasm_intnum_get_uint(intn); 602 YASM_WRITE_32_L(localbuf, value); 603 604 /* alignment */ 605 if (objext_valparams) { 606 yasm_valparam *vp = yasm_vps_first(objext_valparams); 607 for (; vp; vp = yasm_vps_next(vp)) { 608 if (!vp->val) { 609 /*@only@*/ /*@null@*/ yasm_expr *align_expr; 610 /*@dependent@*/ /*@null@*/ 611 const yasm_intnum *align_intn; 612 613 if (!(align_expr = yasm_vp_expr(vp, 614 info->object->symtab, 615 yasm_symrec_get_decl_line(sym))) || 616 !(align_intn = yasm_expr_get_intnum(&align_expr, 617 0))) { 618 yasm_error_set(YASM_ERROR_VALUE, 619 N_("argument to `%s' is not an integer"), 620 vp->val); 621 if (align_expr) 622 yasm_expr_destroy(align_expr); 623 continue; 624 } 625 addralign = yasm_intnum_get_uint(align_intn); 626 yasm_expr_destroy(align_expr); 627 628 /* Alignments must be a power of two. */ 629 if (!is_exp2(addralign)) { 630 yasm_error_set(YASM_ERROR_VALUE, 631 N_("alignment constraint is not a power of two")); 632 continue; 633 } 634 } else 635 yasm_warn_set(YASM_WARN_GENERAL, 636 N_("Unrecognized qualifier `%s'"), vp->val); 637 } 638 } 639 YASM_WRITE_16_L(localbuf, addralign); 640 } else if (vis & YASM_SYM_EXTERN) { 641 unsigned int flags = rdf_parse_flags(sym); 642 if (flags & SYM_FAR) { 643 YASM_WRITE_8(localbuf, RDFREC_FARIMPORT); 644 flags &= ~SYM_FAR; 645 } else 646 YASM_WRITE_8(localbuf, RDFREC_IMPORT); 647 YASM_WRITE_8(localbuf, 3+len+1); /* record length */ 648 YASM_WRITE_8(localbuf, flags); /* flags */ 649 YASM_WRITE_16_L(localbuf, scnum); /* segment allocated */ 650 } 651 } 652 653 /* Symbol name */ 654 memcpy(localbuf, name, len); 655 localbuf += len; 656 YASM_WRITE_8(localbuf, 0); /* 0-terminated name */ 657 yasm_xfree(name); 658 659 fwrite(info->buf, (unsigned long)(localbuf-info->buf), 1, info->f); 660 661 yasm_errwarn_propagate(info->errwarns, yasm_symrec_get_decl_line(sym)); 662 return 0; 663 } 664 665 static void 666 rdf_objfmt_output(yasm_object *object, FILE *f, int all_syms, 667 yasm_errwarns *errwarns) 668 { 669 yasm_objfmt_rdf *objfmt_rdf = (yasm_objfmt_rdf *)object->objfmt; 670 rdf_objfmt_output_info info; 671 unsigned char *localbuf; 672 long headerlen, filelen; 673 xdf_str *cur; 674 size_t len; 675 676 info.object = object; 677 info.objfmt_rdf = objfmt_rdf; 678 info.errwarns = errwarns; 679 info.f = f; 680 info.buf = yasm_xmalloc(REGULAR_OUTBUF_SIZE); 681 info.bss_size = 0; 682 683 /* Allocate space for file header by seeking forward */ 684 if (fseek(f, (long)strlen(RDF_MAGIC)+8, SEEK_SET) < 0) { 685 yasm__fatal(N_("could not seek on output file")); 686 /*@notreached@*/ 687 return; 688 } 689 690 /* Output custom header records (library and module, etc) */ 691 cur = STAILQ_FIRST(&objfmt_rdf->module_names); 692 while (cur) { 693 len = strlen(cur->str)+1; 694 localbuf = info.buf; 695 YASM_WRITE_8(localbuf, RDFREC_MODNAME); /* record type */ 696 YASM_WRITE_8(localbuf, len); /* record length */ 697 fwrite(info.buf, 2, 1, f); 698 fwrite(cur->str, len, 1, f); 699 cur = STAILQ_NEXT(cur, link); 700 } 701 702 cur = STAILQ_FIRST(&objfmt_rdf->library_names); 703 while (cur) { 704 len = strlen(cur->str)+1; 705 localbuf = info.buf; 706 YASM_WRITE_8(localbuf, RDFREC_DLL); /* record type */ 707 YASM_WRITE_8(localbuf, len); /* record length */ 708 fwrite(info.buf, 2, 1, f); 709 fwrite(cur->str, len, 1, f); 710 cur = STAILQ_NEXT(cur, link); 711 } 712 713 /* Output symbol table */ 714 info.indx = objfmt_rdf->parse_scnum; 715 yasm_symtab_traverse(object->symtab, &info, rdf_objfmt_output_sym); 716 717 /* UGH! Due to the fact the relocs go at the beginning of the file, and 718 * we only know if we have relocs when we output the sections, we have 719 * to output the section data before we have output the relocs. But 720 * we also don't know how much space to preallocate for relocs, so.... 721 * we output into memory buffers first (thus the UGH). 722 * 723 * Stupid object format design, if you ask me (basically all other 724 * object formats put the relocs *after* the section data to avoid this 725 * exact problem). 726 * 727 * We also calculate the total size of all BSS sections here. 728 */ 729 if (yasm_object_sections_traverse(object, &info, 730 rdf_objfmt_output_section_mem)) 731 return; 732 733 /* Output all relocs */ 734 if (yasm_object_sections_traverse(object, &info, 735 rdf_objfmt_output_section_reloc)) 736 return; 737 738 /* Output BSS record */ 739 if (info.bss_size > 0) { 740 localbuf = info.buf; 741 YASM_WRITE_8(localbuf, RDFREC_BSS); /* record type */ 742 YASM_WRITE_8(localbuf, 4); /* record length */ 743 YASM_WRITE_32_L(localbuf, info.bss_size); /* total BSS size */ 744 fwrite(info.buf, 6, 1, f); 745 } 746 747 /* Determine header length */ 748 headerlen = ftell(f); 749 if (headerlen == -1) { 750 yasm__fatal(N_("could not get file position on output file")); 751 /*@notreached@*/ 752 return; 753 } 754 755 /* Section data (to file) */ 756 if (yasm_object_sections_traverse(object, &info, 757 rdf_objfmt_output_section_file)) 758 return; 759 760 /* NULL section to end file */ 761 memset(info.buf, 0, 10); 762 fwrite(info.buf, 10, 1, f); 763 764 /* Determine object length */ 765 filelen = ftell(f); 766 if (filelen == -1) { 767 yasm__fatal(N_("could not get file position on output file")); 768 /*@notreached@*/ 769 return; 770 } 771 772 /* Write file header */ 773 if (fseek(f, 0, SEEK_SET) < 0) { 774 yasm__fatal(N_("could not seek on output file")); 775 /*@notreached@*/ 776 return; 777 } 778 779 fwrite(RDF_MAGIC, strlen(RDF_MAGIC), 1, f); 780 localbuf = info.buf; 781 YASM_WRITE_32_L(localbuf, filelen-10); /* object size */ 782 YASM_WRITE_32_L(localbuf, headerlen-14); /* header size */ 783 fwrite(info.buf, 8, 1, f); 784 785 yasm_xfree(info.buf); 786 } 787 788 static void 789 rdf_objfmt_destroy(yasm_objfmt *objfmt) 790 { 791 yasm_objfmt_rdf *objfmt_rdf = (yasm_objfmt_rdf *)objfmt; 792 xdf_str *cur, *next; 793 794 cur = STAILQ_FIRST(&objfmt_rdf->module_names); 795 while (cur) { 796 next = STAILQ_NEXT(cur, link); 797 yasm_xfree(cur->str); 798 yasm_xfree(cur); 799 cur = next; 800 } 801 802 cur = STAILQ_FIRST(&objfmt_rdf->library_names); 803 while (cur) { 804 next = STAILQ_NEXT(cur, link); 805 yasm_xfree(cur->str); 806 yasm_xfree(cur); 807 cur = next; 808 } 809 810 yasm_xfree(objfmt); 811 } 812 813 static void 814 rdf_objfmt_init_new_section(yasm_section *sect, unsigned long line) 815 { 816 yasm_object *object = yasm_section_get_object(sect); 817 const char *sectname = yasm_section_get_name(sect); 818 yasm_objfmt_rdf *objfmt_rdf = (yasm_objfmt_rdf *)object->objfmt; 819 rdf_section_data *data; 820 yasm_symrec *sym; 821 822 data = yasm_xmalloc(sizeof(rdf_section_data)); 823 data->scnum = objfmt_rdf->parse_scnum++; 824 data->type = 0; 825 data->reserved = 0; 826 data->size = 0; 827 data->raw_data = NULL; 828 yasm_section_add_data(sect, &rdf_section_data_cb, data); 829 830 sym = yasm_symtab_define_label(object->symtab, sectname, 831 yasm_section_bcs_first(sect), 1, line); 832 data->sym = sym; 833 } 834 835 static yasm_section * 836 rdf_objfmt_add_default_section(yasm_object *object) 837 { 838 yasm_section *retval; 839 rdf_section_data *rsd; 840 int isnew; 841 842 retval = yasm_object_get_general(object, ".text", 0, 1, 0, &isnew, 0); 843 if (isnew) { 844 rsd = yasm_section_get_data(retval, &rdf_section_data_cb); 845 rsd->type = RDF_SECT_CODE; 846 rsd->reserved = 0; 847 yasm_section_set_default(retval, 1); 848 } 849 return retval; 850 } 851 852 static int 853 rdf_helper_set_type(void *obj, yasm_valparam *vp, unsigned long line, 854 void *d, uintptr_t newtype) 855 { 856 unsigned int *type = (unsigned int *)d; 857 *type = newtype; 858 return 0; 859 } 860 861 struct rdf_section_switch_data { 862 /*@only@*/ /*@null@*/ yasm_intnum *reserved_intn; 863 unsigned int type; 864 }; 865 866 static int 867 rdf_helper_set_reserved(void *obj, yasm_valparam *vp, unsigned long line, 868 void *d) 869 { 870 struct rdf_section_switch_data *data = (struct rdf_section_switch_data *)d; 871 872 if (!vp->val && vp->type == YASM_PARAM_EXPR) 873 return yasm_dir_helper_intn(obj, vp, line, &data->reserved_intn, 0); 874 else 875 return yasm_dir_helper_valparam_warn(obj, vp, line, d); 876 } 877 878 static /*@observer@*/ /*@null@*/ yasm_section * 879 rdf_objfmt_section_switch(yasm_object *object, yasm_valparamhead *valparams, 880 /*@unused@*/ /*@null@*/ 881 yasm_valparamhead *objext_valparams, 882 unsigned long line) 883 { 884 yasm_valparam *vp = yasm_vps_first(valparams); 885 yasm_section *retval; 886 int isnew; 887 unsigned int reserved = 0; 888 int flags_override = 0; 889 const char *sectname; 890 rdf_section_data *rsd; 891 892 struct rdf_section_switch_data data; 893 894 static const yasm_dir_help help[] = { 895 { "bss", 0, rdf_helper_set_type, 896 offsetof(struct rdf_section_switch_data, type), RDF_SECT_BSS }, 897 { "code", 0, rdf_helper_set_type, 898 offsetof(struct rdf_section_switch_data, type), RDF_SECT_CODE }, 899 { "text", 0, rdf_helper_set_type, 900 offsetof(struct rdf_section_switch_data, type), RDF_SECT_CODE }, 901 { "data", 0, rdf_helper_set_type, 902 offsetof(struct rdf_section_switch_data, type), RDF_SECT_DATA }, 903 { "comment", 0, rdf_helper_set_type, 904 offsetof(struct rdf_section_switch_data, type), RDF_SECT_COMMENT }, 905 { "lcomment", 0, rdf_helper_set_type, 906 offsetof(struct rdf_section_switch_data, type), RDF_SECT_LCOMMENT }, 907 { "pcomment", 0, rdf_helper_set_type, 908 offsetof(struct rdf_section_switch_data, type), RDF_SECT_PCOMMENT }, 909 { "symdebug", 0, rdf_helper_set_type, 910 offsetof(struct rdf_section_switch_data, type), RDF_SECT_SYMDEBUG }, 911 { "linedebug", 0, rdf_helper_set_type, 912 offsetof(struct rdf_section_switch_data, type), RDF_SECT_LINEDEBUG }, 913 { "reserved", 1, yasm_dir_helper_intn, 914 offsetof(struct rdf_section_switch_data, reserved_intn), 0 } 915 }; 916 917 data.reserved_intn = NULL; 918 data.type = 0xffff; 919 920 vp = yasm_vps_first(valparams); 921 sectname = yasm_vp_string(vp); 922 if (!sectname) 923 return NULL; 924 vp = yasm_vps_next(vp); 925 926 if (strcmp(sectname, ".text") == 0) 927 data.type = RDF_SECT_CODE; 928 else if (strcmp(sectname, ".data") == 0) 929 data.type = RDF_SECT_DATA; 930 else if (strcmp(sectname, ".bss") == 0) 931 data.type = RDF_SECT_BSS; 932 933 flags_override = yasm_dir_helper(object, vp, line, help, NELEMS(help), 934 &data, rdf_helper_set_reserved); 935 if (flags_override < 0) 936 return NULL; /* error occurred */ 937 938 if (data.type == 0xffff) { 939 yasm_error_set(YASM_ERROR_VALUE, 940 N_("new segment declared without type code")); 941 data.type = RDF_SECT_DATA; 942 } 943 944 if (data.reserved_intn) { 945 reserved = yasm_intnum_get_uint(data.reserved_intn); 946 yasm_intnum_destroy(data.reserved_intn); 947 } 948 949 retval = yasm_object_get_general(object, sectname, 0, 1, 950 data.type == RDF_SECT_BSS, &isnew, line); 951 952 rsd = yasm_section_get_data(retval, &rdf_section_data_cb); 953 954 if (isnew || yasm_section_is_default(retval)) { 955 yasm_section_set_default(retval, 0); 956 rsd->type = data.type; 957 rsd->reserved = reserved; 958 } else if (flags_override) 959 yasm_warn_set(YASM_WARN_GENERAL, 960 N_("section flags ignored on section redeclaration")); 961 return retval; 962 } 963 964 static /*@observer@*/ /*@null@*/ yasm_symrec * 965 rdf_objfmt_get_special_sym(yasm_object *object, const char *name, 966 const char *parser) 967 { 968 return NULL; 969 } 970 971 static void 972 rdf_section_data_destroy(void *data) 973 { 974 rdf_section_data *rsd = (rdf_section_data *)data; 975 if (rsd->raw_data) 976 yasm_xfree(rsd->raw_data); 977 yasm_xfree(data); 978 } 979 980 static void 981 rdf_section_data_print(void *data, FILE *f, int indent_level) 982 { 983 rdf_section_data *rsd = (rdf_section_data *)data; 984 985 fprintf(f, "%*ssym=\n", indent_level, ""); 986 yasm_symrec_print(rsd->sym, f, indent_level+1); 987 fprintf(f, "%*sscnum=%ld\n", indent_level, "", rsd->scnum); 988 fprintf(f, "%*stype=0x%x\n", indent_level, "", rsd->type); 989 fprintf(f, "%*sreserved=0x%x\n", indent_level, "", rsd->reserved); 990 fprintf(f, "%*ssize=%ld\n", indent_level, "", rsd->size); 991 } 992 993 static void 994 rdf_symrec_data_destroy(void *data) 995 { 996 yasm_xfree(data); 997 } 998 999 static void 1000 rdf_symrec_data_print(void *data, FILE *f, int indent_level) 1001 { 1002 rdf_symrec_data *rsymd = (rdf_symrec_data *)data; 1003 1004 fprintf(f, "%*ssymtab segment=%u\n", indent_level, "", rsymd->segment); 1005 } 1006 1007 static void 1008 rdf_objfmt_add_libmodule(yasm_object *object, char *name, int lib) 1009 { 1010 yasm_objfmt_rdf *objfmt_rdf = (yasm_objfmt_rdf *)object->objfmt; 1011 xdf_str *str; 1012 1013 /* Add to list */ 1014 str = yasm_xmalloc(sizeof(xdf_str)); 1015 str->str = name; 1016 if (lib) 1017 STAILQ_INSERT_TAIL(&objfmt_rdf->library_names, str, link); 1018 else 1019 STAILQ_INSERT_TAIL(&objfmt_rdf->module_names, str, link); 1020 1021 if (strlen(str->str) > MODLIB_NAME_MAX-1) { 1022 yasm_warn_set(YASM_WARN_GENERAL, 1023 N_("name too long, truncating to %d bytes"), 1024 MODLIB_NAME_MAX); 1025 str->str[MODLIB_NAME_MAX-1] = '\0'; 1026 } 1027 } 1028 1029 static void 1030 dir_library(yasm_object *object, yasm_valparamhead *valparams, 1031 yasm_valparamhead *objext_valparams, unsigned long line) 1032 { 1033 yasm_valparam *vp = yasm_vps_first(valparams); 1034 rdf_objfmt_add_libmodule(object, yasm__xstrdup(yasm_vp_string(vp)), 1); 1035 } 1036 1037 static void 1038 dir_module(yasm_object *object, yasm_valparamhead *valparams, 1039 yasm_valparamhead *objext_valparams, unsigned long line) 1040 { 1041 yasm_valparam *vp = yasm_vps_first(valparams); 1042 rdf_objfmt_add_libmodule(object, yasm__xstrdup(yasm_vp_string(vp)), 0); 1043 } 1044 1045 /* Define valid debug formats to use with this object format */ 1046 static const char *rdf_objfmt_dbgfmt_keywords[] = { 1047 "null", 1048 NULL 1049 }; 1050 1051 static const yasm_directive rdf_objfmt_directives[] = { 1052 { "library", "nasm", dir_library, YASM_DIR_ARG_REQUIRED }, 1053 { "module", "nasm", dir_module, YASM_DIR_ARG_REQUIRED }, 1054 { NULL, NULL, NULL, 0 } 1055 }; 1056 1057 static const char *rdf_nasm_stdmac[] = { 1058 "%imacro library 1+.nolist", 1059 "[library %1]", 1060 "%endmacro", 1061 "%imacro module 1+.nolist", 1062 "[module %1]", 1063 "%endmacro", 1064 NULL 1065 }; 1066 1067 static const yasm_stdmac rdf_objfmt_stdmacs[] = { 1068 { "nasm", "nasm", rdf_nasm_stdmac }, 1069 { NULL, NULL, NULL } 1070 }; 1071 1072 /* Define objfmt structure -- see objfmt.h for details */ 1073 yasm_objfmt_module yasm_rdf_LTX_objfmt = { 1074 "Relocatable Dynamic Object File Format (RDOFF) v2.0", 1075 "rdf", 1076 "rdf", 1077 32, 1078 0, 1079 rdf_objfmt_dbgfmt_keywords, 1080 "null", 1081 rdf_objfmt_directives, 1082 rdf_objfmt_stdmacs, 1083 rdf_objfmt_create, 1084 rdf_objfmt_output, 1085 rdf_objfmt_destroy, 1086 rdf_objfmt_add_default_section, 1087 rdf_objfmt_init_new_section, 1088 rdf_objfmt_section_switch, 1089 rdf_objfmt_get_special_sym 1090 }; 1091