1 /* 2 * Flat-format binary 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 29 #ifdef HAVE_UNISTD_H 30 #include <unistd.h> 31 #endif 32 #include <libyasm.h> 33 34 35 #define REGULAR_OUTBUF_SIZE 1024 36 37 typedef struct bin_section_data { 38 int bss; /* aka nobits */ 39 40 /* User-provided alignment */ 41 yasm_intnum *align, *valign; 42 43 /* User-provided starts */ 44 /*@null@*/ /*@owned@*/ yasm_expr *start, *vstart; 45 46 /* User-provided follows */ 47 /*@null@*/ /*@owned@*/ char *follows, *vfollows; 48 49 /* Calculated (final) starts, used only during output() */ 50 /*@null@*/ /*@owned@*/ yasm_intnum *istart, *ivstart; 51 52 /* Calculated (final) length, used only during output() */ 53 /*@null@*/ /*@owned@*/ yasm_intnum *length; 54 } bin_section_data; 55 56 typedef struct yasm_objfmt_bin { 57 yasm_objfmt_base objfmt; /* base structure */ 58 59 enum { 60 NO_MAP = 0, 61 MAP_NONE = 0x01, 62 MAP_BRIEF = 0x02, 63 MAP_SECTIONS = 0x04, 64 MAP_SYMBOLS = 0x08 65 } map_flags; 66 /*@null@*/ /*@only@*/ char *map_filename; 67 68 /*@null@*/ /*@only@*/ yasm_expr *org; 69 } yasm_objfmt_bin; 70 71 /* symrec data is used only for the special symbols section<sectname>.start, 72 * section<sectname>.vstart, and section<sectname>.length 73 */ 74 typedef struct bin_symrec_data { 75 yasm_section *section; /* referenced section */ 76 enum bin_ssym { 77 SSYM_START, 78 SSYM_VSTART, 79 SSYM_LENGTH 80 } which; 81 } bin_symrec_data; 82 83 static void bin_section_data_destroy(/*@only@*/ void *d); 84 static void bin_section_data_print(void *data, FILE *f, int indent_level); 85 86 static const yasm_assoc_data_callback bin_section_data_cb = { 87 bin_section_data_destroy, 88 bin_section_data_print 89 }; 90 91 static void bin_symrec_data_destroy(/*@only@*/ void *d); 92 static void bin_symrec_data_print(void *data, FILE *f, int indent_level); 93 94 static const yasm_assoc_data_callback bin_symrec_data_cb = { 95 bin_symrec_data_destroy, 96 bin_symrec_data_print 97 }; 98 99 yasm_objfmt_module yasm_bin_LTX_objfmt; 100 101 102 static yasm_objfmt * 103 bin_objfmt_create(yasm_object *object) 104 { 105 yasm_objfmt_bin *objfmt_bin = yasm_xmalloc(sizeof(yasm_objfmt_bin)); 106 objfmt_bin->objfmt.module = &yasm_bin_LTX_objfmt; 107 108 objfmt_bin->map_flags = NO_MAP; 109 objfmt_bin->map_filename = NULL; 110 objfmt_bin->org = NULL; 111 112 return (yasm_objfmt *)objfmt_bin; 113 } 114 115 typedef TAILQ_HEAD(bin_group_head, bin_group) bin_groups; 116 117 typedef struct bin_group { 118 TAILQ_ENTRY(bin_group) link; 119 yasm_section *section; 120 bin_section_data *bsd; 121 122 /* Groups that (in parallel) logically come immediately after this 123 * group's section. 124 */ 125 bin_groups follow_groups; 126 } bin_group; 127 128 /* Recursive function to find group containing named section. */ 129 static bin_group * 130 find_group_by_name(bin_groups *groups, const char *name) 131 { 132 bin_group *group, *found; 133 TAILQ_FOREACH(group, groups, link) { 134 if (strcmp(yasm_section_get_name(group->section), name) == 0) 135 return group; 136 /* Recurse to loop through follow groups */ 137 found = find_group_by_name(&group->follow_groups, name); 138 if (found) 139 return found; 140 } 141 return NULL; 142 } 143 144 /* Recursive function to find group. Returns NULL if not found. */ 145 static bin_group * 146 find_group_by_section(bin_groups *groups, yasm_section *section) 147 { 148 bin_group *group, *found; 149 TAILQ_FOREACH(group, groups, link) { 150 if (group->section == section) 151 return group; 152 /* Recurse to loop through follow groups */ 153 found = find_group_by_section(&group->follow_groups, section); 154 if (found) 155 return found; 156 } 157 return NULL; 158 } 159 160 #if 0 161 /* Debugging function */ 162 static void 163 print_groups(const bin_groups *groups, int indent_level) 164 { 165 bin_group *group; 166 TAILQ_FOREACH(group, groups, link) { 167 printf("%*sSection `%s':\n", indent_level, "", 168 yasm_section_get_name(group->section)); 169 bin_section_data_print(group->bsd, stdout, indent_level+1); 170 if (!TAILQ_EMPTY(&group->follow_groups)) { 171 printf("%*sFollowing groups:\n", indent_level, ""); 172 print_groups(&group->follow_groups, indent_level+1); 173 } 174 } 175 } 176 #endif 177 178 static void 179 bin_group_destroy(/*@only@*/ bin_group *group) 180 { 181 bin_group *follow, *group_temp; 182 TAILQ_FOREACH_SAFE(follow, &group->follow_groups, link, group_temp) 183 bin_group_destroy(follow); 184 yasm_xfree(group); 185 } 186 187 typedef struct bin_objfmt_output_info { 188 yasm_object *object; 189 yasm_errwarns *errwarns; 190 /*@dependent@*/ FILE *f; 191 /*@only@*/ unsigned char *buf; 192 /*@observer@*/ const yasm_section *sect; 193 unsigned long start; /* what normal variables go against */ 194 195 yasm_intnum *origin; 196 yasm_intnum *tmp_intn; /* temporary working intnum */ 197 198 bin_groups lma_groups, vma_groups; 199 } bin_objfmt_output_info; 200 201 static int 202 bin_objfmt_check_sym(yasm_symrec *sym, /*@null@*/ void *d) 203 { 204 /*@null@*/ bin_objfmt_output_info *info = (bin_objfmt_output_info *)d; 205 yasm_sym_vis vis = yasm_symrec_get_visibility(sym); 206 assert(info != NULL); 207 208 /* Don't check internally-generated symbols. Only internally generated 209 * symbols have symrec data, so simply check for its presence. 210 */ 211 if (yasm_symrec_get_data(sym, &bin_symrec_data_cb)) 212 return 0; 213 214 if (vis & YASM_SYM_EXTERN) { 215 yasm_warn_set(YASM_WARN_GENERAL, 216 N_("binary object format does not support extern variables")); 217 yasm_errwarn_propagate(info->errwarns, yasm_symrec_get_decl_line(sym)); 218 } else if (vis & YASM_SYM_GLOBAL) { 219 yasm_warn_set(YASM_WARN_GENERAL, 220 N_("binary object format does not support global variables")); 221 yasm_errwarn_propagate(info->errwarns, yasm_symrec_get_decl_line(sym)); 222 } else if (vis & YASM_SYM_COMMON) { 223 yasm_error_set(YASM_ERROR_TYPE, 224 N_("binary object format does not support common variables")); 225 yasm_errwarn_propagate(info->errwarns, yasm_symrec_get_decl_line(sym)); 226 } 227 return 0; 228 } 229 230 static int 231 bin_lma_create_group(yasm_section *sect, /*@null@*/ void *d) 232 { 233 bin_objfmt_output_info *info = (bin_objfmt_output_info *)d; 234 bin_section_data *bsd = yasm_section_get_data(sect, &bin_section_data_cb); 235 unsigned long align = yasm_section_get_align(sect); 236 bin_group *group; 237 238 assert(info != NULL); 239 assert(bsd != NULL); 240 241 group = yasm_xmalloc(sizeof(bin_group)); 242 group->section = sect; 243 group->bsd = bsd; 244 TAILQ_INIT(&group->follow_groups); 245 246 /* Determine section alignment as necessary. */ 247 if (!bsd->align) 248 bsd->align = yasm_intnum_create_uint(align > 4 ? align : 4); 249 else { 250 yasm_intnum *align_intn = yasm_intnum_create_uint(align); 251 if (yasm_intnum_compare(align_intn, bsd->align) > 0) { 252 yasm_warn_set(YASM_WARN_GENERAL, 253 N_("section `%s' internal align of %lu is greater than `%s' of %lu; using `%s'"), 254 yasm_section_get_name(sect), 255 yasm_intnum_get_uint(align_intn), 256 N_("align"), 257 yasm_intnum_get_uint(bsd->align), 258 N_("align")); 259 yasm_errwarn_propagate(info->errwarns, 0); 260 } 261 yasm_intnum_destroy(align_intn); 262 } 263 264 /* Calculate section integer start. */ 265 if (bsd->start) { 266 bsd->istart = yasm_expr_get_intnum(&bsd->start, 0); 267 if (!bsd->istart) { 268 yasm_error_set(YASM_ERROR_TOO_COMPLEX, 269 N_("start expression is too complex")); 270 yasm_errwarn_propagate(info->errwarns, bsd->start->line); 271 return 1; 272 } else 273 bsd->istart = yasm_intnum_copy(bsd->istart); 274 } else 275 bsd->istart = NULL; 276 277 /* Calculate section integer vstart. */ 278 if (bsd->vstart) { 279 bsd->ivstart = yasm_expr_get_intnum(&bsd->vstart, 0); 280 if (!bsd->ivstart) { 281 yasm_error_set(YASM_ERROR_TOO_COMPLEX, 282 N_("vstart expression is too complex")); 283 yasm_errwarn_propagate(info->errwarns, bsd->vstart->line); 284 return 1; 285 } else 286 bsd->ivstart = yasm_intnum_copy(bsd->ivstart); 287 } else 288 bsd->ivstart = NULL; 289 290 /* Calculate section integer length. */ 291 bsd->length = yasm_calc_bc_dist(yasm_section_bcs_first(sect), 292 yasm_section_bcs_last(sect)); 293 294 TAILQ_INSERT_TAIL(&info->lma_groups, group, link); 295 return 0; 296 } 297 298 static int 299 bin_vma_create_group(yasm_section *sect, /*@null@*/ void *d) 300 { 301 bin_objfmt_output_info *info = (bin_objfmt_output_info *)d; 302 bin_section_data *bsd = yasm_section_get_data(sect, &bin_section_data_cb); 303 bin_group *group; 304 305 assert(info != NULL); 306 assert(bsd != NULL); 307 308 group = yasm_xmalloc(sizeof(bin_group)); 309 group->section = sect; 310 group->bsd = bsd; 311 TAILQ_INIT(&group->follow_groups); 312 313 TAILQ_INSERT_TAIL(&info->vma_groups, group, link); 314 return 0; 315 } 316 317 /* Calculates new start address based on alignment constraint. 318 * Start is modified (rounded up) to the closest aligned value greater than 319 * what was passed in. 320 * Align must be a power of 2. 321 */ 322 static void 323 bin_objfmt_align(yasm_intnum *start, const yasm_intnum *align) 324 { 325 /* Because alignment is always a power of two, we can use some bit 326 * trickery to do this easily. 327 */ 328 yasm_intnum *align_intn = 329 yasm_intnum_create_uint(yasm_intnum_get_uint(align)-1); 330 yasm_intnum_calc(align_intn, YASM_EXPR_AND, start); 331 if (!yasm_intnum_is_zero(align_intn)) { 332 /* start = (start & ~(align-1)) + align; */ 333 yasm_intnum_set_uint(align_intn, yasm_intnum_get_uint(align)-1); 334 yasm_intnum_calc(align_intn, YASM_EXPR_NOT, NULL); 335 yasm_intnum_calc(align_intn, YASM_EXPR_AND, start); 336 yasm_intnum_set(start, align); 337 yasm_intnum_calc(start, YASM_EXPR_ADD, align_intn); 338 } 339 yasm_intnum_destroy(align_intn); 340 } 341 342 /* Recursive function to assign start addresses. 343 * Updates start, last, and vdelta parameters as it goes along. 344 * The tmp parameter is just a working intnum so one doesn't have to be 345 * locally allocated for this purpose. 346 */ 347 static void 348 group_assign_start_recurse(bin_group *group, yasm_intnum *start, 349 yasm_intnum *last, yasm_intnum *vdelta, 350 yasm_intnum *tmp, yasm_errwarns *errwarns) 351 { 352 bin_group *follow_group; 353 354 /* Determine LMA */ 355 if (group->bsd->istart) { 356 yasm_intnum_set(group->bsd->istart, start); 357 if (group->bsd->align) { 358 bin_objfmt_align(group->bsd->istart, group->bsd->align); 359 if (yasm_intnum_compare(start, group->bsd->istart) != 0) { 360 yasm_warn_set(YASM_WARN_GENERAL, 361 N_("start inconsistent with align; using aligned value")); 362 yasm_errwarn_propagate(errwarns, group->bsd->start->line); 363 } 364 } 365 } else { 366 group->bsd->istart = yasm_intnum_copy(start); 367 if (group->bsd->align != 0) 368 bin_objfmt_align(group->bsd->istart, group->bsd->align); 369 } 370 371 /* Determine VMA if either just valign specified or if no v* specified */ 372 if (!group->bsd->vstart) { 373 if (!group->bsd->vfollows && !group->bsd->valign) { 374 /* No v* specified, set VMA=LMA+vdelta. */ 375 group->bsd->ivstart = yasm_intnum_copy(group->bsd->istart); 376 yasm_intnum_calc(group->bsd->ivstart, YASM_EXPR_ADD, vdelta); 377 } else if (!group->bsd->vfollows) { 378 /* Just valign specified: set VMA=LMA+vdelta, align VMA, then add 379 * delta between unaligned and aligned to vdelta parameter. 380 */ 381 group->bsd->ivstart = yasm_intnum_copy(group->bsd->istart); 382 yasm_intnum_calc(group->bsd->ivstart, YASM_EXPR_ADD, vdelta); 383 yasm_intnum_set(tmp, group->bsd->ivstart); 384 bin_objfmt_align(group->bsd->ivstart, group->bsd->valign); 385 yasm_intnum_calc(vdelta, YASM_EXPR_ADD, group->bsd->ivstart); 386 yasm_intnum_calc(vdelta, YASM_EXPR_SUB, tmp); 387 } 388 } 389 390 /* Find the maximum end value */ 391 yasm_intnum_set(tmp, group->bsd->istart); 392 yasm_intnum_calc(tmp, YASM_EXPR_ADD, group->bsd->length); 393 if (yasm_intnum_compare(tmp, last) > 0) /* tmp > last */ 394 yasm_intnum_set(last, tmp); 395 396 /* Recurse for each following group. */ 397 TAILQ_FOREACH(follow_group, &group->follow_groups, link) { 398 /* Following sections have to follow this one, 399 * so add length to start. 400 */ 401 yasm_intnum_set(start, group->bsd->istart); 402 yasm_intnum_calc(start, YASM_EXPR_ADD, group->bsd->length); 403 404 group_assign_start_recurse(follow_group, start, last, vdelta, tmp, 405 errwarns); 406 } 407 } 408 409 /* Recursive function to assign start addresses. 410 * Updates start parameter as it goes along. 411 * The tmp parameter is just a working intnum so one doesn't have to be 412 * locally allocated for this purpose. 413 */ 414 static void 415 group_assign_vstart_recurse(bin_group *group, yasm_intnum *start, 416 yasm_errwarns *errwarns) 417 { 418 bin_group *follow_group; 419 420 /* Determine VMA section alignment as necessary. 421 * Default to LMA alignment if not specified. 422 */ 423 if (!group->bsd->valign) 424 group->bsd->valign = yasm_intnum_copy(group->bsd->align); 425 else { 426 unsigned long align = yasm_section_get_align(group->section); 427 yasm_intnum *align_intn = yasm_intnum_create_uint(align); 428 if (yasm_intnum_compare(align_intn, group->bsd->valign) > 0) { 429 yasm_warn_set(YASM_WARN_GENERAL, 430 N_("section `%s' internal align of %lu is greater than `%s' of %lu; using `%s'"), 431 yasm_section_get_name(group->section), 432 yasm_intnum_get_uint(align_intn), 433 N_("valign"), 434 yasm_intnum_get_uint(group->bsd->valign), 435 N_("valign")); 436 yasm_errwarn_propagate(errwarns, 0); 437 } 438 yasm_intnum_destroy(align_intn); 439 } 440 441 /* Determine VMA */ 442 if (group->bsd->ivstart) { 443 yasm_intnum_set(group->bsd->ivstart, start); 444 if (group->bsd->valign) { 445 bin_objfmt_align(group->bsd->ivstart, group->bsd->valign); 446 if (yasm_intnum_compare(start, group->bsd->ivstart) != 0) { 447 yasm_error_set(YASM_ERROR_VALUE, 448 N_("vstart inconsistent with valign")); 449 yasm_errwarn_propagate(errwarns, group->bsd->vstart->line); 450 } 451 } 452 } else { 453 group->bsd->ivstart = yasm_intnum_copy(start); 454 if (group->bsd->valign) 455 bin_objfmt_align(group->bsd->ivstart, group->bsd->valign); 456 } 457 458 /* Recurse for each following group. */ 459 TAILQ_FOREACH(follow_group, &group->follow_groups, link) { 460 /* Following sections have to follow this one, 461 * so add length to start. 462 */ 463 yasm_intnum_set(start, group->bsd->ivstart); 464 yasm_intnum_calc(start, YASM_EXPR_ADD, group->bsd->length); 465 466 group_assign_vstart_recurse(follow_group, start, errwarns); 467 } 468 } 469 470 static /*@null@*/ const yasm_intnum * 471 get_ssym_value(yasm_symrec *sym) 472 { 473 bin_symrec_data *bsymd = yasm_symrec_get_data(sym, &bin_symrec_data_cb); 474 bin_section_data *bsd; 475 476 if (!bsymd) 477 return NULL; 478 479 bsd = yasm_section_get_data(bsymd->section, &bin_section_data_cb); 480 assert(bsd != NULL); 481 482 switch (bsymd->which) { 483 case SSYM_START: return bsd->istart; 484 case SSYM_VSTART: return bsd->ivstart; 485 case SSYM_LENGTH: return bsd->length; 486 } 487 return NULL; 488 } 489 490 static /*@only@*/ yasm_expr * 491 bin_objfmt_expr_xform(/*@returned@*/ /*@only@*/ yasm_expr *e, 492 /*@unused@*/ /*@null@*/ void *d) 493 { 494 int i; 495 for (i=0; i<e->numterms; i++) { 496 /*@dependent@*/ yasm_section *sect; 497 /*@dependent@*/ /*@null@*/ yasm_bytecode *precbc; 498 /*@null@*/ yasm_intnum *dist; 499 /*@null@*/ const yasm_intnum *ssymval; 500 501 /* Transform symrecs or precbcs that reference sections into 502 * vstart + intnum(dist). 503 */ 504 if (((e->terms[i].type == YASM_EXPR_SYM && 505 yasm_symrec_get_label(e->terms[i].data.sym, &precbc)) || 506 (e->terms[i].type == YASM_EXPR_PRECBC && 507 (precbc = e->terms[i].data.precbc))) && 508 (sect = yasm_bc_get_section(precbc)) && 509 (dist = yasm_calc_bc_dist(yasm_section_bcs_first(sect), precbc))) { 510 bin_section_data *bsd; 511 bsd = yasm_section_get_data(sect, &bin_section_data_cb); 512 assert(bsd != NULL); 513 yasm_intnum_calc(dist, YASM_EXPR_ADD, bsd->ivstart); 514 e->terms[i].type = YASM_EXPR_INT; 515 e->terms[i].data.intn = dist; 516 } 517 518 /* Transform our special symrecs into the appropriate value */ 519 if (e->terms[i].type == YASM_EXPR_SYM && 520 (ssymval = get_ssym_value(e->terms[i].data.sym))) { 521 e->terms[i].type = YASM_EXPR_INT; 522 e->terms[i].data.intn = yasm_intnum_copy(ssymval); 523 } 524 } 525 526 return e; 527 } 528 529 typedef struct map_output_info { 530 /* address width */ 531 int bytes; 532 533 /* intnum output static data areas */ 534 unsigned char *buf; 535 yasm_intnum *intn; 536 537 /* symrec output information */ 538 unsigned long count; 539 yasm_section *section; /* NULL for EQUs */ 540 541 yasm_object *object; /* object */ 542 FILE *f; /* map output file */ 543 } map_output_info; 544 545 static int 546 map_prescan_bytes(yasm_section *sect, void *d) 547 { 548 bin_section_data *bsd = yasm_section_get_data(sect, &bin_section_data_cb); 549 map_output_info *info = (map_output_info *)d; 550 551 assert(bsd != NULL); 552 assert(info != NULL); 553 554 while (!yasm_intnum_check_size(bsd->length, info->bytes * 8, 0, 0)) 555 info->bytes *= 2; 556 while (!yasm_intnum_check_size(bsd->istart, info->bytes * 8, 0, 0)) 557 info->bytes *= 2; 558 while (!yasm_intnum_check_size(bsd->ivstart, info->bytes * 8, 0, 0)) 559 info->bytes *= 2; 560 561 return 0; 562 } 563 564 static void 565 map_print_intnum(const yasm_intnum *intn, map_output_info *info) 566 { 567 size_t i; 568 yasm_intnum_get_sized(intn, info->buf, info->bytes, info->bytes*8, 0, 0, 569 0); 570 for (i=info->bytes; i != 0; i--) 571 fprintf(info->f, "%02X", info->buf[i-1]); 572 } 573 574 static void 575 map_sections_summary(bin_groups *groups, map_output_info *info) 576 { 577 bin_group *group; 578 TAILQ_FOREACH(group, groups, link) { 579 bin_section_data *bsd = group->bsd; 580 581 assert(bsd != NULL); 582 assert(info != NULL); 583 584 map_print_intnum(bsd->ivstart, info); 585 fprintf(info->f, " "); 586 587 yasm_intnum_set(info->intn, bsd->ivstart); 588 yasm_intnum_calc(info->intn, YASM_EXPR_ADD, bsd->length); 589 map_print_intnum(info->intn, info); 590 fprintf(info->f, " "); 591 592 map_print_intnum(bsd->istart, info); 593 fprintf(info->f, " "); 594 595 yasm_intnum_set(info->intn, bsd->istart); 596 yasm_intnum_calc(info->intn, YASM_EXPR_ADD, bsd->length); 597 map_print_intnum(info->intn, info); 598 fprintf(info->f, " "); 599 600 map_print_intnum(bsd->length, info); 601 fprintf(info->f, " "); 602 603 fprintf(info->f, "%-*s", 10, bsd->bss ? "nobits" : "progbits"); 604 fprintf(info->f, "%s\n", yasm_section_get_name(group->section)); 605 606 /* Recurse to loop through follow groups */ 607 map_sections_summary(&group->follow_groups, info); 608 } 609 } 610 611 static void 612 map_sections_detail(bin_groups *groups, map_output_info *info) 613 { 614 bin_group *group; 615 TAILQ_FOREACH(group, groups, link) { 616 bin_section_data *bsd = group->bsd; 617 size_t i; 618 const char *s; 619 620 s = yasm_section_get_name(group->section); 621 fprintf(info->f, "---- Section %s ", s); 622 for (i=0; i<(65-strlen(s)); i++) 623 fputc('-', info->f); 624 625 fprintf(info->f, "\n\nclass: %s", 626 bsd->bss ? "nobits" : "progbits"); 627 fprintf(info->f, "\nlength: "); 628 map_print_intnum(bsd->length, info); 629 fprintf(info->f, "\nstart: "); 630 map_print_intnum(bsd->istart, info); 631 fprintf(info->f, "\nalign: "); 632 map_print_intnum(bsd->align, info); 633 fprintf(info->f, "\nfollows: %s", 634 bsd->follows ? bsd->follows : "not defined"); 635 fprintf(info->f, "\nvstart: "); 636 map_print_intnum(bsd->ivstart, info); 637 fprintf(info->f, "\nvalign: "); 638 map_print_intnum(bsd->valign, info); 639 fprintf(info->f, "\nvfollows: %s\n\n", 640 bsd->vfollows ? bsd->vfollows : "not defined"); 641 642 /* Recurse to loop through follow groups */ 643 map_sections_detail(&group->follow_groups, info); 644 } 645 } 646 647 static int 648 map_symrec_count(yasm_symrec *sym, void *d) 649 { 650 map_output_info *info = (map_output_info *)d; 651 /*@dependent@*/ yasm_bytecode *precbc; 652 653 assert(info != NULL); 654 655 /* TODO: autodetect wider size */ 656 if (!info->section && yasm_symrec_get_equ(sym)) { 657 info->count++; 658 } else if (yasm_symrec_get_label(sym, &precbc) && 659 yasm_bc_get_section(precbc) == info->section) { 660 info->count++; 661 } 662 return 0; 663 } 664 665 static int 666 map_symrec_output(yasm_symrec *sym, void *d) 667 { 668 map_output_info *info = (map_output_info *)d; 669 const yasm_expr *equ; 670 /*@dependent@*/ yasm_bytecode *precbc; 671 /*@only@*/ char *name = yasm_symrec_get_global_name(sym, info->object); 672 673 assert(info != NULL); 674 675 if (!info->section && (equ = yasm_symrec_get_equ(sym))) { 676 yasm_expr *realequ = yasm_expr_copy(equ); 677 realequ = yasm_expr__level_tree 678 (realequ, 1, 1, 1, 0, bin_objfmt_expr_xform, NULL); 679 yasm_intnum_set(info->intn, yasm_expr_get_intnum(&realequ, 0)); 680 yasm_expr_destroy(realequ); 681 map_print_intnum(info->intn, info); 682 fprintf(info->f, " %s\n", name); 683 } else if (yasm_symrec_get_label(sym, &precbc) && 684 yasm_bc_get_section(precbc) == info->section) { 685 bin_section_data *bsd = 686 yasm_section_get_data(info->section, &bin_section_data_cb); 687 688 /* Real address */ 689 yasm_intnum_set_uint(info->intn, yasm_bc_next_offset(precbc)); 690 yasm_intnum_calc(info->intn, YASM_EXPR_ADD, bsd->istart); 691 map_print_intnum(info->intn, info); 692 fprintf(info->f, " "); 693 694 /* Virtual address */ 695 yasm_intnum_set_uint(info->intn, yasm_bc_next_offset(precbc)); 696 yasm_intnum_calc(info->intn, YASM_EXPR_ADD, bsd->ivstart); 697 map_print_intnum(info->intn, info); 698 699 /* Name */ 700 fprintf(info->f, " %s\n", name); 701 } 702 yasm_xfree(name); 703 return 0; 704 } 705 706 static void 707 map_sections_symbols(bin_groups *groups, map_output_info *info) 708 { 709 bin_group *group; 710 TAILQ_FOREACH(group, groups, link) { 711 info->count = 0; 712 info->section = group->section; 713 yasm_symtab_traverse(info->object->symtab, info, map_symrec_count); 714 715 if (info->count > 0) { 716 const char *s = yasm_section_get_name(group->section); 717 size_t i; 718 fprintf(info->f, "---- Section %s ", s); 719 for (i=0; i<(65-strlen(s)); i++) 720 fputc('-', info->f); 721 fprintf(info->f, "\n\n%-*s%-*s%s\n", 722 info->bytes*2+2, "Real", 723 info->bytes*2+2, "Virtual", 724 "Name"); 725 yasm_symtab_traverse(info->object->symtab, info, 726 map_symrec_output); 727 fprintf(info->f, "\n\n"); 728 } 729 730 /* Recurse to loop through follow groups */ 731 map_sections_symbols(&group->follow_groups, info); 732 } 733 } 734 735 static void 736 output_map(bin_objfmt_output_info *info) 737 { 738 yasm_objfmt_bin *objfmt_bin = (yasm_objfmt_bin *)info->object->objfmt; 739 FILE *f; 740 int i; 741 map_output_info mapinfo; 742 743 if (objfmt_bin->map_flags == NO_MAP) 744 return; 745 746 if (objfmt_bin->map_flags == MAP_NONE) 747 objfmt_bin->map_flags = MAP_BRIEF; /* default to brief */ 748 749 if (!objfmt_bin->map_filename) 750 f = stdout; /* default to stdout */ 751 else { 752 f = fopen(objfmt_bin->map_filename, "wt"); 753 if (!f) { 754 yasm_warn_set(YASM_WARN_GENERAL, 755 N_("unable to open map file `%s'"), 756 objfmt_bin->map_filename); 757 yasm_errwarn_propagate(info->errwarns, 0); 758 return; 759 } 760 } 761 762 mapinfo.object = info->object; 763 mapinfo.f = f; 764 765 /* Temporary intnum */ 766 mapinfo.intn = info->tmp_intn; 767 768 /* Prescan all values to figure out what width we should make the output 769 * fields. Start with a minimum of 4. 770 */ 771 mapinfo.bytes = 4; 772 while (!yasm_intnum_check_size(info->origin, mapinfo.bytes * 8, 0, 0)) 773 mapinfo.bytes *= 2; 774 yasm_object_sections_traverse(info->object, &mapinfo, map_prescan_bytes); 775 mapinfo.buf = yasm_xmalloc(mapinfo.bytes); 776 777 fprintf(f, "\n- YASM Map file "); 778 for (i=0; i<63; i++) 779 fputc('-', f); 780 fprintf(f, "\n\nSource file: %s\n", info->object->src_filename); 781 fprintf(f, "Output file: %s\n\n", info->object->obj_filename); 782 783 fprintf(f, "-- Program origin "); 784 for (i=0; i<61; i++) 785 fputc('-', f); 786 fprintf(f, "\n\n"); 787 map_print_intnum(info->origin, &mapinfo); 788 fprintf(f, "\n\n"); 789 790 if (objfmt_bin->map_flags & MAP_BRIEF) { 791 fprintf(f, "-- Sections (summary) "); 792 for (i=0; i<57; i++) 793 fputc('-', f); 794 fprintf(f, "\n\n%-*s%-*s%-*s%-*s%-*s%-*s%s\n", 795 mapinfo.bytes*2+2, "Vstart", 796 mapinfo.bytes*2+2, "Vstop", 797 mapinfo.bytes*2+2, "Start", 798 mapinfo.bytes*2+2, "Stop", 799 mapinfo.bytes*2+2, "Length", 800 10, "Class", "Name"); 801 802 map_sections_summary(&info->lma_groups, &mapinfo); 803 fprintf(f, "\n"); 804 } 805 806 if (objfmt_bin->map_flags & MAP_SECTIONS) { 807 fprintf(f, "-- Sections (detailed) "); 808 for (i=0; i<56; i++) 809 fputc('-', f); 810 fprintf(f, "\n\n"); 811 map_sections_detail(&info->lma_groups, &mapinfo); 812 } 813 814 if (objfmt_bin->map_flags & MAP_SYMBOLS) { 815 fprintf(f, "-- Symbols "); 816 for (i=0; i<68; i++) 817 fputc('-', f); 818 fprintf(f, "\n\n"); 819 820 /* We do two passes for EQU and each section; the first pass 821 * determines the byte width to use for the value and whether any 822 * symbols are present, the second pass actually outputs the text. 823 */ 824 825 /* EQUs */ 826 mapinfo.count = 0; 827 mapinfo.section = NULL; 828 yasm_symtab_traverse(info->object->symtab, &mapinfo, map_symrec_count); 829 830 if (mapinfo.count > 0) { 831 fprintf(f, "---- No Section "); 832 for (i=0; i<63; i++) 833 fputc('-', f); 834 fprintf(f, "\n\n%-*s%s\n", mapinfo.bytes*2+2, "Value", "Name"); 835 yasm_symtab_traverse(info->object->symtab, &mapinfo, 836 map_symrec_output); 837 fprintf(f, "\n\n"); 838 } 839 840 /* Other sections */ 841 map_sections_symbols(&info->lma_groups, &mapinfo); 842 } 843 844 if (f != stdout) 845 fclose(f); 846 847 yasm_xfree(mapinfo.buf); 848 } 849 850 /* Check for LMA overlap using a simple N^2 algorithm. */ 851 static int 852 check_lma_overlap(yasm_section *sect, /*@null@*/ void *d) 853 { 854 bin_section_data *bsd, *bsd2; 855 yasm_section *other = (yasm_section *)d; 856 yasm_intnum *overlap; 857 858 if (!d) 859 return yasm_object_sections_traverse(yasm_section_get_object(sect), 860 sect, check_lma_overlap); 861 if (sect == other) 862 return 0; 863 864 bsd = yasm_section_get_data(sect, &bin_section_data_cb); 865 bsd2 = yasm_section_get_data(other, &bin_section_data_cb); 866 867 if (yasm_intnum_is_zero(bsd->length) || 868 yasm_intnum_is_zero(bsd2->length)) 869 return 0; 870 871 if (yasm_intnum_compare(bsd->istart, bsd2->istart) <= 0) { 872 overlap = yasm_intnum_copy(bsd->istart); 873 yasm_intnum_calc(overlap, YASM_EXPR_ADD, bsd->length); 874 yasm_intnum_calc(overlap, YASM_EXPR_SUB, bsd2->istart); 875 } else { 876 overlap = yasm_intnum_copy(bsd2->istart); 877 yasm_intnum_calc(overlap, YASM_EXPR_ADD, bsd2->length); 878 yasm_intnum_calc(overlap, YASM_EXPR_SUB, bsd->istart); 879 } 880 881 if (yasm_intnum_sign(overlap) > 0) { 882 yasm_error_set(YASM_ERROR_GENERAL, 883 N_("sections `%s' and `%s' overlap by %lu bytes"), 884 yasm_section_get_name(sect), 885 yasm_section_get_name(other), 886 yasm_intnum_get_uint(overlap)); 887 yasm_intnum_destroy(overlap); 888 return -1; 889 } 890 891 yasm_intnum_destroy(overlap); 892 return 0; 893 } 894 895 static int 896 bin_objfmt_output_value(yasm_value *value, unsigned char *buf, 897 unsigned int destsize, 898 /*@unused@*/ unsigned long offset, yasm_bytecode *bc, 899 int warn, /*@null@*/ void *d) 900 { 901 /*@null@*/ bin_objfmt_output_info *info = (bin_objfmt_output_info *)d; 902 /*@dependent@*/ /*@null@*/ yasm_bytecode *precbc; 903 /*@dependent@*/ yasm_section *sect; 904 905 assert(info != NULL); 906 907 /* Binary objects we need to resolve against object, not against section. */ 908 if (value->rel) { 909 unsigned int rshift = (unsigned int)value->rshift; 910 yasm_expr *syme; 911 /*@null@*/ const yasm_intnum *ssymval; 912 913 if (yasm_symrec_is_abs(value->rel)) { 914 syme = yasm_expr_create_ident(yasm_expr_int( 915 yasm_intnum_create_uint(0)), bc->line); 916 } else if (yasm_symrec_get_label(value->rel, &precbc) 917 && (sect = yasm_bc_get_section(precbc))) { 918 syme = yasm_expr_create_ident(yasm_expr_sym(value->rel), bc->line); 919 } else if ((ssymval = get_ssym_value(value->rel))) { 920 syme = yasm_expr_create_ident(yasm_expr_int( 921 yasm_intnum_copy(ssymval)), bc->line); 922 } else 923 goto done; 924 925 /* Handle PC-relative */ 926 if (value->curpos_rel) { 927 yasm_expr *sube; 928 sube = yasm_expr_create(YASM_EXPR_SUB, yasm_expr_precbc(bc), 929 yasm_expr_int(yasm_intnum_create_uint(bc->len*bc->mult_int)), 930 bc->line); 931 syme = yasm_expr_create(YASM_EXPR_SUB, yasm_expr_expr(syme), 932 yasm_expr_expr(sube), bc->line); 933 value->curpos_rel = 0; 934 value->ip_rel = 0; 935 } 936 937 if (value->rshift > 0) 938 syme = yasm_expr_create(YASM_EXPR_SHR, yasm_expr_expr(syme), 939 yasm_expr_int(yasm_intnum_create_uint(rshift)), bc->line); 940 941 /* Add into absolute portion */ 942 if (!value->abs) 943 value->abs = syme; 944 else 945 value->abs = 946 yasm_expr_create(YASM_EXPR_ADD, yasm_expr_expr(value->abs), 947 yasm_expr_expr(syme), bc->line); 948 value->rel = NULL; 949 value->rshift = 0; 950 } 951 done: 952 /* Simplify absolute portion of value, transforming symrecs */ 953 if (value->abs) 954 value->abs = yasm_expr__level_tree 955 (value->abs, 1, 1, 1, 0, bin_objfmt_expr_xform, NULL); 956 957 /* Output */ 958 switch (yasm_value_output_basic(value, buf, destsize, bc, warn, 959 info->object->arch)) { 960 case -1: 961 return 1; 962 case 0: 963 break; 964 default: 965 return 0; 966 } 967 968 /* Couldn't output, assume it contains an external reference. */ 969 yasm_error_set(YASM_ERROR_GENERAL, 970 N_("binary object format does not support external references")); 971 return 1; 972 } 973 974 static int 975 bin_objfmt_output_bytecode(yasm_bytecode *bc, /*@null@*/ void *d) 976 { 977 /*@null@*/ bin_objfmt_output_info *info = (bin_objfmt_output_info *)d; 978 /*@null@*/ /*@only@*/ unsigned char *bigbuf; 979 unsigned long size = REGULAR_OUTBUF_SIZE; 980 int gap; 981 982 assert(info != NULL); 983 984 bigbuf = yasm_bc_tobytes(bc, info->buf, &size, &gap, info, 985 bin_objfmt_output_value, NULL); 986 987 /* Don't bother doing anything else if size ended up being 0. */ 988 if (size == 0) { 989 if (bigbuf) 990 yasm_xfree(bigbuf); 991 return 0; 992 } 993 994 /* Warn that gaps are converted to 0 and write out the 0's. */ 995 if (gap) { 996 unsigned long left; 997 yasm_warn_set(YASM_WARN_UNINIT_CONTENTS, 998 N_("uninitialized space declared in code/data section: zeroing")); 999 /* Write out in chunks */ 1000 memset(info->buf, 0, REGULAR_OUTBUF_SIZE); 1001 left = size; 1002 while (left > REGULAR_OUTBUF_SIZE) { 1003 fwrite(info->buf, REGULAR_OUTBUF_SIZE, 1, info->f); 1004 left -= REGULAR_OUTBUF_SIZE; 1005 } 1006 fwrite(info->buf, left, 1, info->f); 1007 } else { 1008 /* Output buf (or bigbuf if non-NULL) to file */ 1009 fwrite(bigbuf ? bigbuf : info->buf, (size_t)size, 1, info->f); 1010 } 1011 1012 /* If bigbuf was allocated, free it */ 1013 if (bigbuf) 1014 yasm_xfree(bigbuf); 1015 1016 return 0; 1017 } 1018 1019 /* Check to ensure bytecode is res* (for BSS sections) */ 1020 static int 1021 bin_objfmt_no_output_bytecode(yasm_bytecode *bc, /*@null@*/ void *d) 1022 { 1023 /*@null@*/ bin_objfmt_output_info *info = (bin_objfmt_output_info *)d; 1024 /*@null@*/ /*@only@*/ unsigned char *bigbuf; 1025 unsigned long size = REGULAR_OUTBUF_SIZE; 1026 int gap; 1027 1028 assert(info != NULL); 1029 1030 bigbuf = yasm_bc_tobytes(bc, info->buf, &size, &gap, info, 1031 bin_objfmt_output_value, NULL); 1032 1033 /* If bigbuf was allocated, free it */ 1034 if (bigbuf) 1035 yasm_xfree(bigbuf); 1036 1037 /* Don't bother doing anything else if size ended up being 0. */ 1038 if (size == 0) 1039 return 0; 1040 1041 /* Warn if not a gap. */ 1042 if (!gap) { 1043 yasm_warn_set(YASM_WARN_GENERAL, 1044 N_("initialized space declared in nobits section: ignoring")); 1045 } 1046 1047 return 0; 1048 } 1049 1050 static int 1051 bin_objfmt_output_section(yasm_section *sect, /*@null@*/ void *d) 1052 { 1053 bin_section_data *bsd = yasm_section_get_data(sect, &bin_section_data_cb); 1054 /*@null@*/ bin_objfmt_output_info *info = (bin_objfmt_output_info *)d; 1055 1056 assert(bsd != NULL); 1057 assert(info != NULL); 1058 1059 if (bsd->bss) { 1060 yasm_section_bcs_traverse(sect, info->errwarns, 1061 info, bin_objfmt_no_output_bytecode); 1062 } else { 1063 yasm_intnum_set(info->tmp_intn, bsd->istart); 1064 yasm_intnum_calc(info->tmp_intn, YASM_EXPR_SUB, info->origin); 1065 if (yasm_intnum_sign(info->tmp_intn) < 0) { 1066 yasm_error_set(YASM_ERROR_VALUE, 1067 N_("section `%s' starts before origin (ORG)"), 1068 yasm_section_get_name(sect)); 1069 yasm_errwarn_propagate(info->errwarns, 0); 1070 return 0; 1071 } 1072 if (!yasm_intnum_check_size(info->tmp_intn, sizeof(long)*8, 0, 1)) { 1073 yasm_error_set(YASM_ERROR_VALUE, 1074 N_("section `%s' start value too large"), 1075 yasm_section_get_name(sect)); 1076 yasm_errwarn_propagate(info->errwarns, 0); 1077 return 0; 1078 } 1079 if (fseek(info->f, yasm_intnum_get_int(info->tmp_intn) + info->start, 1080 SEEK_SET) < 0) 1081 yasm__fatal(N_("could not seek on output file")); 1082 yasm_section_bcs_traverse(sect, info->errwarns, 1083 info, bin_objfmt_output_bytecode); 1084 } 1085 1086 return 0; 1087 } 1088 1089 static void 1090 bin_objfmt_cleanup(bin_objfmt_output_info *info) 1091 { 1092 bin_group *group, *group_temp; 1093 1094 yasm_xfree(info->buf); 1095 yasm_intnum_destroy(info->origin); 1096 yasm_intnum_destroy(info->tmp_intn); 1097 1098 TAILQ_FOREACH_SAFE(group, &info->lma_groups, link, group_temp) 1099 bin_group_destroy(group); 1100 1101 TAILQ_FOREACH_SAFE(group, &info->vma_groups, link, group_temp) 1102 bin_group_destroy(group); 1103 } 1104 1105 static void 1106 bin_objfmt_output(yasm_object *object, FILE *f, /*@unused@*/ int all_syms, 1107 yasm_errwarns *errwarns) 1108 { 1109 yasm_objfmt_bin *objfmt_bin = (yasm_objfmt_bin *)object->objfmt; 1110 bin_objfmt_output_info info; 1111 bin_group *group, *lma_group, *vma_group, *group_temp; 1112 yasm_intnum *start, *last, *vdelta; 1113 bin_groups unsorted_groups, bss_groups; 1114 1115 info.start = ftell(f); 1116 1117 /* Set ORG to 0 unless otherwise specified */ 1118 if (objfmt_bin->org) { 1119 info.origin = yasm_expr_get_intnum(&objfmt_bin->org, 0); 1120 if (!info.origin) { 1121 yasm_error_set(YASM_ERROR_TOO_COMPLEX, 1122 N_("ORG expression is too complex")); 1123 yasm_errwarn_propagate(errwarns, objfmt_bin->org->line); 1124 return; 1125 } 1126 if (yasm_intnum_sign(info.origin) < 0) { 1127 yasm_error_set(YASM_ERROR_VALUE, N_("ORG expression is negative")); 1128 yasm_errwarn_propagate(errwarns, objfmt_bin->org->line); 1129 return; 1130 } 1131 info.origin = yasm_intnum_copy(info.origin); 1132 } else 1133 info.origin = yasm_intnum_create_uint(0); 1134 1135 info.object = object; 1136 info.errwarns = errwarns; 1137 info.f = f; 1138 info.buf = yasm_xmalloc(REGULAR_OUTBUF_SIZE); 1139 info.tmp_intn = yasm_intnum_create_uint(0); 1140 TAILQ_INIT(&info.lma_groups); 1141 TAILQ_INIT(&info.vma_groups); 1142 1143 /* Check symbol table */ 1144 yasm_symtab_traverse(object->symtab, &info, bin_objfmt_check_sym); 1145 1146 /* Create section groups */ 1147 if (yasm_object_sections_traverse(object, &info, bin_lma_create_group)) { 1148 bin_objfmt_cleanup(&info); 1149 return; /* error detected */ 1150 } 1151 1152 /* Determine section order according to LMA. 1153 * Sections can be ordered either by (priority): 1154 * - follows 1155 * - start 1156 * - progbits/nobits setting 1157 * - order in the input file 1158 */ 1159 1160 /* Look at each group with follows specified, and find the section 1161 * that group is supposed to follow. 1162 */ 1163 TAILQ_FOREACH_SAFE(lma_group, &info.lma_groups, link, group_temp) { 1164 if (lma_group->bsd->follows) { 1165 bin_group *found; 1166 /* Need to find group containing section this section follows. */ 1167 found = 1168 find_group_by_name(&info.lma_groups, lma_group->bsd->follows); 1169 if (!found) { 1170 yasm_error_set(YASM_ERROR_VALUE, 1171 N_("section `%s' follows an invalid or unknown section `%s'"), 1172 yasm_section_get_name(lma_group->section), 1173 lma_group->bsd->follows); 1174 yasm_errwarn_propagate(errwarns, 0); 1175 bin_objfmt_cleanup(&info); 1176 return; 1177 } 1178 1179 /* Check for loops */ 1180 if (lma_group->section == found->section || 1181 find_group_by_section(&lma_group->follow_groups, 1182 found->section)) { 1183 yasm_error_set(YASM_ERROR_VALUE, 1184 N_("follows loop between section `%s' and section `%s'"), 1185 yasm_section_get_name(lma_group->section), 1186 yasm_section_get_name(found->section)); 1187 yasm_errwarn_propagate(errwarns, 0); 1188 bin_objfmt_cleanup(&info); 1189 return; 1190 } 1191 1192 /* Remove this section from main lma groups list */ 1193 TAILQ_REMOVE(&info.lma_groups, lma_group, link); 1194 /* Add it after the section it's supposed to follow. */ 1195 TAILQ_INSERT_TAIL(&found->follow_groups, lma_group, link); 1196 } 1197 } 1198 1199 /* Sort the top-level groups according to their start address. 1200 * Use Shell sort for ease of implementation. 1201 * If no start address is specified for a section, don't change the order, 1202 * and move BSS sections to a separate list so they can be moved to the 1203 * end of the lma list after all other sections are sorted. 1204 */ 1205 unsorted_groups = info.lma_groups; /* structure copy */ 1206 TAILQ_INIT(&info.lma_groups); 1207 TAILQ_INIT(&bss_groups); 1208 TAILQ_FOREACH_SAFE(lma_group, &unsorted_groups, link, group_temp) { 1209 bin_group *before; 1210 1211 if (!lma_group->bsd->istart) { 1212 if (lma_group->bsd->bss) 1213 TAILQ_INSERT_TAIL(&bss_groups, lma_group, link); 1214 else 1215 TAILQ_INSERT_TAIL(&info.lma_groups, lma_group, link); 1216 continue; 1217 } 1218 1219 before = NULL; 1220 TAILQ_FOREACH(group, &info.lma_groups, link) { 1221 if (!group->bsd->istart) 1222 continue; 1223 if (yasm_intnum_compare(group->bsd->istart, 1224 lma_group->bsd->istart) > 0) { 1225 before = group; 1226 break; 1227 } 1228 } 1229 if (before) 1230 TAILQ_INSERT_BEFORE(before, lma_group, link); 1231 else 1232 TAILQ_INSERT_TAIL(&info.lma_groups, lma_group, link); 1233 } 1234 1235 /* Move the pure-BSS sections to the end of the LMA list. */ 1236 TAILQ_FOREACH_SAFE(group, &bss_groups, link, group_temp) 1237 TAILQ_INSERT_TAIL(&info.lma_groups, group, link); 1238 TAILQ_INIT(&bss_groups); /* For sanity */ 1239 1240 /* Assign a LMA start address to every section. 1241 * Also assign VMA=LMA unless otherwise specified. 1242 * 1243 * We need to assign VMA=LMA here (while walking the tree) for the case: 1244 * sect1 start=0 (size=0x11) 1245 * sect2 follows=sect1 valign=16 (size=0x104) 1246 * sect3 follows=sect2 valign=16 1247 * Where the valign of sect2 will result in a sect3 vaddr higher than a 1248 * naive segment-by-segment interpretation (where sect3 and sect2 would 1249 * have a VMA overlap). 1250 * 1251 * Algorithm for VMA=LMA setting: 1252 * Start with delta=0. 1253 * If there's no virtual attributes, we simply set VMA = LMA+delta. 1254 * If there's only valign specified, we set VMA = aligned LMA, and add 1255 * any new alignment difference to delta. 1256 * 1257 * We could do the LMA start and VMA=LMA steps in two separate steps, 1258 * but it's easier to just recurse once. 1259 */ 1260 start = yasm_intnum_copy(info.origin); 1261 last = yasm_intnum_copy(info.origin); 1262 vdelta = yasm_intnum_create_uint(0); 1263 TAILQ_FOREACH(lma_group, &info.lma_groups, link) { 1264 if (lma_group->bsd->istart) 1265 yasm_intnum_set(start, lma_group->bsd->istart); 1266 group_assign_start_recurse(lma_group, start, last, vdelta, 1267 info.tmp_intn, errwarns); 1268 yasm_intnum_set(start, last); 1269 } 1270 yasm_intnum_destroy(last); 1271 yasm_intnum_destroy(vdelta); 1272 1273 /* 1274 * Determine section order according to VMA 1275 */ 1276 1277 /* Create section groups */ 1278 if (yasm_object_sections_traverse(object, &info, bin_vma_create_group)) { 1279 yasm_intnum_destroy(start); 1280 bin_objfmt_cleanup(&info); 1281 return; /* error detected */ 1282 } 1283 1284 /* Look at each group with vfollows specified, and find the section 1285 * that group is supposed to follow. 1286 */ 1287 TAILQ_FOREACH_SAFE(vma_group, &info.vma_groups, link, group_temp) { 1288 if (vma_group->bsd->vfollows) { 1289 bin_group *found; 1290 /* Need to find group containing section this section follows. */ 1291 found = find_group_by_name(&info.vma_groups, 1292 vma_group->bsd->vfollows); 1293 if (!found) { 1294 yasm_error_set(YASM_ERROR_VALUE, 1295 N_("section `%s' vfollows an invalid or unknown section `%s'"), 1296 yasm_section_get_name(vma_group->section), 1297 vma_group->bsd->vfollows); 1298 yasm_errwarn_propagate(errwarns, 0); 1299 yasm_intnum_destroy(start); 1300 bin_objfmt_cleanup(&info); 1301 return; 1302 } 1303 1304 /* Check for loops */ 1305 if (vma_group->section == found->section || 1306 find_group_by_section(&vma_group->follow_groups, 1307 found->section)) { 1308 yasm_error_set(YASM_ERROR_VALUE, 1309 N_("vfollows loop between section `%s' and section `%s'"), 1310 yasm_section_get_name(vma_group->section), 1311 yasm_section_get_name(found->section)); 1312 yasm_errwarn_propagate(errwarns, 0); 1313 bin_objfmt_cleanup(&info); 1314 return; 1315 } 1316 1317 /* Remove this section from main lma groups list */ 1318 TAILQ_REMOVE(&info.vma_groups, vma_group, link); 1319 /* Add it after the section it's supposed to follow. */ 1320 TAILQ_INSERT_TAIL(&found->follow_groups, vma_group, link); 1321 } 1322 } 1323 1324 /* Due to the combination of steps above, we now know that all top-level 1325 * groups have integer ivstart: 1326 * Vstart Vfollows Valign Handled by 1327 * No No No group_assign_start_recurse() 1328 * No No Yes group_assign_start_recurse() 1329 * No Yes - vfollows loop (above) 1330 * Yes - - bin_lma_create_group() 1331 */ 1332 TAILQ_FOREACH(vma_group, &info.vma_groups, link) { 1333 yasm_intnum_set(start, vma_group->bsd->ivstart); 1334 group_assign_vstart_recurse(vma_group, start, errwarns); 1335 } 1336 1337 /* Output map file */ 1338 output_map(&info); 1339 1340 /* Ensure we don't have overlapping progbits LMAs. 1341 * Use a dumb O(N^2) algorithm as the number of sections is essentially 1342 * always low. 1343 */ 1344 if (yasm_object_sections_traverse(object, NULL, check_lma_overlap)) { 1345 yasm_errwarn_propagate(errwarns, 0); 1346 yasm_intnum_destroy(start); 1347 bin_objfmt_cleanup(&info); 1348 return; 1349 } 1350 1351 /* Output sections */ 1352 yasm_object_sections_traverse(object, &info, bin_objfmt_output_section); 1353 1354 /* Clean up */ 1355 yasm_intnum_destroy(start); 1356 bin_objfmt_cleanup(&info); 1357 } 1358 1359 static void 1360 bin_objfmt_destroy(yasm_objfmt *objfmt) 1361 { 1362 yasm_objfmt_bin *objfmt_bin = (yasm_objfmt_bin *)objfmt; 1363 if (objfmt_bin->map_filename) 1364 yasm_xfree(objfmt_bin->map_filename); 1365 yasm_expr_destroy(objfmt_bin->org); 1366 yasm_xfree(objfmt); 1367 } 1368 1369 static void 1370 define_section_symbol(yasm_symtab *symtab, yasm_section *sect, 1371 const char *sectname, const char *suffix, 1372 enum bin_ssym which, unsigned long line) 1373 { 1374 yasm_symrec *sym; 1375 bin_symrec_data *bsymd = yasm_xmalloc(sizeof(bin_symrec_data)); 1376 char *symname = yasm_xmalloc(8+strlen(sectname)+strlen(suffix)+1); 1377 1378 strcpy(symname, "section."); 1379 strcat(symname, sectname); 1380 strcat(symname, suffix); 1381 1382 bsymd->section = sect; 1383 bsymd->which = which; 1384 1385 sym = yasm_symtab_declare(symtab, symname, YASM_SYM_EXTERN, line); 1386 yasm_xfree(symname); 1387 yasm_symrec_add_data(sym, &bin_symrec_data_cb, bsymd); 1388 } 1389 1390 static void 1391 bin_objfmt_init_new_section(yasm_section *sect, unsigned long line) 1392 { 1393 yasm_object *object = yasm_section_get_object(sect); 1394 const char *sectname = yasm_section_get_name(sect); 1395 /*yasm_objfmt_bin *objfmt_bin = (yasm_objfmt_bin *)object->objfmt;*/ 1396 bin_section_data *data; 1397 1398 data = yasm_xmalloc(sizeof(bin_section_data)); 1399 data->bss = 0; 1400 data->align = NULL; 1401 data->valign = NULL; 1402 data->start = NULL; 1403 data->vstart = NULL; 1404 data->follows = NULL; 1405 data->vfollows = NULL; 1406 data->istart = NULL; 1407 data->ivstart = NULL; 1408 data->length = NULL; 1409 yasm_section_add_data(sect, &bin_section_data_cb, data); 1410 1411 define_section_symbol(object->symtab, sect, sectname, ".start", 1412 SSYM_START, line); 1413 define_section_symbol(object->symtab, sect, sectname, ".vstart", 1414 SSYM_VSTART, line); 1415 define_section_symbol(object->symtab, sect, sectname, ".length", 1416 SSYM_LENGTH, line); 1417 } 1418 1419 static yasm_section * 1420 bin_objfmt_add_default_section(yasm_object *object) 1421 { 1422 yasm_section *retval; 1423 int isnew; 1424 1425 retval = yasm_object_get_general(object, ".text", 0, 1, 0, &isnew, 0); 1426 if (isnew) 1427 yasm_section_set_default(retval, 1); 1428 return retval; 1429 } 1430 1431 /* GAS-style flags */ 1432 static int 1433 bin_helper_gasflags(void *obj, yasm_valparam *vp, unsigned long line, void *d, 1434 /*@unused@*/ uintptr_t arg) 1435 { 1436 /* TODO */ 1437 return 0; 1438 } 1439 1440 static /*@observer@*/ /*@null@*/ yasm_section * 1441 bin_objfmt_section_switch(yasm_object *object, yasm_valparamhead *valparams, 1442 /*@unused@*/ /*@null@*/ 1443 yasm_valparamhead *objext_valparams, 1444 unsigned long line) 1445 { 1446 yasm_valparam *vp; 1447 yasm_section *retval; 1448 int isnew; 1449 int flags_override = 0; 1450 const char *sectname; 1451 bin_section_data *bsd = NULL; 1452 1453 struct bin_section_switch_data { 1454 /*@only@*/ /*@null@*/ char *follows; 1455 /*@only@*/ /*@null@*/ char *vfollows; 1456 /*@only@*/ /*@null@*/ yasm_expr *start; 1457 /*@only@*/ /*@null@*/ yasm_expr *vstart; 1458 /*@only@*/ /*@null@*/ yasm_intnum *align; 1459 /*@only@*/ /*@null@*/ yasm_intnum *valign; 1460 unsigned long bss; 1461 unsigned long code; 1462 } data; 1463 1464 static const yasm_dir_help help[] = { 1465 { "follows", 1, yasm_dir_helper_string, 1466 offsetof(struct bin_section_switch_data, follows), 0 }, 1467 { "vfollows", 1, yasm_dir_helper_string, 1468 offsetof(struct bin_section_switch_data, vfollows), 0 }, 1469 { "start", 1, yasm_dir_helper_expr, 1470 offsetof(struct bin_section_switch_data, start), 0 }, 1471 { "vstart", 1, yasm_dir_helper_expr, 1472 offsetof(struct bin_section_switch_data, vstart), 0 }, 1473 { "align", 1, yasm_dir_helper_intn, 1474 offsetof(struct bin_section_switch_data, align), 0 }, 1475 { "valign", 1, yasm_dir_helper_intn, 1476 offsetof(struct bin_section_switch_data, valign), 0 }, 1477 { "nobits", 0, yasm_dir_helper_flag_set, 1478 offsetof(struct bin_section_switch_data, bss), 1 }, 1479 { "progbits", 0, yasm_dir_helper_flag_set, 1480 offsetof(struct bin_section_switch_data, bss), 0 }, 1481 { "code", 0, yasm_dir_helper_flag_set, 1482 offsetof(struct bin_section_switch_data, code), 1 }, 1483 { "data", 0, yasm_dir_helper_flag_set, 1484 offsetof(struct bin_section_switch_data, code), 0 }, 1485 { "execute", 0, yasm_dir_helper_flag_set, 1486 offsetof(struct bin_section_switch_data, code), 1 }, 1487 { "noexecute", 0, yasm_dir_helper_flag_set, 1488 offsetof(struct bin_section_switch_data, code), 0 }, 1489 { "gasflags", 1, bin_helper_gasflags, 0, 0 } 1490 }; 1491 1492 vp = yasm_vps_first(valparams); 1493 sectname = yasm_vp_string(vp); 1494 if (!sectname) 1495 return NULL; 1496 vp = yasm_vps_next(vp); 1497 1498 retval = yasm_object_find_general(object, sectname); 1499 if (retval) { 1500 bsd = yasm_section_get_data(retval, &bin_section_data_cb); 1501 assert(bsd != NULL); 1502 data.follows = bsd->follows; 1503 data.vfollows = bsd->vfollows; 1504 data.start = bsd->start; 1505 data.vstart = bsd->vstart; 1506 data.align = NULL; 1507 data.valign = NULL; 1508 data.bss = bsd->bss; 1509 data.code = yasm_section_is_code(retval); 1510 } else { 1511 data.follows = NULL; 1512 data.vfollows = NULL; 1513 data.start = NULL; 1514 data.vstart = NULL; 1515 data.align = NULL; 1516 data.valign = NULL; 1517 data.bss = strcmp(sectname, ".bss") == 0; 1518 data.code = strcmp(sectname, ".text") == 0; 1519 } 1520 1521 flags_override = yasm_dir_helper(object, vp, line, help, NELEMS(help), 1522 &data, yasm_dir_helper_valparam_warn); 1523 if (flags_override < 0) 1524 return NULL; /* error occurred */ 1525 1526 if (data.start && data.follows) { 1527 yasm_error_set(YASM_ERROR_GENERAL, 1528 N_("cannot combine `start' and `follows' section attributes")); 1529 return NULL; 1530 } 1531 1532 if (data.vstart && data.vfollows) { 1533 yasm_error_set(YASM_ERROR_GENERAL, 1534 N_("cannot combine `vstart' and `vfollows' section attributes")); 1535 return NULL; 1536 } 1537 1538 if (data.align) { 1539 unsigned long align = yasm_intnum_get_uint(data.align); 1540 1541 /* Alignments must be a power of two. */ 1542 if (!is_exp2(align)) { 1543 yasm_error_set(YASM_ERROR_VALUE, 1544 N_("argument to `%s' is not a power of two"), 1545 "align"); 1546 return NULL; 1547 } 1548 } else 1549 data.align = bsd ? bsd->align : NULL; 1550 1551 if (data.valign) { 1552 unsigned long valign = yasm_intnum_get_uint(data.valign); 1553 1554 /* Alignments must be a power of two. */ 1555 if (!is_exp2(valign)) { 1556 yasm_error_set(YASM_ERROR_VALUE, 1557 N_("argument to `%s' is not a power of two"), 1558 "valign"); 1559 return NULL; 1560 } 1561 } else 1562 data.valign = bsd ? bsd->valign : NULL; 1563 1564 retval = yasm_object_get_general(object, sectname, 0, (int)data.code, 1565 (int)data.bss, &isnew, line); 1566 1567 bsd = yasm_section_get_data(retval, &bin_section_data_cb); 1568 1569 if (isnew || yasm_section_is_default(retval)) { 1570 yasm_section_set_default(retval, 0); 1571 } 1572 1573 /* Update section flags */ 1574 bsd->bss = data.bss; 1575 bsd->align = data.align; 1576 bsd->valign = data.valign; 1577 bsd->start = data.start; 1578 bsd->vstart = data.vstart; 1579 bsd->follows = data.follows; 1580 bsd->vfollows = data.vfollows; 1581 1582 return retval; 1583 } 1584 1585 static /*@observer@*/ /*@null@*/ yasm_symrec * 1586 bin_objfmt_get_special_sym(yasm_object *object, const char *name, 1587 const char *parser) 1588 { 1589 return NULL; 1590 } 1591 1592 static void 1593 bin_objfmt_dir_org(yasm_object *object, 1594 /*@null@*/ yasm_valparamhead *valparams, 1595 /*@unused@*/ /*@null@*/ 1596 yasm_valparamhead *objext_valparams, unsigned long line) 1597 { 1598 yasm_objfmt_bin *objfmt_bin = (yasm_objfmt_bin *)object->objfmt; 1599 yasm_valparam *vp; 1600 1601 /* We only allow a single ORG in a program. */ 1602 if (objfmt_bin->org) { 1603 yasm_error_set(YASM_ERROR_GENERAL, N_("program origin redefined")); 1604 return; 1605 } 1606 1607 /* ORG takes just a simple expression as param */ 1608 vp = yasm_vps_first(valparams); 1609 objfmt_bin->org = yasm_vp_expr(vp, object->symtab, line); 1610 if (!objfmt_bin->org) { 1611 yasm_error_set(YASM_ERROR_SYNTAX, 1612 N_("argument to ORG must be expression")); 1613 return; 1614 } 1615 } 1616 1617 struct bin_dir_map_data { 1618 unsigned long flags; 1619 /*@only@*/ /*@null@*/ char *filename; 1620 }; 1621 1622 static int 1623 dir_map_filename(void *obj, yasm_valparam *vp, unsigned long line, void *data) 1624 { 1625 struct bin_dir_map_data *mdata = (struct bin_dir_map_data *)data; 1626 const char *filename; 1627 1628 if (mdata->filename) { 1629 yasm_warn_set(YASM_WARN_GENERAL, N_("map file already specified")); 1630 return 0; 1631 } 1632 1633 filename = yasm_vp_string(vp); 1634 if (!filename) { 1635 yasm_error_set(YASM_ERROR_SYNTAX, 1636 N_("unexpected expression in [map]")); 1637 return -1; 1638 } 1639 mdata->filename = yasm__xstrdup(filename); 1640 1641 return 1; 1642 } 1643 1644 static void 1645 bin_objfmt_dir_map(yasm_object *object, 1646 /*@null@*/ yasm_valparamhead *valparams, 1647 /*@unused@*/ /*@null@*/ 1648 yasm_valparamhead *objext_valparams, unsigned long line) 1649 { 1650 yasm_objfmt_bin *objfmt_bin = (yasm_objfmt_bin *)object->objfmt; 1651 1652 struct bin_dir_map_data data; 1653 1654 static const yasm_dir_help help[] = { 1655 { "all", 0, yasm_dir_helper_flag_or, 1656 offsetof(struct bin_dir_map_data, flags), 1657 MAP_BRIEF|MAP_SECTIONS|MAP_SYMBOLS }, 1658 { "brief", 0, yasm_dir_helper_flag_or, 1659 offsetof(struct bin_dir_map_data, flags), MAP_BRIEF }, 1660 { "sections", 0, yasm_dir_helper_flag_or, 1661 offsetof(struct bin_dir_map_data, flags), MAP_SECTIONS }, 1662 { "segments", 0, yasm_dir_helper_flag_or, 1663 offsetof(struct bin_dir_map_data, flags), MAP_SECTIONS }, 1664 { "symbols", 0, yasm_dir_helper_flag_or, 1665 offsetof(struct bin_dir_map_data, flags), MAP_SYMBOLS } 1666 }; 1667 1668 data.flags = objfmt_bin->map_flags | MAP_NONE; 1669 data.filename = objfmt_bin->map_filename; 1670 1671 if (valparams && yasm_dir_helper(object, yasm_vps_first(valparams), line, help, 1672 NELEMS(help), &data, dir_map_filename) < 0) 1673 return; /* error occurred */ 1674 1675 objfmt_bin->map_flags = data.flags; 1676 objfmt_bin->map_filename = data.filename; 1677 } 1678 1679 static void 1680 bin_section_data_destroy(void *data) 1681 { 1682 bin_section_data *bsd = (bin_section_data *)data; 1683 if (bsd->start) 1684 yasm_expr_destroy(bsd->start); 1685 if (bsd->vstart) 1686 yasm_expr_destroy(bsd->vstart); 1687 if (bsd->follows) 1688 yasm_xfree(bsd->follows); 1689 if (bsd->vfollows) 1690 yasm_xfree(bsd->vfollows); 1691 if (bsd->istart) 1692 yasm_intnum_destroy(bsd->istart); 1693 if (bsd->ivstart) 1694 yasm_intnum_destroy(bsd->ivstart); 1695 if (bsd->length) 1696 yasm_intnum_destroy(bsd->length); 1697 yasm_xfree(data); 1698 } 1699 1700 static void 1701 bin_section_data_print(void *data, FILE *f, int indent_level) 1702 { 1703 bin_section_data *bsd = (bin_section_data *)data; 1704 1705 fprintf(f, "%*sbss=%d\n", indent_level, "", bsd->bss); 1706 1707 fprintf(f, "%*salign=", indent_level, ""); 1708 if (bsd->align) 1709 yasm_intnum_print(bsd->align, f); 1710 else 1711 fprintf(f, "(nil)"); 1712 fprintf(f, "\n%*svalign=", indent_level, ""); 1713 if (bsd->valign) 1714 yasm_intnum_print(bsd->valign, f); 1715 else 1716 fprintf(f, "(nil)"); 1717 1718 fprintf(f, "\n%*sstart=", indent_level, ""); 1719 yasm_expr_print(bsd->start, f); 1720 fprintf(f, "\n%*svstart=", indent_level, ""); 1721 yasm_expr_print(bsd->vstart, f); 1722 1723 fprintf(f, "\n%*sfollows=", indent_level, ""); 1724 if (bsd->follows) 1725 fprintf(f, "\"%s\"", bsd->follows); 1726 else 1727 fprintf(f, "(nil)"); 1728 fprintf(f, "\n%*svfollows=", indent_level, ""); 1729 if (bsd->vfollows) 1730 fprintf(f, "\"%s\"", bsd->vfollows); 1731 else 1732 fprintf(f, "(nil)"); 1733 1734 fprintf(f, "\n%*sistart=", indent_level, ""); 1735 if (bsd->istart) 1736 yasm_intnum_print(bsd->istart, f); 1737 else 1738 fprintf(f, "(nil)"); 1739 fprintf(f, "\n%*sivstart=", indent_level, ""); 1740 if (bsd->ivstart) 1741 yasm_intnum_print(bsd->ivstart, f); 1742 else 1743 fprintf(f, "(nil)"); 1744 1745 fprintf(f, "\n%*slength=", indent_level, ""); 1746 if (bsd->length) 1747 yasm_intnum_print(bsd->length, f); 1748 else 1749 fprintf(f, "(nil)"); 1750 fprintf(f, "\n"); 1751 } 1752 1753 static void 1754 bin_symrec_data_destroy(void *data) 1755 { 1756 yasm_xfree(data); 1757 } 1758 1759 static void 1760 bin_symrec_data_print(void *data, FILE *f, int indent_level) 1761 { 1762 bin_symrec_data *bsymd = (bin_symrec_data *)data; 1763 1764 fprintf(f, "%*ssection=\"%s\"\n", indent_level, "", 1765 yasm_section_get_name(bsymd->section)); 1766 fprintf(f, "%*swhich=", indent_level, ""); 1767 switch (bsymd->which) { 1768 case SSYM_START: fprintf(f, "START"); break; 1769 case SSYM_VSTART: fprintf(f, "VSTART"); break; 1770 case SSYM_LENGTH: fprintf(f, "LENGTH"); break; 1771 } 1772 fprintf(f, "\n"); 1773 } 1774 1775 1776 /* Define valid debug formats to use with this object format */ 1777 static const char *bin_objfmt_dbgfmt_keywords[] = { 1778 "null", 1779 NULL 1780 }; 1781 1782 static const yasm_directive bin_objfmt_directives[] = { 1783 { "org", "nasm", bin_objfmt_dir_org, YASM_DIR_ARG_REQUIRED }, 1784 { "map", "nasm", bin_objfmt_dir_map, YASM_DIR_ANY }, 1785 { NULL, NULL, NULL, 0 } 1786 }; 1787 1788 static const char *bin_nasm_stdmac[] = { 1789 "%imacro org 1+.nolist", 1790 "[org %1]", 1791 "%endmacro", 1792 NULL 1793 }; 1794 1795 static const yasm_stdmac bin_objfmt_stdmacs[] = { 1796 { "nasm", "nasm", bin_nasm_stdmac }, 1797 { "tasm", "tasm", bin_nasm_stdmac }, 1798 { NULL, NULL, NULL } 1799 }; 1800 1801 /* Define objfmt structure -- see objfmt.h for details */ 1802 yasm_objfmt_module yasm_bin_LTX_objfmt = { 1803 "Flat format binary", 1804 "bin", 1805 NULL, 1806 16, 1807 0, 1808 bin_objfmt_dbgfmt_keywords, 1809 "null", 1810 bin_objfmt_directives, 1811 bin_objfmt_stdmacs, 1812 bin_objfmt_create, 1813 bin_objfmt_output, 1814 bin_objfmt_destroy, 1815 bin_objfmt_add_default_section, 1816 bin_objfmt_init_new_section, 1817 bin_objfmt_section_switch, 1818 bin_objfmt_get_special_sym 1819 }; 1820 1821 #define EXE_HEADER_SIZE 0x200 1822 1823 /* DOS .EXE binaries are just raw binaries with a header */ 1824 yasm_objfmt_module yasm_dosexe_LTX_objfmt; 1825 1826 static yasm_objfmt * 1827 dosexe_objfmt_create(yasm_object *object) 1828 { 1829 yasm_objfmt_bin *objfmt_bin = (yasm_objfmt_bin *) bin_objfmt_create(object); 1830 objfmt_bin->objfmt.module = &yasm_dosexe_LTX_objfmt; 1831 return (yasm_objfmt *)objfmt_bin; 1832 } 1833 1834 static unsigned long 1835 get_sym(yasm_object *object, const char *name) { 1836 yasm_symrec *symrec = yasm_symtab_get(object->symtab, name); 1837 yasm_bytecode *prevbc; 1838 if (!symrec) 1839 return 0; 1840 if (!yasm_symrec_get_label(symrec, &prevbc)) 1841 return 0; 1842 return prevbc->offset + prevbc->len; 1843 } 1844 1845 static void 1846 dosexe_objfmt_output(yasm_object *object, FILE *f, /*@unused@*/ int all_syms, 1847 yasm_errwarns *errwarns) 1848 { 1849 unsigned long tot_size, size, bss_size; 1850 unsigned long start, bss; 1851 unsigned char c; 1852 1853 fseek(f, EXE_HEADER_SIZE, SEEK_SET); 1854 1855 bin_objfmt_output(object, f, all_syms, errwarns); 1856 1857 tot_size = ftell(f); 1858 1859 /* if there is a __bss_start symbol, data after it is 0, no need to write 1860 * it. */ 1861 bss = get_sym(object, "__bss_start"); 1862 if (bss) 1863 size = bss; 1864 else 1865 size = tot_size; 1866 bss_size = tot_size - size; 1867 #ifdef HAVE_FTRUNCATE 1868 if (size != tot_size) 1869 ftruncate(fileno(f), EXE_HEADER_SIZE + size); 1870 #endif 1871 fseek(f, 0, SEEK_SET); 1872 1873 /* magic */ 1874 fwrite("MZ", 1, 2, f); 1875 1876 /* file size */ 1877 c = size & 0xff; 1878 fwrite(&c, 1, 1, f); 1879 c = !!(size & 0x100); 1880 fwrite(&c, 1, 1, f); 1881 c = ((size + 511) >> 9) & 0xff; 1882 fwrite(&c, 1, 1, f); 1883 c = ((size + 511) >> 17) & 0xff; 1884 fwrite(&c, 1, 1, f); 1885 1886 /* relocation # */ 1887 c = 0; 1888 fwrite(&c, 1, 1, f); 1889 fwrite(&c, 1, 1, f); 1890 1891 /* header size */ 1892 c = EXE_HEADER_SIZE / 16; 1893 fwrite(&c, 1, 1, f); 1894 c = 0; 1895 fwrite(&c, 1, 1, f); 1896 1897 /* minimum paragraph # */ 1898 bss_size = (bss_size + 15) >> 4; 1899 c = bss_size & 0xff; 1900 fwrite(&c, 1, 1, f); 1901 c = (bss_size >> 8) & 0xff; 1902 fwrite(&c, 1, 1, f); 1903 1904 /* maximum paragraph # */ 1905 c = 0xFF; 1906 fwrite(&c, 1, 1, f); 1907 fwrite(&c, 1, 1, f); 1908 1909 /* relative value of stack segment */ 1910 c = 0; 1911 fwrite(&c, 1, 1, f); 1912 fwrite(&c, 1, 1, f); 1913 1914 /* SP at start */ 1915 c = 0; 1916 fwrite(&c, 1, 1, f); 1917 fwrite(&c, 1, 1, f); 1918 1919 /* header checksum */ 1920 c = 0; 1921 fwrite(&c, 1, 1, f); 1922 fwrite(&c, 1, 1, f); 1923 1924 /* IP at start */ 1925 start = get_sym(object, "start"); 1926 if (!start) { 1927 yasm_error_set(YASM_ERROR_GENERAL, 1928 N_("%s: could not find symbol `start'")); 1929 return; 1930 } 1931 c = start & 0xff; 1932 fwrite(&c, 1, 1, f); 1933 c = (start >> 8) & 0xff; 1934 fwrite(&c, 1, 1, f); 1935 1936 /* CS start */ 1937 c = 0; 1938 fwrite(&c, 1, 1, f); 1939 fwrite(&c, 1, 1, f); 1940 1941 /* reloc start */ 1942 c = 0x22; 1943 fwrite(&c, 1, 1, f); 1944 c = 0; 1945 fwrite(&c, 1, 1, f); 1946 1947 /* Overlay number */ 1948 c = 0; 1949 fwrite(&c, 1, 1, f); 1950 fwrite(&c, 1, 1, f); 1951 } 1952 1953 1954 /* Define objfmt structure -- see objfmt.h for details */ 1955 yasm_objfmt_module yasm_dosexe_LTX_objfmt = { 1956 "DOS .EXE format binary", 1957 "dosexe", 1958 "exe", 1959 16, 1960 0, 1961 bin_objfmt_dbgfmt_keywords, 1962 "null", 1963 bin_objfmt_directives, 1964 bin_objfmt_stdmacs, 1965 dosexe_objfmt_create, 1966 dosexe_objfmt_output, 1967 bin_objfmt_destroy, 1968 bin_objfmt_add_default_section, 1969 bin_objfmt_init_new_section, 1970 bin_objfmt_section_switch, 1971 bin_objfmt_get_special_sym 1972 }; 1973