Home | History | Annotate | Download | only in bin
      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