aboutsummaryrefslogtreecommitdiffstats
path: root/contrib/tools/yasm/modules/objfmts/bin
diff options
context:
space:
mode:
authorsomov <somov@yandex-team.ru>2022-02-10 16:45:49 +0300
committerDaniil Cherednik <dcherednik@yandex-team.ru>2022-02-10 16:45:49 +0300
commit7489e4682331202b9c7d863c0898eb83d7b12c2b (patch)
tree9142afc54d335ea52910662635b898e79e192e49 /contrib/tools/yasm/modules/objfmts/bin
parenta5950576e397b1909261050b8c7da16db58f10b1 (diff)
downloadydb-7489e4682331202b9c7d863c0898eb83d7b12c2b.tar.gz
Restoring authorship annotation for <somov@yandex-team.ru>. Commit 2 of 2.
Diffstat (limited to 'contrib/tools/yasm/modules/objfmts/bin')
-rw-r--r--contrib/tools/yasm/modules/objfmts/bin/bin-objfmt.c3944
1 files changed, 1972 insertions, 1972 deletions
diff --git a/contrib/tools/yasm/modules/objfmts/bin/bin-objfmt.c b/contrib/tools/yasm/modules/objfmts/bin/bin-objfmt.c
index 702bda1590..5f422245d3 100644
--- a/contrib/tools/yasm/modules/objfmts/bin/bin-objfmt.c
+++ b/contrib/tools/yasm/modules/objfmts/bin/bin-objfmt.c
@@ -1,1972 +1,1972 @@
-/*
- * Flat-format binary object format
- *
- * Copyright (C) 2002-2007 Peter Johnson
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND OTHER CONTRIBUTORS ``AS IS''
- * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR OTHER CONTRIBUTORS BE
- * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
- * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
- * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
- * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
- * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
- * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
- * POSSIBILITY OF SUCH DAMAGE.
- */
-#include <util.h>
-
-#ifdef HAVE_UNISTD_H
-#include <unistd.h>
-#endif
-#include <libyasm.h>
-
-
-#define REGULAR_OUTBUF_SIZE 1024
-
-typedef struct bin_section_data {
- int bss; /* aka nobits */
-
- /* User-provided alignment */
- yasm_intnum *align, *valign;
-
- /* User-provided starts */
- /*@null@*/ /*@owned@*/ yasm_expr *start, *vstart;
-
- /* User-provided follows */
- /*@null@*/ /*@owned@*/ char *follows, *vfollows;
-
- /* Calculated (final) starts, used only during output() */
- /*@null@*/ /*@owned@*/ yasm_intnum *istart, *ivstart;
-
- /* Calculated (final) length, used only during output() */
- /*@null@*/ /*@owned@*/ yasm_intnum *length;
-} bin_section_data;
-
-typedef struct yasm_objfmt_bin {
- yasm_objfmt_base objfmt; /* base structure */
-
- enum {
- NO_MAP = 0,
- MAP_NONE = 0x01,
- MAP_BRIEF = 0x02,
- MAP_SECTIONS = 0x04,
- MAP_SYMBOLS = 0x08
- } map_flags;
- /*@null@*/ /*@only@*/ char *map_filename;
-
- /*@null@*/ /*@only@*/ yasm_expr *org;
-} yasm_objfmt_bin;
-
-/* symrec data is used only for the special symbols section<sectname>.start,
- * section<sectname>.vstart, and section<sectname>.length
- */
-typedef struct bin_symrec_data {
- yasm_section *section; /* referenced section */
- enum bin_ssym {
- SSYM_START,
- SSYM_VSTART,
- SSYM_LENGTH
- } which;
-} bin_symrec_data;
-
-static void bin_section_data_destroy(/*@only@*/ void *d);
-static void bin_section_data_print(void *data, FILE *f, int indent_level);
-
-static const yasm_assoc_data_callback bin_section_data_cb = {
- bin_section_data_destroy,
- bin_section_data_print
-};
-
-static void bin_symrec_data_destroy(/*@only@*/ void *d);
-static void bin_symrec_data_print(void *data, FILE *f, int indent_level);
-
-static const yasm_assoc_data_callback bin_symrec_data_cb = {
- bin_symrec_data_destroy,
- bin_symrec_data_print
-};
-
-yasm_objfmt_module yasm_bin_LTX_objfmt;
-
-
-static yasm_objfmt *
-bin_objfmt_create(yasm_object *object)
-{
- yasm_objfmt_bin *objfmt_bin = yasm_xmalloc(sizeof(yasm_objfmt_bin));
- objfmt_bin->objfmt.module = &yasm_bin_LTX_objfmt;
-
- objfmt_bin->map_flags = NO_MAP;
- objfmt_bin->map_filename = NULL;
- objfmt_bin->org = NULL;
-
- return (yasm_objfmt *)objfmt_bin;
-}
-
-typedef TAILQ_HEAD(bin_group_head, bin_group) bin_groups;
-
-typedef struct bin_group {
- TAILQ_ENTRY(bin_group) link;
- yasm_section *section;
- bin_section_data *bsd;
-
- /* Groups that (in parallel) logically come immediately after this
- * group's section.
- */
- bin_groups follow_groups;
-} bin_group;
-
-/* Recursive function to find group containing named section. */
-static bin_group *
-find_group_by_name(bin_groups *groups, const char *name)
-{
- bin_group *group, *found;
- TAILQ_FOREACH(group, groups, link) {
- if (strcmp(yasm_section_get_name(group->section), name) == 0)
- return group;
- /* Recurse to loop through follow groups */
- found = find_group_by_name(&group->follow_groups, name);
- if (found)
- return found;
- }
- return NULL;
-}
-
-/* Recursive function to find group. Returns NULL if not found. */
-static bin_group *
-find_group_by_section(bin_groups *groups, yasm_section *section)
-{
- bin_group *group, *found;
- TAILQ_FOREACH(group, groups, link) {
- if (group->section == section)
- return group;
- /* Recurse to loop through follow groups */
- found = find_group_by_section(&group->follow_groups, section);
- if (found)
- return found;
- }
- return NULL;
-}
-
-#if 0
-/* Debugging function */
-static void
-print_groups(const bin_groups *groups, int indent_level)
-{
- bin_group *group;
- TAILQ_FOREACH(group, groups, link) {
- printf("%*sSection `%s':\n", indent_level, "",
- yasm_section_get_name(group->section));
- bin_section_data_print(group->bsd, stdout, indent_level+1);
- if (!TAILQ_EMPTY(&group->follow_groups)) {
- printf("%*sFollowing groups:\n", indent_level, "");
- print_groups(&group->follow_groups, indent_level+1);
- }
- }
-}
-#endif
-
-static void
-bin_group_destroy(/*@only@*/ bin_group *group)
-{
- bin_group *follow, *group_temp;
- TAILQ_FOREACH_SAFE(follow, &group->follow_groups, link, group_temp)
- bin_group_destroy(follow);
- yasm_xfree(group);
-}
-
-typedef struct bin_objfmt_output_info {
- yasm_object *object;
- yasm_errwarns *errwarns;
- /*@dependent@*/ FILE *f;
- /*@only@*/ unsigned char *buf;
- /*@observer@*/ const yasm_section *sect;
- unsigned long start; /* what normal variables go against */
-
- yasm_intnum *origin;
- yasm_intnum *tmp_intn; /* temporary working intnum */
-
- bin_groups lma_groups, vma_groups;
-} bin_objfmt_output_info;
-
-static int
-bin_objfmt_check_sym(yasm_symrec *sym, /*@null@*/ void *d)
-{
- /*@null@*/ bin_objfmt_output_info *info = (bin_objfmt_output_info *)d;
- yasm_sym_vis vis = yasm_symrec_get_visibility(sym);
- assert(info != NULL);
-
- /* Don't check internally-generated symbols. Only internally generated
- * symbols have symrec data, so simply check for its presence.
- */
- if (yasm_symrec_get_data(sym, &bin_symrec_data_cb))
- return 0;
-
- if (vis & YASM_SYM_EXTERN) {
- yasm_warn_set(YASM_WARN_GENERAL,
- N_("binary object format does not support extern variables"));
- yasm_errwarn_propagate(info->errwarns, yasm_symrec_get_decl_line(sym));
- } else if (vis & YASM_SYM_GLOBAL) {
- yasm_warn_set(YASM_WARN_GENERAL,
- N_("binary object format does not support global variables"));
- yasm_errwarn_propagate(info->errwarns, yasm_symrec_get_decl_line(sym));
- } else if (vis & YASM_SYM_COMMON) {
- yasm_error_set(YASM_ERROR_TYPE,
- N_("binary object format does not support common variables"));
- yasm_errwarn_propagate(info->errwarns, yasm_symrec_get_decl_line(sym));
- }
- return 0;
-}
-
-static int
-bin_lma_create_group(yasm_section *sect, /*@null@*/ void *d)
-{
- bin_objfmt_output_info *info = (bin_objfmt_output_info *)d;
- bin_section_data *bsd = yasm_section_get_data(sect, &bin_section_data_cb);
- unsigned long align = yasm_section_get_align(sect);
- bin_group *group;
-
- assert(info != NULL);
- assert(bsd != NULL);
-
- group = yasm_xmalloc(sizeof(bin_group));
- group->section = sect;
- group->bsd = bsd;
- TAILQ_INIT(&group->follow_groups);
-
- /* Determine section alignment as necessary. */
- if (!bsd->align)
- bsd->align = yasm_intnum_create_uint(align > 4 ? align : 4);
- else {
- yasm_intnum *align_intn = yasm_intnum_create_uint(align);
- if (yasm_intnum_compare(align_intn, bsd->align) > 0) {
- yasm_warn_set(YASM_WARN_GENERAL,
- N_("section `%s' internal align of %lu is greater than `%s' of %lu; using `%s'"),
- yasm_section_get_name(sect),
- yasm_intnum_get_uint(align_intn),
- N_("align"),
- yasm_intnum_get_uint(bsd->align),
- N_("align"));
- yasm_errwarn_propagate(info->errwarns, 0);
- }
- yasm_intnum_destroy(align_intn);
- }
-
- /* Calculate section integer start. */
- if (bsd->start) {
- bsd->istart = yasm_expr_get_intnum(&bsd->start, 0);
- if (!bsd->istart) {
- yasm_error_set(YASM_ERROR_TOO_COMPLEX,
- N_("start expression is too complex"));
- yasm_errwarn_propagate(info->errwarns, bsd->start->line);
- return 1;
- } else
- bsd->istart = yasm_intnum_copy(bsd->istart);
- } else
- bsd->istart = NULL;
-
- /* Calculate section integer vstart. */
- if (bsd->vstart) {
- bsd->ivstart = yasm_expr_get_intnum(&bsd->vstart, 0);
- if (!bsd->ivstart) {
- yasm_error_set(YASM_ERROR_TOO_COMPLEX,
- N_("vstart expression is too complex"));
- yasm_errwarn_propagate(info->errwarns, bsd->vstart->line);
- return 1;
- } else
- bsd->ivstart = yasm_intnum_copy(bsd->ivstart);
- } else
- bsd->ivstart = NULL;
-
- /* Calculate section integer length. */
- bsd->length = yasm_calc_bc_dist(yasm_section_bcs_first(sect),
- yasm_section_bcs_last(sect));
-
- TAILQ_INSERT_TAIL(&info->lma_groups, group, link);
- return 0;
-}
-
-static int
-bin_vma_create_group(yasm_section *sect, /*@null@*/ void *d)
-{
- bin_objfmt_output_info *info = (bin_objfmt_output_info *)d;
- bin_section_data *bsd = yasm_section_get_data(sect, &bin_section_data_cb);
- bin_group *group;
-
- assert(info != NULL);
- assert(bsd != NULL);
-
- group = yasm_xmalloc(sizeof(bin_group));
- group->section = sect;
- group->bsd = bsd;
- TAILQ_INIT(&group->follow_groups);
-
- TAILQ_INSERT_TAIL(&info->vma_groups, group, link);
- return 0;
-}
-
-/* Calculates new start address based on alignment constraint.
- * Start is modified (rounded up) to the closest aligned value greater than
- * what was passed in.
- * Align must be a power of 2.
- */
-static void
-bin_objfmt_align(yasm_intnum *start, const yasm_intnum *align)
-{
- /* Because alignment is always a power of two, we can use some bit
- * trickery to do this easily.
- */
- yasm_intnum *align_intn =
- yasm_intnum_create_uint(yasm_intnum_get_uint(align)-1);
- yasm_intnum_calc(align_intn, YASM_EXPR_AND, start);
- if (!yasm_intnum_is_zero(align_intn)) {
- /* start = (start & ~(align-1)) + align; */
- yasm_intnum_set_uint(align_intn, yasm_intnum_get_uint(align)-1);
- yasm_intnum_calc(align_intn, YASM_EXPR_NOT, NULL);
- yasm_intnum_calc(align_intn, YASM_EXPR_AND, start);
- yasm_intnum_set(start, align);
- yasm_intnum_calc(start, YASM_EXPR_ADD, align_intn);
- }
- yasm_intnum_destroy(align_intn);
-}
-
-/* Recursive function to assign start addresses.
- * Updates start, last, and vdelta parameters as it goes along.
- * The tmp parameter is just a working intnum so one doesn't have to be
- * locally allocated for this purpose.
- */
-static void
-group_assign_start_recurse(bin_group *group, yasm_intnum *start,
- yasm_intnum *last, yasm_intnum *vdelta,
- yasm_intnum *tmp, yasm_errwarns *errwarns)
-{
- bin_group *follow_group;
-
- /* Determine LMA */
- if (group->bsd->istart) {
- yasm_intnum_set(group->bsd->istart, start);
- if (group->bsd->align) {
- bin_objfmt_align(group->bsd->istart, group->bsd->align);
- if (yasm_intnum_compare(start, group->bsd->istart) != 0) {
- yasm_warn_set(YASM_WARN_GENERAL,
- N_("start inconsistent with align; using aligned value"));
- yasm_errwarn_propagate(errwarns, group->bsd->start->line);
- }
- }
- } else {
- group->bsd->istart = yasm_intnum_copy(start);
- if (group->bsd->align != 0)
- bin_objfmt_align(group->bsd->istart, group->bsd->align);
- }
-
- /* Determine VMA if either just valign specified or if no v* specified */
- if (!group->bsd->vstart) {
- if (!group->bsd->vfollows && !group->bsd->valign) {
- /* No v* specified, set VMA=LMA+vdelta. */
- group->bsd->ivstart = yasm_intnum_copy(group->bsd->istart);
- yasm_intnum_calc(group->bsd->ivstart, YASM_EXPR_ADD, vdelta);
- } else if (!group->bsd->vfollows) {
- /* Just valign specified: set VMA=LMA+vdelta, align VMA, then add
- * delta between unaligned and aligned to vdelta parameter.
- */
- group->bsd->ivstart = yasm_intnum_copy(group->bsd->istart);
- yasm_intnum_calc(group->bsd->ivstart, YASM_EXPR_ADD, vdelta);
- yasm_intnum_set(tmp, group->bsd->ivstart);
- bin_objfmt_align(group->bsd->ivstart, group->bsd->valign);
- yasm_intnum_calc(vdelta, YASM_EXPR_ADD, group->bsd->ivstart);
- yasm_intnum_calc(vdelta, YASM_EXPR_SUB, tmp);
- }
- }
-
- /* Find the maximum end value */
- yasm_intnum_set(tmp, group->bsd->istart);
- yasm_intnum_calc(tmp, YASM_EXPR_ADD, group->bsd->length);
- if (yasm_intnum_compare(tmp, last) > 0) /* tmp > last */
- yasm_intnum_set(last, tmp);
-
- /* Recurse for each following group. */
- TAILQ_FOREACH(follow_group, &group->follow_groups, link) {
- /* Following sections have to follow this one,
- * so add length to start.
- */
- yasm_intnum_set(start, group->bsd->istart);
- yasm_intnum_calc(start, YASM_EXPR_ADD, group->bsd->length);
-
- group_assign_start_recurse(follow_group, start, last, vdelta, tmp,
- errwarns);
- }
-}
-
-/* Recursive function to assign start addresses.
- * Updates start parameter as it goes along.
- * The tmp parameter is just a working intnum so one doesn't have to be
- * locally allocated for this purpose.
- */
-static void
-group_assign_vstart_recurse(bin_group *group, yasm_intnum *start,
- yasm_errwarns *errwarns)
-{
- bin_group *follow_group;
-
- /* Determine VMA section alignment as necessary.
- * Default to LMA alignment if not specified.
- */
- if (!group->bsd->valign)
- group->bsd->valign = yasm_intnum_copy(group->bsd->align);
- else {
- unsigned long align = yasm_section_get_align(group->section);
- yasm_intnum *align_intn = yasm_intnum_create_uint(align);
- if (yasm_intnum_compare(align_intn, group->bsd->valign) > 0) {
- yasm_warn_set(YASM_WARN_GENERAL,
- N_("section `%s' internal align of %lu is greater than `%s' of %lu; using `%s'"),
- yasm_section_get_name(group->section),
- yasm_intnum_get_uint(align_intn),
- N_("valign"),
- yasm_intnum_get_uint(group->bsd->valign),
- N_("valign"));
- yasm_errwarn_propagate(errwarns, 0);
- }
- yasm_intnum_destroy(align_intn);
- }
-
- /* Determine VMA */
- if (group->bsd->ivstart) {
- yasm_intnum_set(group->bsd->ivstart, start);
- if (group->bsd->valign) {
- bin_objfmt_align(group->bsd->ivstart, group->bsd->valign);
- if (yasm_intnum_compare(start, group->bsd->ivstart) != 0) {
- yasm_error_set(YASM_ERROR_VALUE,
- N_("vstart inconsistent with valign"));
- yasm_errwarn_propagate(errwarns, group->bsd->vstart->line);
- }
- }
- } else {
- group->bsd->ivstart = yasm_intnum_copy(start);
- if (group->bsd->valign)
- bin_objfmt_align(group->bsd->ivstart, group->bsd->valign);
- }
-
- /* Recurse for each following group. */
- TAILQ_FOREACH(follow_group, &group->follow_groups, link) {
- /* Following sections have to follow this one,
- * so add length to start.
- */
- yasm_intnum_set(start, group->bsd->ivstart);
- yasm_intnum_calc(start, YASM_EXPR_ADD, group->bsd->length);
-
- group_assign_vstart_recurse(follow_group, start, errwarns);
- }
-}
-
-static /*@null@*/ const yasm_intnum *
-get_ssym_value(yasm_symrec *sym)
-{
- bin_symrec_data *bsymd = yasm_symrec_get_data(sym, &bin_symrec_data_cb);
- bin_section_data *bsd;
-
- if (!bsymd)
- return NULL;
-
- bsd = yasm_section_get_data(bsymd->section, &bin_section_data_cb);
- assert(bsd != NULL);
-
- switch (bsymd->which) {
- case SSYM_START: return bsd->istart;
- case SSYM_VSTART: return bsd->ivstart;
- case SSYM_LENGTH: return bsd->length;
- }
- return NULL;
-}
-
-static /*@only@*/ yasm_expr *
-bin_objfmt_expr_xform(/*@returned@*/ /*@only@*/ yasm_expr *e,
- /*@unused@*/ /*@null@*/ void *d)
-{
- int i;
- for (i=0; i<e->numterms; i++) {
- /*@dependent@*/ yasm_section *sect;
- /*@dependent@*/ /*@null@*/ yasm_bytecode *precbc;
- /*@null@*/ yasm_intnum *dist;
- /*@null@*/ const yasm_intnum *ssymval;
-
- /* Transform symrecs or precbcs that reference sections into
- * vstart + intnum(dist).
- */
- if (((e->terms[i].type == YASM_EXPR_SYM &&
- yasm_symrec_get_label(e->terms[i].data.sym, &precbc)) ||
- (e->terms[i].type == YASM_EXPR_PRECBC &&
- (precbc = e->terms[i].data.precbc))) &&
- (sect = yasm_bc_get_section(precbc)) &&
- (dist = yasm_calc_bc_dist(yasm_section_bcs_first(sect), precbc))) {
- bin_section_data *bsd;
- bsd = yasm_section_get_data(sect, &bin_section_data_cb);
- assert(bsd != NULL);
- yasm_intnum_calc(dist, YASM_EXPR_ADD, bsd->ivstart);
- e->terms[i].type = YASM_EXPR_INT;
- e->terms[i].data.intn = dist;
- }
-
- /* Transform our special symrecs into the appropriate value */
- if (e->terms[i].type == YASM_EXPR_SYM &&
- (ssymval = get_ssym_value(e->terms[i].data.sym))) {
- e->terms[i].type = YASM_EXPR_INT;
- e->terms[i].data.intn = yasm_intnum_copy(ssymval);
- }
- }
-
- return e;
-}
-
-typedef struct map_output_info {
- /* address width */
- int bytes;
-
- /* intnum output static data areas */
- unsigned char *buf;
- yasm_intnum *intn;
-
- /* symrec output information */
- unsigned long count;
- yasm_section *section; /* NULL for EQUs */
-
- yasm_object *object; /* object */
- FILE *f; /* map output file */
-} map_output_info;
-
-static int
-map_prescan_bytes(yasm_section *sect, void *d)
-{
- bin_section_data *bsd = yasm_section_get_data(sect, &bin_section_data_cb);
- map_output_info *info = (map_output_info *)d;
-
- assert(bsd != NULL);
- assert(info != NULL);
-
- while (!yasm_intnum_check_size(bsd->length, info->bytes * 8, 0, 0))
- info->bytes *= 2;
- while (!yasm_intnum_check_size(bsd->istart, info->bytes * 8, 0, 0))
- info->bytes *= 2;
- while (!yasm_intnum_check_size(bsd->ivstart, info->bytes * 8, 0, 0))
- info->bytes *= 2;
-
- return 0;
-}
-
-static void
-map_print_intnum(const yasm_intnum *intn, map_output_info *info)
-{
- size_t i;
- yasm_intnum_get_sized(intn, info->buf, info->bytes, info->bytes*8, 0, 0,
- 0);
- for (i=info->bytes; i != 0; i--)
- fprintf(info->f, "%02X", info->buf[i-1]);
-}
-
-static void
-map_sections_summary(bin_groups *groups, map_output_info *info)
-{
- bin_group *group;
- TAILQ_FOREACH(group, groups, link) {
- bin_section_data *bsd = group->bsd;
-
- assert(bsd != NULL);
- assert(info != NULL);
-
- map_print_intnum(bsd->ivstart, info);
- fprintf(info->f, " ");
-
- yasm_intnum_set(info->intn, bsd->ivstart);
- yasm_intnum_calc(info->intn, YASM_EXPR_ADD, bsd->length);
- map_print_intnum(info->intn, info);
- fprintf(info->f, " ");
-
- map_print_intnum(bsd->istart, info);
- fprintf(info->f, " ");
-
- yasm_intnum_set(info->intn, bsd->istart);
- yasm_intnum_calc(info->intn, YASM_EXPR_ADD, bsd->length);
- map_print_intnum(info->intn, info);
- fprintf(info->f, " ");
-
- map_print_intnum(bsd->length, info);
- fprintf(info->f, " ");
-
- fprintf(info->f, "%-*s", 10, bsd->bss ? "nobits" : "progbits");
- fprintf(info->f, "%s\n", yasm_section_get_name(group->section));
-
- /* Recurse to loop through follow groups */
- map_sections_summary(&group->follow_groups, info);
- }
-}
-
-static void
-map_sections_detail(bin_groups *groups, map_output_info *info)
-{
- bin_group *group;
- TAILQ_FOREACH(group, groups, link) {
- bin_section_data *bsd = group->bsd;
- size_t i;
- const char *s;
-
- s = yasm_section_get_name(group->section);
- fprintf(info->f, "---- Section %s ", s);
- for (i=0; i<(65-strlen(s)); i++)
- fputc('-', info->f);
-
- fprintf(info->f, "\n\nclass: %s",
- bsd->bss ? "nobits" : "progbits");
- fprintf(info->f, "\nlength: ");
- map_print_intnum(bsd->length, info);
- fprintf(info->f, "\nstart: ");
- map_print_intnum(bsd->istart, info);
- fprintf(info->f, "\nalign: ");
- map_print_intnum(bsd->align, info);
- fprintf(info->f, "\nfollows: %s",
- bsd->follows ? bsd->follows : "not defined");
- fprintf(info->f, "\nvstart: ");
- map_print_intnum(bsd->ivstart, info);
- fprintf(info->f, "\nvalign: ");
- map_print_intnum(bsd->valign, info);
- fprintf(info->f, "\nvfollows: %s\n\n",
- bsd->vfollows ? bsd->vfollows : "not defined");
-
- /* Recurse to loop through follow groups */
- map_sections_detail(&group->follow_groups, info);
- }
-}
-
-static int
-map_symrec_count(yasm_symrec *sym, void *d)
-{
- map_output_info *info = (map_output_info *)d;
- /*@dependent@*/ yasm_bytecode *precbc;
-
- assert(info != NULL);
-
- /* TODO: autodetect wider size */
- if (!info->section && yasm_symrec_get_equ(sym)) {
- info->count++;
- } else if (yasm_symrec_get_label(sym, &precbc) &&
- yasm_bc_get_section(precbc) == info->section) {
- info->count++;
- }
- return 0;
-}
-
-static int
-map_symrec_output(yasm_symrec *sym, void *d)
-{
- map_output_info *info = (map_output_info *)d;
- const yasm_expr *equ;
- /*@dependent@*/ yasm_bytecode *precbc;
- /*@only@*/ char *name = yasm_symrec_get_global_name(sym, info->object);
-
- assert(info != NULL);
-
- if (!info->section && (equ = yasm_symrec_get_equ(sym))) {
- yasm_expr *realequ = yasm_expr_copy(equ);
- realequ = yasm_expr__level_tree
- (realequ, 1, 1, 1, 0, bin_objfmt_expr_xform, NULL);
- yasm_intnum_set(info->intn, yasm_expr_get_intnum(&realequ, 0));
- yasm_expr_destroy(realequ);
- map_print_intnum(info->intn, info);
- fprintf(info->f, " %s\n", name);
- } else if (yasm_symrec_get_label(sym, &precbc) &&
- yasm_bc_get_section(precbc) == info->section) {
- bin_section_data *bsd =
- yasm_section_get_data(info->section, &bin_section_data_cb);
-
- /* Real address */
- yasm_intnum_set_uint(info->intn, yasm_bc_next_offset(precbc));
- yasm_intnum_calc(info->intn, YASM_EXPR_ADD, bsd->istart);
- map_print_intnum(info->intn, info);
- fprintf(info->f, " ");
-
- /* Virtual address */
- yasm_intnum_set_uint(info->intn, yasm_bc_next_offset(precbc));
- yasm_intnum_calc(info->intn, YASM_EXPR_ADD, bsd->ivstart);
- map_print_intnum(info->intn, info);
-
- /* Name */
- fprintf(info->f, " %s\n", name);
- }
- yasm_xfree(name);
- return 0;
-}
-
-static void
-map_sections_symbols(bin_groups *groups, map_output_info *info)
-{
- bin_group *group;
- TAILQ_FOREACH(group, groups, link) {
- info->count = 0;
- info->section = group->section;
- yasm_symtab_traverse(info->object->symtab, info, map_symrec_count);
-
- if (info->count > 0) {
- const char *s = yasm_section_get_name(group->section);
- size_t i;
- fprintf(info->f, "---- Section %s ", s);
- for (i=0; i<(65-strlen(s)); i++)
- fputc('-', info->f);
- fprintf(info->f, "\n\n%-*s%-*s%s\n",
- info->bytes*2+2, "Real",
- info->bytes*2+2, "Virtual",
- "Name");
- yasm_symtab_traverse(info->object->symtab, info,
- map_symrec_output);
- fprintf(info->f, "\n\n");
- }
-
- /* Recurse to loop through follow groups */
- map_sections_symbols(&group->follow_groups, info);
- }
-}
-
-static void
-output_map(bin_objfmt_output_info *info)
-{
- yasm_objfmt_bin *objfmt_bin = (yasm_objfmt_bin *)info->object->objfmt;
- FILE *f;
- int i;
- map_output_info mapinfo;
-
- if (objfmt_bin->map_flags == NO_MAP)
- return;
-
- if (objfmt_bin->map_flags == MAP_NONE)
- objfmt_bin->map_flags = MAP_BRIEF; /* default to brief */
-
- if (!objfmt_bin->map_filename)
- f = stdout; /* default to stdout */
- else {
- f = fopen(objfmt_bin->map_filename, "wt");
- if (!f) {
- yasm_warn_set(YASM_WARN_GENERAL,
- N_("unable to open map file `%s'"),
- objfmt_bin->map_filename);
- yasm_errwarn_propagate(info->errwarns, 0);
- return;
- }
- }
-
- mapinfo.object = info->object;
- mapinfo.f = f;
-
- /* Temporary intnum */
- mapinfo.intn = info->tmp_intn;
-
- /* Prescan all values to figure out what width we should make the output
- * fields. Start with a minimum of 4.
- */
- mapinfo.bytes = 4;
- while (!yasm_intnum_check_size(info->origin, mapinfo.bytes * 8, 0, 0))
- mapinfo.bytes *= 2;
- yasm_object_sections_traverse(info->object, &mapinfo, map_prescan_bytes);
- mapinfo.buf = yasm_xmalloc(mapinfo.bytes);
-
- fprintf(f, "\n- YASM Map file ");
- for (i=0; i<63; i++)
- fputc('-', f);
- fprintf(f, "\n\nSource file: %s\n", info->object->src_filename);
- fprintf(f, "Output file: %s\n\n", info->object->obj_filename);
-
- fprintf(f, "-- Program origin ");
- for (i=0; i<61; i++)
- fputc('-', f);
- fprintf(f, "\n\n");
- map_print_intnum(info->origin, &mapinfo);
- fprintf(f, "\n\n");
-
- if (objfmt_bin->map_flags & MAP_BRIEF) {
- fprintf(f, "-- Sections (summary) ");
- for (i=0; i<57; i++)
- fputc('-', f);
- fprintf(f, "\n\n%-*s%-*s%-*s%-*s%-*s%-*s%s\n",
- mapinfo.bytes*2+2, "Vstart",
- mapinfo.bytes*2+2, "Vstop",
- mapinfo.bytes*2+2, "Start",
- mapinfo.bytes*2+2, "Stop",
- mapinfo.bytes*2+2, "Length",
- 10, "Class", "Name");
-
- map_sections_summary(&info->lma_groups, &mapinfo);
- fprintf(f, "\n");
- }
-
- if (objfmt_bin->map_flags & MAP_SECTIONS) {
- fprintf(f, "-- Sections (detailed) ");
- for (i=0; i<56; i++)
- fputc('-', f);
- fprintf(f, "\n\n");
- map_sections_detail(&info->lma_groups, &mapinfo);
- }
-
- if (objfmt_bin->map_flags & MAP_SYMBOLS) {
- fprintf(f, "-- Symbols ");
- for (i=0; i<68; i++)
- fputc('-', f);
- fprintf(f, "\n\n");
-
- /* We do two passes for EQU and each section; the first pass
- * determines the byte width to use for the value and whether any
- * symbols are present, the second pass actually outputs the text.
- */
-
- /* EQUs */
- mapinfo.count = 0;
- mapinfo.section = NULL;
- yasm_symtab_traverse(info->object->symtab, &mapinfo, map_symrec_count);
-
- if (mapinfo.count > 0) {
- fprintf(f, "---- No Section ");
- for (i=0; i<63; i++)
- fputc('-', f);
- fprintf(f, "\n\n%-*s%s\n", mapinfo.bytes*2+2, "Value", "Name");
- yasm_symtab_traverse(info->object->symtab, &mapinfo,
- map_symrec_output);
- fprintf(f, "\n\n");
- }
-
- /* Other sections */
- map_sections_symbols(&info->lma_groups, &mapinfo);
- }
-
- if (f != stdout)
- fclose(f);
-
- yasm_xfree(mapinfo.buf);
-}
-
-/* Check for LMA overlap using a simple N^2 algorithm. */
-static int
-check_lma_overlap(yasm_section *sect, /*@null@*/ void *d)
-{
- bin_section_data *bsd, *bsd2;
- yasm_section *other = (yasm_section *)d;
- yasm_intnum *overlap;
-
- if (!d)
- return yasm_object_sections_traverse(yasm_section_get_object(sect),
- sect, check_lma_overlap);
- if (sect == other)
- return 0;
-
- bsd = yasm_section_get_data(sect, &bin_section_data_cb);
- bsd2 = yasm_section_get_data(other, &bin_section_data_cb);
-
- if (yasm_intnum_is_zero(bsd->length) ||
- yasm_intnum_is_zero(bsd2->length))
- return 0;
-
- if (yasm_intnum_compare(bsd->istart, bsd2->istart) <= 0) {
- overlap = yasm_intnum_copy(bsd->istart);
- yasm_intnum_calc(overlap, YASM_EXPR_ADD, bsd->length);
- yasm_intnum_calc(overlap, YASM_EXPR_SUB, bsd2->istart);
- } else {
- overlap = yasm_intnum_copy(bsd2->istart);
- yasm_intnum_calc(overlap, YASM_EXPR_ADD, bsd2->length);
- yasm_intnum_calc(overlap, YASM_EXPR_SUB, bsd->istart);
- }
-
- if (yasm_intnum_sign(overlap) > 0) {
- yasm_error_set(YASM_ERROR_GENERAL,
- N_("sections `%s' and `%s' overlap by %lu bytes"),
- yasm_section_get_name(sect),
- yasm_section_get_name(other),
- yasm_intnum_get_uint(overlap));
- yasm_intnum_destroy(overlap);
- return -1;
- }
-
- yasm_intnum_destroy(overlap);
- return 0;
-}
-
-static int
-bin_objfmt_output_value(yasm_value *value, unsigned char *buf,
- unsigned int destsize,
- /*@unused@*/ unsigned long offset, yasm_bytecode *bc,
- int warn, /*@null@*/ void *d)
-{
- /*@null@*/ bin_objfmt_output_info *info = (bin_objfmt_output_info *)d;
- /*@dependent@*/ /*@null@*/ yasm_bytecode *precbc;
- /*@dependent@*/ yasm_section *sect;
-
- assert(info != NULL);
-
- /* Binary objects we need to resolve against object, not against section. */
- if (value->rel) {
- unsigned int rshift = (unsigned int)value->rshift;
- yasm_expr *syme;
- /*@null@*/ const yasm_intnum *ssymval;
-
- if (yasm_symrec_is_abs(value->rel)) {
- syme = yasm_expr_create_ident(yasm_expr_int(
- yasm_intnum_create_uint(0)), bc->line);
- } else if (yasm_symrec_get_label(value->rel, &precbc)
- && (sect = yasm_bc_get_section(precbc))) {
- syme = yasm_expr_create_ident(yasm_expr_sym(value->rel), bc->line);
- } else if ((ssymval = get_ssym_value(value->rel))) {
- syme = yasm_expr_create_ident(yasm_expr_int(
- yasm_intnum_copy(ssymval)), bc->line);
- } else
- goto done;
-
- /* Handle PC-relative */
- if (value->curpos_rel) {
- yasm_expr *sube;
- sube = yasm_expr_create(YASM_EXPR_SUB, yasm_expr_precbc(bc),
- yasm_expr_int(yasm_intnum_create_uint(bc->len*bc->mult_int)),
- bc->line);
- syme = yasm_expr_create(YASM_EXPR_SUB, yasm_expr_expr(syme),
- yasm_expr_expr(sube), bc->line);
- value->curpos_rel = 0;
- value->ip_rel = 0;
- }
-
- if (value->rshift > 0)
- syme = yasm_expr_create(YASM_EXPR_SHR, yasm_expr_expr(syme),
- yasm_expr_int(yasm_intnum_create_uint(rshift)), bc->line);
-
- /* Add into absolute portion */
- if (!value->abs)
- value->abs = syme;
- else
- value->abs =
- yasm_expr_create(YASM_EXPR_ADD, yasm_expr_expr(value->abs),
- yasm_expr_expr(syme), bc->line);
- value->rel = NULL;
- value->rshift = 0;
- }
-done:
- /* Simplify absolute portion of value, transforming symrecs */
- if (value->abs)
- value->abs = yasm_expr__level_tree
- (value->abs, 1, 1, 1, 0, bin_objfmt_expr_xform, NULL);
-
- /* Output */
- switch (yasm_value_output_basic(value, buf, destsize, bc, warn,
- info->object->arch)) {
- case -1:
- return 1;
- case 0:
- break;
- default:
- return 0;
- }
-
- /* Couldn't output, assume it contains an external reference. */
- yasm_error_set(YASM_ERROR_GENERAL,
- N_("binary object format does not support external references"));
- return 1;
-}
-
-static int
-bin_objfmt_output_bytecode(yasm_bytecode *bc, /*@null@*/ void *d)
-{
- /*@null@*/ bin_objfmt_output_info *info = (bin_objfmt_output_info *)d;
- /*@null@*/ /*@only@*/ unsigned char *bigbuf;
- unsigned long size = REGULAR_OUTBUF_SIZE;
- int gap;
-
- assert(info != NULL);
-
- bigbuf = yasm_bc_tobytes(bc, info->buf, &size, &gap, info,
- bin_objfmt_output_value, NULL);
-
- /* Don't bother doing anything else if size ended up being 0. */
- if (size == 0) {
- if (bigbuf)
- yasm_xfree(bigbuf);
- return 0;
- }
-
- /* Warn that gaps are converted to 0 and write out the 0's. */
- if (gap) {
- unsigned long left;
- yasm_warn_set(YASM_WARN_UNINIT_CONTENTS,
- N_("uninitialized space declared in code/data section: zeroing"));
- /* Write out in chunks */
- memset(info->buf, 0, REGULAR_OUTBUF_SIZE);
- left = size;
- while (left > REGULAR_OUTBUF_SIZE) {
- fwrite(info->buf, REGULAR_OUTBUF_SIZE, 1, info->f);
- left -= REGULAR_OUTBUF_SIZE;
- }
- fwrite(info->buf, left, 1, info->f);
- } else {
- /* Output buf (or bigbuf if non-NULL) to file */
- fwrite(bigbuf ? bigbuf : info->buf, (size_t)size, 1, info->f);
- }
-
- /* If bigbuf was allocated, free it */
- if (bigbuf)
- yasm_xfree(bigbuf);
-
- return 0;
-}
-
-/* Check to ensure bytecode is res* (for BSS sections) */
-static int
-bin_objfmt_no_output_bytecode(yasm_bytecode *bc, /*@null@*/ void *d)
-{
- /*@null@*/ bin_objfmt_output_info *info = (bin_objfmt_output_info *)d;
- /*@null@*/ /*@only@*/ unsigned char *bigbuf;
- unsigned long size = REGULAR_OUTBUF_SIZE;
- int gap;
-
- assert(info != NULL);
-
- bigbuf = yasm_bc_tobytes(bc, info->buf, &size, &gap, info,
- bin_objfmt_output_value, NULL);
-
- /* If bigbuf was allocated, free it */
- if (bigbuf)
- yasm_xfree(bigbuf);
-
- /* Don't bother doing anything else if size ended up being 0. */
- if (size == 0)
- return 0;
-
- /* Warn if not a gap. */
- if (!gap) {
- yasm_warn_set(YASM_WARN_GENERAL,
- N_("initialized space declared in nobits section: ignoring"));
- }
-
- return 0;
-}
-
-static int
-bin_objfmt_output_section(yasm_section *sect, /*@null@*/ void *d)
-{
- bin_section_data *bsd = yasm_section_get_data(sect, &bin_section_data_cb);
- /*@null@*/ bin_objfmt_output_info *info = (bin_objfmt_output_info *)d;
-
- assert(bsd != NULL);
- assert(info != NULL);
-
- if (bsd->bss) {
- yasm_section_bcs_traverse(sect, info->errwarns,
- info, bin_objfmt_no_output_bytecode);
- } else {
- yasm_intnum_set(info->tmp_intn, bsd->istart);
- yasm_intnum_calc(info->tmp_intn, YASM_EXPR_SUB, info->origin);
- if (yasm_intnum_sign(info->tmp_intn) < 0) {
- yasm_error_set(YASM_ERROR_VALUE,
- N_("section `%s' starts before origin (ORG)"),
- yasm_section_get_name(sect));
- yasm_errwarn_propagate(info->errwarns, 0);
- return 0;
- }
- if (!yasm_intnum_check_size(info->tmp_intn, sizeof(long)*8, 0, 1)) {
- yasm_error_set(YASM_ERROR_VALUE,
- N_("section `%s' start value too large"),
- yasm_section_get_name(sect));
- yasm_errwarn_propagate(info->errwarns, 0);
- return 0;
- }
- if (fseek(info->f, yasm_intnum_get_int(info->tmp_intn) + info->start,
- SEEK_SET) < 0)
- yasm__fatal(N_("could not seek on output file"));
- yasm_section_bcs_traverse(sect, info->errwarns,
- info, bin_objfmt_output_bytecode);
- }
-
- return 0;
-}
-
-static void
-bin_objfmt_cleanup(bin_objfmt_output_info *info)
-{
- bin_group *group, *group_temp;
-
- yasm_xfree(info->buf);
- yasm_intnum_destroy(info->origin);
- yasm_intnum_destroy(info->tmp_intn);
-
- TAILQ_FOREACH_SAFE(group, &info->lma_groups, link, group_temp)
- bin_group_destroy(group);
-
- TAILQ_FOREACH_SAFE(group, &info->vma_groups, link, group_temp)
- bin_group_destroy(group);
-}
-
-static void
-bin_objfmt_output(yasm_object *object, FILE *f, /*@unused@*/ int all_syms,
- yasm_errwarns *errwarns)
-{
- yasm_objfmt_bin *objfmt_bin = (yasm_objfmt_bin *)object->objfmt;
- bin_objfmt_output_info info;
- bin_group *group, *lma_group, *vma_group, *group_temp;
- yasm_intnum *start, *last, *vdelta;
- bin_groups unsorted_groups, bss_groups;
-
- info.start = ftell(f);
-
- /* Set ORG to 0 unless otherwise specified */
- if (objfmt_bin->org) {
- info.origin = yasm_expr_get_intnum(&objfmt_bin->org, 0);
- if (!info.origin) {
- yasm_error_set(YASM_ERROR_TOO_COMPLEX,
- N_("ORG expression is too complex"));
- yasm_errwarn_propagate(errwarns, objfmt_bin->org->line);
- return;
- }
- if (yasm_intnum_sign(info.origin) < 0) {
- yasm_error_set(YASM_ERROR_VALUE, N_("ORG expression is negative"));
- yasm_errwarn_propagate(errwarns, objfmt_bin->org->line);
- return;
- }
- info.origin = yasm_intnum_copy(info.origin);
- } else
- info.origin = yasm_intnum_create_uint(0);
-
- info.object = object;
- info.errwarns = errwarns;
- info.f = f;
- info.buf = yasm_xmalloc(REGULAR_OUTBUF_SIZE);
- info.tmp_intn = yasm_intnum_create_uint(0);
- TAILQ_INIT(&info.lma_groups);
- TAILQ_INIT(&info.vma_groups);
-
- /* Check symbol table */
- yasm_symtab_traverse(object->symtab, &info, bin_objfmt_check_sym);
-
- /* Create section groups */
- if (yasm_object_sections_traverse(object, &info, bin_lma_create_group)) {
- bin_objfmt_cleanup(&info);
- return; /* error detected */
- }
-
- /* Determine section order according to LMA.
- * Sections can be ordered either by (priority):
- * - follows
- * - start
- * - progbits/nobits setting
- * - order in the input file
- */
-
- /* Look at each group with follows specified, and find the section
- * that group is supposed to follow.
- */
- TAILQ_FOREACH_SAFE(lma_group, &info.lma_groups, link, group_temp) {
- if (lma_group->bsd->follows) {
- bin_group *found;
- /* Need to find group containing section this section follows. */
- found =
- find_group_by_name(&info.lma_groups, lma_group->bsd->follows);
- if (!found) {
- yasm_error_set(YASM_ERROR_VALUE,
- N_("section `%s' follows an invalid or unknown section `%s'"),
- yasm_section_get_name(lma_group->section),
- lma_group->bsd->follows);
- yasm_errwarn_propagate(errwarns, 0);
- bin_objfmt_cleanup(&info);
- return;
- }
-
- /* Check for loops */
- if (lma_group->section == found->section ||
- find_group_by_section(&lma_group->follow_groups,
- found->section)) {
- yasm_error_set(YASM_ERROR_VALUE,
- N_("follows loop between section `%s' and section `%s'"),
- yasm_section_get_name(lma_group->section),
- yasm_section_get_name(found->section));
- yasm_errwarn_propagate(errwarns, 0);
- bin_objfmt_cleanup(&info);
- return;
- }
-
- /* Remove this section from main lma groups list */
- TAILQ_REMOVE(&info.lma_groups, lma_group, link);
- /* Add it after the section it's supposed to follow. */
- TAILQ_INSERT_TAIL(&found->follow_groups, lma_group, link);
- }
- }
-
- /* Sort the top-level groups according to their start address.
- * Use Shell sort for ease of implementation.
- * If no start address is specified for a section, don't change the order,
- * and move BSS sections to a separate list so they can be moved to the
- * end of the lma list after all other sections are sorted.
- */
- unsorted_groups = info.lma_groups; /* structure copy */
- TAILQ_INIT(&info.lma_groups);
- TAILQ_INIT(&bss_groups);
- TAILQ_FOREACH_SAFE(lma_group, &unsorted_groups, link, group_temp) {
- bin_group *before;
-
- if (!lma_group->bsd->istart) {
- if (lma_group->bsd->bss)
- TAILQ_INSERT_TAIL(&bss_groups, lma_group, link);
- else
- TAILQ_INSERT_TAIL(&info.lma_groups, lma_group, link);
- continue;
- }
-
- before = NULL;
- TAILQ_FOREACH(group, &info.lma_groups, link) {
- if (!group->bsd->istart)
- continue;
- if (yasm_intnum_compare(group->bsd->istart,
- lma_group->bsd->istart) > 0) {
- before = group;
- break;
- }
- }
- if (before)
- TAILQ_INSERT_BEFORE(before, lma_group, link);
- else
- TAILQ_INSERT_TAIL(&info.lma_groups, lma_group, link);
- }
-
- /* Move the pure-BSS sections to the end of the LMA list. */
- TAILQ_FOREACH_SAFE(group, &bss_groups, link, group_temp)
- TAILQ_INSERT_TAIL(&info.lma_groups, group, link);
- TAILQ_INIT(&bss_groups); /* For sanity */
-
- /* Assign a LMA start address to every section.
- * Also assign VMA=LMA unless otherwise specified.
- *
- * We need to assign VMA=LMA here (while walking the tree) for the case:
- * sect1 start=0 (size=0x11)
- * sect2 follows=sect1 valign=16 (size=0x104)
- * sect3 follows=sect2 valign=16
- * Where the valign of sect2 will result in a sect3 vaddr higher than a
- * naive segment-by-segment interpretation (where sect3 and sect2 would
- * have a VMA overlap).
- *
- * Algorithm for VMA=LMA setting:
- * Start with delta=0.
- * If there's no virtual attributes, we simply set VMA = LMA+delta.
- * If there's only valign specified, we set VMA = aligned LMA, and add
- * any new alignment difference to delta.
- *
- * We could do the LMA start and VMA=LMA steps in two separate steps,
- * but it's easier to just recurse once.
- */
- start = yasm_intnum_copy(info.origin);
- last = yasm_intnum_copy(info.origin);
- vdelta = yasm_intnum_create_uint(0);
- TAILQ_FOREACH(lma_group, &info.lma_groups, link) {
- if (lma_group->bsd->istart)
- yasm_intnum_set(start, lma_group->bsd->istart);
- group_assign_start_recurse(lma_group, start, last, vdelta,
- info.tmp_intn, errwarns);
- yasm_intnum_set(start, last);
- }
- yasm_intnum_destroy(last);
- yasm_intnum_destroy(vdelta);
-
- /*
- * Determine section order according to VMA
- */
-
- /* Create section groups */
- if (yasm_object_sections_traverse(object, &info, bin_vma_create_group)) {
- yasm_intnum_destroy(start);
- bin_objfmt_cleanup(&info);
- return; /* error detected */
- }
-
- /* Look at each group with vfollows specified, and find the section
- * that group is supposed to follow.
- */
- TAILQ_FOREACH_SAFE(vma_group, &info.vma_groups, link, group_temp) {
- if (vma_group->bsd->vfollows) {
- bin_group *found;
- /* Need to find group containing section this section follows. */
- found = find_group_by_name(&info.vma_groups,
- vma_group->bsd->vfollows);
- if (!found) {
- yasm_error_set(YASM_ERROR_VALUE,
- N_("section `%s' vfollows an invalid or unknown section `%s'"),
- yasm_section_get_name(vma_group->section),
- vma_group->bsd->vfollows);
- yasm_errwarn_propagate(errwarns, 0);
- yasm_intnum_destroy(start);
- bin_objfmt_cleanup(&info);
- return;
- }
-
- /* Check for loops */
- if (vma_group->section == found->section ||
- find_group_by_section(&vma_group->follow_groups,
- found->section)) {
- yasm_error_set(YASM_ERROR_VALUE,
- N_("vfollows loop between section `%s' and section `%s'"),
- yasm_section_get_name(vma_group->section),
- yasm_section_get_name(found->section));
- yasm_errwarn_propagate(errwarns, 0);
- bin_objfmt_cleanup(&info);
- return;
- }
-
- /* Remove this section from main lma groups list */
- TAILQ_REMOVE(&info.vma_groups, vma_group, link);
- /* Add it after the section it's supposed to follow. */
- TAILQ_INSERT_TAIL(&found->follow_groups, vma_group, link);
- }
- }
-
- /* Due to the combination of steps above, we now know that all top-level
- * groups have integer ivstart:
- * Vstart Vfollows Valign Handled by
- * No No No group_assign_start_recurse()
- * No No Yes group_assign_start_recurse()
- * No Yes - vfollows loop (above)
- * Yes - - bin_lma_create_group()
- */
- TAILQ_FOREACH(vma_group, &info.vma_groups, link) {
- yasm_intnum_set(start, vma_group->bsd->ivstart);
- group_assign_vstart_recurse(vma_group, start, errwarns);
- }
-
- /* Output map file */
- output_map(&info);
-
- /* Ensure we don't have overlapping progbits LMAs.
- * Use a dumb O(N^2) algorithm as the number of sections is essentially
- * always low.
- */
- if (yasm_object_sections_traverse(object, NULL, check_lma_overlap)) {
- yasm_errwarn_propagate(errwarns, 0);
- yasm_intnum_destroy(start);
- bin_objfmt_cleanup(&info);
- return;
- }
-
- /* Output sections */
- yasm_object_sections_traverse(object, &info, bin_objfmt_output_section);
-
- /* Clean up */
- yasm_intnum_destroy(start);
- bin_objfmt_cleanup(&info);
-}
-
-static void
-bin_objfmt_destroy(yasm_objfmt *objfmt)
-{
- yasm_objfmt_bin *objfmt_bin = (yasm_objfmt_bin *)objfmt;
- if (objfmt_bin->map_filename)
- yasm_xfree(objfmt_bin->map_filename);
- yasm_expr_destroy(objfmt_bin->org);
- yasm_xfree(objfmt);
-}
-
-static void
-define_section_symbol(yasm_symtab *symtab, yasm_section *sect,
- const char *sectname, const char *suffix,
- enum bin_ssym which, unsigned long line)
-{
- yasm_symrec *sym;
- bin_symrec_data *bsymd = yasm_xmalloc(sizeof(bin_symrec_data));
- char *symname = yasm_xmalloc(8+strlen(sectname)+strlen(suffix)+1);
-
- strcpy(symname, "section.");
- strcat(symname, sectname);
- strcat(symname, suffix);
-
- bsymd->section = sect;
- bsymd->which = which;
-
- sym = yasm_symtab_declare(symtab, symname, YASM_SYM_EXTERN, line);
- yasm_xfree(symname);
- yasm_symrec_add_data(sym, &bin_symrec_data_cb, bsymd);
-}
-
-static void
-bin_objfmt_init_new_section(yasm_section *sect, unsigned long line)
-{
- yasm_object *object = yasm_section_get_object(sect);
- const char *sectname = yasm_section_get_name(sect);
- /*yasm_objfmt_bin *objfmt_bin = (yasm_objfmt_bin *)object->objfmt;*/
- bin_section_data *data;
-
- data = yasm_xmalloc(sizeof(bin_section_data));
- data->bss = 0;
- data->align = NULL;
- data->valign = NULL;
- data->start = NULL;
- data->vstart = NULL;
- data->follows = NULL;
- data->vfollows = NULL;
- data->istart = NULL;
- data->ivstart = NULL;
- data->length = NULL;
- yasm_section_add_data(sect, &bin_section_data_cb, data);
-
- define_section_symbol(object->symtab, sect, sectname, ".start",
- SSYM_START, line);
- define_section_symbol(object->symtab, sect, sectname, ".vstart",
- SSYM_VSTART, line);
- define_section_symbol(object->symtab, sect, sectname, ".length",
- SSYM_LENGTH, line);
-}
-
-static yasm_section *
-bin_objfmt_add_default_section(yasm_object *object)
-{
- yasm_section *retval;
- int isnew;
-
- retval = yasm_object_get_general(object, ".text", 0, 1, 0, &isnew, 0);
- if (isnew)
- yasm_section_set_default(retval, 1);
- return retval;
-}
-
-/* GAS-style flags */
-static int
-bin_helper_gasflags(void *obj, yasm_valparam *vp, unsigned long line, void *d,
- /*@unused@*/ uintptr_t arg)
-{
- /* TODO */
- return 0;
-}
-
-static /*@observer@*/ /*@null@*/ yasm_section *
-bin_objfmt_section_switch(yasm_object *object, yasm_valparamhead *valparams,
- /*@unused@*/ /*@null@*/
- yasm_valparamhead *objext_valparams,
- unsigned long line)
-{
- yasm_valparam *vp;
- yasm_section *retval;
- int isnew;
- int flags_override = 0;
- const char *sectname;
- bin_section_data *bsd = NULL;
-
- struct bin_section_switch_data {
- /*@only@*/ /*@null@*/ char *follows;
- /*@only@*/ /*@null@*/ char *vfollows;
- /*@only@*/ /*@null@*/ yasm_expr *start;
- /*@only@*/ /*@null@*/ yasm_expr *vstart;
- /*@only@*/ /*@null@*/ yasm_intnum *align;
- /*@only@*/ /*@null@*/ yasm_intnum *valign;
- unsigned long bss;
- unsigned long code;
- } data;
-
- static const yasm_dir_help help[] = {
- { "follows", 1, yasm_dir_helper_string,
- offsetof(struct bin_section_switch_data, follows), 0 },
- { "vfollows", 1, yasm_dir_helper_string,
- offsetof(struct bin_section_switch_data, vfollows), 0 },
- { "start", 1, yasm_dir_helper_expr,
- offsetof(struct bin_section_switch_data, start), 0 },
- { "vstart", 1, yasm_dir_helper_expr,
- offsetof(struct bin_section_switch_data, vstart), 0 },
- { "align", 1, yasm_dir_helper_intn,
- offsetof(struct bin_section_switch_data, align), 0 },
- { "valign", 1, yasm_dir_helper_intn,
- offsetof(struct bin_section_switch_data, valign), 0 },
- { "nobits", 0, yasm_dir_helper_flag_set,
- offsetof(struct bin_section_switch_data, bss), 1 },
- { "progbits", 0, yasm_dir_helper_flag_set,
- offsetof(struct bin_section_switch_data, bss), 0 },
- { "code", 0, yasm_dir_helper_flag_set,
- offsetof(struct bin_section_switch_data, code), 1 },
- { "data", 0, yasm_dir_helper_flag_set,
- offsetof(struct bin_section_switch_data, code), 0 },
- { "execute", 0, yasm_dir_helper_flag_set,
- offsetof(struct bin_section_switch_data, code), 1 },
- { "noexecute", 0, yasm_dir_helper_flag_set,
- offsetof(struct bin_section_switch_data, code), 0 },
- { "gasflags", 1, bin_helper_gasflags, 0, 0 }
- };
-
- vp = yasm_vps_first(valparams);
- sectname = yasm_vp_string(vp);
- if (!sectname)
- return NULL;
- vp = yasm_vps_next(vp);
-
- retval = yasm_object_find_general(object, sectname);
- if (retval) {
- bsd = yasm_section_get_data(retval, &bin_section_data_cb);
- assert(bsd != NULL);
- data.follows = bsd->follows;
- data.vfollows = bsd->vfollows;
- data.start = bsd->start;
- data.vstart = bsd->vstart;
- data.align = NULL;
- data.valign = NULL;
- data.bss = bsd->bss;
- data.code = yasm_section_is_code(retval);
- } else {
- data.follows = NULL;
- data.vfollows = NULL;
- data.start = NULL;
- data.vstart = NULL;
- data.align = NULL;
- data.valign = NULL;
- data.bss = strcmp(sectname, ".bss") == 0;
- data.code = strcmp(sectname, ".text") == 0;
- }
-
- flags_override = yasm_dir_helper(object, vp, line, help, NELEMS(help),
- &data, yasm_dir_helper_valparam_warn);
- if (flags_override < 0)
- return NULL; /* error occurred */
-
- if (data.start && data.follows) {
- yasm_error_set(YASM_ERROR_GENERAL,
- N_("cannot combine `start' and `follows' section attributes"));
- return NULL;
- }
-
- if (data.vstart && data.vfollows) {
- yasm_error_set(YASM_ERROR_GENERAL,
- N_("cannot combine `vstart' and `vfollows' section attributes"));
- return NULL;
- }
-
- if (data.align) {
- unsigned long align = yasm_intnum_get_uint(data.align);
-
- /* Alignments must be a power of two. */
- if (!is_exp2(align)) {
- yasm_error_set(YASM_ERROR_VALUE,
- N_("argument to `%s' is not a power of two"),
- "align");
- return NULL;
- }
- } else
- data.align = bsd ? bsd->align : NULL;
-
- if (data.valign) {
- unsigned long valign = yasm_intnum_get_uint(data.valign);
-
- /* Alignments must be a power of two. */
- if (!is_exp2(valign)) {
- yasm_error_set(YASM_ERROR_VALUE,
- N_("argument to `%s' is not a power of two"),
- "valign");
- return NULL;
- }
- } else
- data.valign = bsd ? bsd->valign : NULL;
-
- retval = yasm_object_get_general(object, sectname, 0, (int)data.code,
- (int)data.bss, &isnew, line);
-
- bsd = yasm_section_get_data(retval, &bin_section_data_cb);
-
- if (isnew || yasm_section_is_default(retval)) {
- yasm_section_set_default(retval, 0);
- }
-
- /* Update section flags */
- bsd->bss = data.bss;
- bsd->align = data.align;
- bsd->valign = data.valign;
- bsd->start = data.start;
- bsd->vstart = data.vstart;
- bsd->follows = data.follows;
- bsd->vfollows = data.vfollows;
-
- return retval;
-}
-
-static /*@observer@*/ /*@null@*/ yasm_symrec *
-bin_objfmt_get_special_sym(yasm_object *object, const char *name,
- const char *parser)
-{
- return NULL;
-}
-
-static void
-bin_objfmt_dir_org(yasm_object *object,
- /*@null@*/ yasm_valparamhead *valparams,
- /*@unused@*/ /*@null@*/
- yasm_valparamhead *objext_valparams, unsigned long line)
-{
- yasm_objfmt_bin *objfmt_bin = (yasm_objfmt_bin *)object->objfmt;
- yasm_valparam *vp;
-
- /* We only allow a single ORG in a program. */
- if (objfmt_bin->org) {
- yasm_error_set(YASM_ERROR_GENERAL, N_("program origin redefined"));
- return;
- }
-
- /* ORG takes just a simple expression as param */
- vp = yasm_vps_first(valparams);
- objfmt_bin->org = yasm_vp_expr(vp, object->symtab, line);
- if (!objfmt_bin->org) {
- yasm_error_set(YASM_ERROR_SYNTAX,
- N_("argument to ORG must be expression"));
- return;
- }
-}
-
-struct bin_dir_map_data {
- unsigned long flags;
- /*@only@*/ /*@null@*/ char *filename;
-};
-
-static int
-dir_map_filename(void *obj, yasm_valparam *vp, unsigned long line, void *data)
-{
- struct bin_dir_map_data *mdata = (struct bin_dir_map_data *)data;
- const char *filename;
-
- if (mdata->filename) {
- yasm_warn_set(YASM_WARN_GENERAL, N_("map file already specified"));
- return 0;
- }
-
- filename = yasm_vp_string(vp);
- if (!filename) {
- yasm_error_set(YASM_ERROR_SYNTAX,
- N_("unexpected expression in [map]"));
- return -1;
- }
- mdata->filename = yasm__xstrdup(filename);
-
- return 1;
-}
-
-static void
-bin_objfmt_dir_map(yasm_object *object,
- /*@null@*/ yasm_valparamhead *valparams,
- /*@unused@*/ /*@null@*/
- yasm_valparamhead *objext_valparams, unsigned long line)
-{
- yasm_objfmt_bin *objfmt_bin = (yasm_objfmt_bin *)object->objfmt;
-
- struct bin_dir_map_data data;
-
- static const yasm_dir_help help[] = {
- { "all", 0, yasm_dir_helper_flag_or,
- offsetof(struct bin_dir_map_data, flags),
- MAP_BRIEF|MAP_SECTIONS|MAP_SYMBOLS },
- { "brief", 0, yasm_dir_helper_flag_or,
- offsetof(struct bin_dir_map_data, flags), MAP_BRIEF },
- { "sections", 0, yasm_dir_helper_flag_or,
- offsetof(struct bin_dir_map_data, flags), MAP_SECTIONS },
- { "segments", 0, yasm_dir_helper_flag_or,
- offsetof(struct bin_dir_map_data, flags), MAP_SECTIONS },
- { "symbols", 0, yasm_dir_helper_flag_or,
- offsetof(struct bin_dir_map_data, flags), MAP_SYMBOLS }
- };
-
- data.flags = objfmt_bin->map_flags | MAP_NONE;
- data.filename = objfmt_bin->map_filename;
-
- if (valparams && yasm_dir_helper(object, yasm_vps_first(valparams), line, help,
- NELEMS(help), &data, dir_map_filename) < 0)
- return; /* error occurred */
-
- objfmt_bin->map_flags = data.flags;
- objfmt_bin->map_filename = data.filename;
-}
-
-static void
-bin_section_data_destroy(void *data)
-{
- bin_section_data *bsd = (bin_section_data *)data;
- if (bsd->start)
- yasm_expr_destroy(bsd->start);
- if (bsd->vstart)
- yasm_expr_destroy(bsd->vstart);
- if (bsd->follows)
- yasm_xfree(bsd->follows);
- if (bsd->vfollows)
- yasm_xfree(bsd->vfollows);
- if (bsd->istart)
- yasm_intnum_destroy(bsd->istart);
- if (bsd->ivstart)
- yasm_intnum_destroy(bsd->ivstart);
- if (bsd->length)
- yasm_intnum_destroy(bsd->length);
- yasm_xfree(data);
-}
-
-static void
-bin_section_data_print(void *data, FILE *f, int indent_level)
-{
- bin_section_data *bsd = (bin_section_data *)data;
-
- fprintf(f, "%*sbss=%d\n", indent_level, "", bsd->bss);
-
- fprintf(f, "%*salign=", indent_level, "");
- if (bsd->align)
- yasm_intnum_print(bsd->align, f);
- else
- fprintf(f, "(nil)");
- fprintf(f, "\n%*svalign=", indent_level, "");
- if (bsd->valign)
- yasm_intnum_print(bsd->valign, f);
- else
- fprintf(f, "(nil)");
-
- fprintf(f, "\n%*sstart=", indent_level, "");
- yasm_expr_print(bsd->start, f);
- fprintf(f, "\n%*svstart=", indent_level, "");
- yasm_expr_print(bsd->vstart, f);
-
- fprintf(f, "\n%*sfollows=", indent_level, "");
- if (bsd->follows)
- fprintf(f, "\"%s\"", bsd->follows);
- else
- fprintf(f, "(nil)");
- fprintf(f, "\n%*svfollows=", indent_level, "");
- if (bsd->vfollows)
- fprintf(f, "\"%s\"", bsd->vfollows);
- else
- fprintf(f, "(nil)");
-
- fprintf(f, "\n%*sistart=", indent_level, "");
- if (bsd->istart)
- yasm_intnum_print(bsd->istart, f);
- else
- fprintf(f, "(nil)");
- fprintf(f, "\n%*sivstart=", indent_level, "");
- if (bsd->ivstart)
- yasm_intnum_print(bsd->ivstart, f);
- else
- fprintf(f, "(nil)");
-
- fprintf(f, "\n%*slength=", indent_level, "");
- if (bsd->length)
- yasm_intnum_print(bsd->length, f);
- else
- fprintf(f, "(nil)");
- fprintf(f, "\n");
-}
-
-static void
-bin_symrec_data_destroy(void *data)
-{
- yasm_xfree(data);
-}
-
-static void
-bin_symrec_data_print(void *data, FILE *f, int indent_level)
-{
- bin_symrec_data *bsymd = (bin_symrec_data *)data;
-
- fprintf(f, "%*ssection=\"%s\"\n", indent_level, "",
- yasm_section_get_name(bsymd->section));
- fprintf(f, "%*swhich=", indent_level, "");
- switch (bsymd->which) {
- case SSYM_START: fprintf(f, "START"); break;
- case SSYM_VSTART: fprintf(f, "VSTART"); break;
- case SSYM_LENGTH: fprintf(f, "LENGTH"); break;
- }
- fprintf(f, "\n");
-}
-
-
-/* Define valid debug formats to use with this object format */
-static const char *bin_objfmt_dbgfmt_keywords[] = {
- "null",
- NULL
-};
-
-static const yasm_directive bin_objfmt_directives[] = {
- { "org", "nasm", bin_objfmt_dir_org, YASM_DIR_ARG_REQUIRED },
- { "map", "nasm", bin_objfmt_dir_map, YASM_DIR_ANY },
- { NULL, NULL, NULL, 0 }
-};
-
-static const char *bin_nasm_stdmac[] = {
- "%imacro org 1+.nolist",
- "[org %1]",
- "%endmacro",
- NULL
-};
-
-static const yasm_stdmac bin_objfmt_stdmacs[] = {
- { "nasm", "nasm", bin_nasm_stdmac },
- { "tasm", "tasm", bin_nasm_stdmac },
- { NULL, NULL, NULL }
-};
-
-/* Define objfmt structure -- see objfmt.h for details */
-yasm_objfmt_module yasm_bin_LTX_objfmt = {
- "Flat format binary",
- "bin",
- NULL,
- 16,
- 0,
- bin_objfmt_dbgfmt_keywords,
- "null",
- bin_objfmt_directives,
- bin_objfmt_stdmacs,
- bin_objfmt_create,
- bin_objfmt_output,
- bin_objfmt_destroy,
- bin_objfmt_add_default_section,
- bin_objfmt_init_new_section,
- bin_objfmt_section_switch,
- bin_objfmt_get_special_sym
-};
-
-#define EXE_HEADER_SIZE 0x200
-
-/* DOS .EXE binaries are just raw binaries with a header */
-yasm_objfmt_module yasm_dosexe_LTX_objfmt;
-
-static yasm_objfmt *
-dosexe_objfmt_create(yasm_object *object)
-{
- yasm_objfmt_bin *objfmt_bin = (yasm_objfmt_bin *) bin_objfmt_create(object);
- objfmt_bin->objfmt.module = &yasm_dosexe_LTX_objfmt;
- return (yasm_objfmt *)objfmt_bin;
-}
-
-static unsigned long
-get_sym(yasm_object *object, const char *name) {
- yasm_symrec *symrec = yasm_symtab_get(object->symtab, name);
- yasm_bytecode *prevbc;
- if (!symrec)
- return 0;
- if (!yasm_symrec_get_label(symrec, &prevbc))
- return 0;
- return prevbc->offset + prevbc->len;
-}
-
-static void
-dosexe_objfmt_output(yasm_object *object, FILE *f, /*@unused@*/ int all_syms,
- yasm_errwarns *errwarns)
-{
- unsigned long tot_size, size, bss_size;
- unsigned long start, bss;
- unsigned char c;
-
- fseek(f, EXE_HEADER_SIZE, SEEK_SET);
-
- bin_objfmt_output(object, f, all_syms, errwarns);
-
- tot_size = ftell(f);
-
- /* if there is a __bss_start symbol, data after it is 0, no need to write
- * it. */
- bss = get_sym(object, "__bss_start");
- if (bss)
- size = bss;
- else
- size = tot_size;
- bss_size = tot_size - size;
-#ifdef HAVE_FTRUNCATE
- if (size != tot_size)
- ftruncate(fileno(f), EXE_HEADER_SIZE + size);
-#endif
- fseek(f, 0, SEEK_SET);
-
- /* magic */
- fwrite("MZ", 1, 2, f);
-
- /* file size */
- c = size & 0xff;
- fwrite(&c, 1, 1, f);
- c = !!(size & 0x100);
- fwrite(&c, 1, 1, f);
- c = ((size + 511) >> 9) & 0xff;
- fwrite(&c, 1, 1, f);
- c = ((size + 511) >> 17) & 0xff;
- fwrite(&c, 1, 1, f);
-
- /* relocation # */
- c = 0;
- fwrite(&c, 1, 1, f);
- fwrite(&c, 1, 1, f);
-
- /* header size */
- c = EXE_HEADER_SIZE / 16;
- fwrite(&c, 1, 1, f);
- c = 0;
- fwrite(&c, 1, 1, f);
-
- /* minimum paragraph # */
- bss_size = (bss_size + 15) >> 4;
- c = bss_size & 0xff;
- fwrite(&c, 1, 1, f);
- c = (bss_size >> 8) & 0xff;
- fwrite(&c, 1, 1, f);
-
- /* maximum paragraph # */
- c = 0xFF;
- fwrite(&c, 1, 1, f);
- fwrite(&c, 1, 1, f);
-
- /* relative value of stack segment */
- c = 0;
- fwrite(&c, 1, 1, f);
- fwrite(&c, 1, 1, f);
-
- /* SP at start */
- c = 0;
- fwrite(&c, 1, 1, f);
- fwrite(&c, 1, 1, f);
-
- /* header checksum */
- c = 0;
- fwrite(&c, 1, 1, f);
- fwrite(&c, 1, 1, f);
-
- /* IP at start */
- start = get_sym(object, "start");
- if (!start) {
- yasm_error_set(YASM_ERROR_GENERAL,
- N_("%s: could not find symbol `start'"));
- return;
- }
- c = start & 0xff;
- fwrite(&c, 1, 1, f);
- c = (start >> 8) & 0xff;
- fwrite(&c, 1, 1, f);
-
- /* CS start */
- c = 0;
- fwrite(&c, 1, 1, f);
- fwrite(&c, 1, 1, f);
-
- /* reloc start */
- c = 0x22;
- fwrite(&c, 1, 1, f);
- c = 0;
- fwrite(&c, 1, 1, f);
-
- /* Overlay number */
- c = 0;
- fwrite(&c, 1, 1, f);
- fwrite(&c, 1, 1, f);
-}
-
-
-/* Define objfmt structure -- see objfmt.h for details */
-yasm_objfmt_module yasm_dosexe_LTX_objfmt = {
- "DOS .EXE format binary",
- "dosexe",
- "exe",
- 16,
- 0,
- bin_objfmt_dbgfmt_keywords,
- "null",
- bin_objfmt_directives,
- bin_objfmt_stdmacs,
- dosexe_objfmt_create,
- dosexe_objfmt_output,
- bin_objfmt_destroy,
- bin_objfmt_add_default_section,
- bin_objfmt_init_new_section,
- bin_objfmt_section_switch,
- bin_objfmt_get_special_sym
-};
+/*
+ * Flat-format binary object format
+ *
+ * Copyright (C) 2002-2007 Peter Johnson
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND OTHER CONTRIBUTORS ``AS IS''
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR OTHER CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+#include <util.h>
+
+#ifdef HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+#include <libyasm.h>
+
+
+#define REGULAR_OUTBUF_SIZE 1024
+
+typedef struct bin_section_data {
+ int bss; /* aka nobits */
+
+ /* User-provided alignment */
+ yasm_intnum *align, *valign;
+
+ /* User-provided starts */
+ /*@null@*/ /*@owned@*/ yasm_expr *start, *vstart;
+
+ /* User-provided follows */
+ /*@null@*/ /*@owned@*/ char *follows, *vfollows;
+
+ /* Calculated (final) starts, used only during output() */
+ /*@null@*/ /*@owned@*/ yasm_intnum *istart, *ivstart;
+
+ /* Calculated (final) length, used only during output() */
+ /*@null@*/ /*@owned@*/ yasm_intnum *length;
+} bin_section_data;
+
+typedef struct yasm_objfmt_bin {
+ yasm_objfmt_base objfmt; /* base structure */
+
+ enum {
+ NO_MAP = 0,
+ MAP_NONE = 0x01,
+ MAP_BRIEF = 0x02,
+ MAP_SECTIONS = 0x04,
+ MAP_SYMBOLS = 0x08
+ } map_flags;
+ /*@null@*/ /*@only@*/ char *map_filename;
+
+ /*@null@*/ /*@only@*/ yasm_expr *org;
+} yasm_objfmt_bin;
+
+/* symrec data is used only for the special symbols section<sectname>.start,
+ * section<sectname>.vstart, and section<sectname>.length
+ */
+typedef struct bin_symrec_data {
+ yasm_section *section; /* referenced section */
+ enum bin_ssym {
+ SSYM_START,
+ SSYM_VSTART,
+ SSYM_LENGTH
+ } which;
+} bin_symrec_data;
+
+static void bin_section_data_destroy(/*@only@*/ void *d);
+static void bin_section_data_print(void *data, FILE *f, int indent_level);
+
+static const yasm_assoc_data_callback bin_section_data_cb = {
+ bin_section_data_destroy,
+ bin_section_data_print
+};
+
+static void bin_symrec_data_destroy(/*@only@*/ void *d);
+static void bin_symrec_data_print(void *data, FILE *f, int indent_level);
+
+static const yasm_assoc_data_callback bin_symrec_data_cb = {
+ bin_symrec_data_destroy,
+ bin_symrec_data_print
+};
+
+yasm_objfmt_module yasm_bin_LTX_objfmt;
+
+
+static yasm_objfmt *
+bin_objfmt_create(yasm_object *object)
+{
+ yasm_objfmt_bin *objfmt_bin = yasm_xmalloc(sizeof(yasm_objfmt_bin));
+ objfmt_bin->objfmt.module = &yasm_bin_LTX_objfmt;
+
+ objfmt_bin->map_flags = NO_MAP;
+ objfmt_bin->map_filename = NULL;
+ objfmt_bin->org = NULL;
+
+ return (yasm_objfmt *)objfmt_bin;
+}
+
+typedef TAILQ_HEAD(bin_group_head, bin_group) bin_groups;
+
+typedef struct bin_group {
+ TAILQ_ENTRY(bin_group) link;
+ yasm_section *section;
+ bin_section_data *bsd;
+
+ /* Groups that (in parallel) logically come immediately after this
+ * group's section.
+ */
+ bin_groups follow_groups;
+} bin_group;
+
+/* Recursive function to find group containing named section. */
+static bin_group *
+find_group_by_name(bin_groups *groups, const char *name)
+{
+ bin_group *group, *found;
+ TAILQ_FOREACH(group, groups, link) {
+ if (strcmp(yasm_section_get_name(group->section), name) == 0)
+ return group;
+ /* Recurse to loop through follow groups */
+ found = find_group_by_name(&group->follow_groups, name);
+ if (found)
+ return found;
+ }
+ return NULL;
+}
+
+/* Recursive function to find group. Returns NULL if not found. */
+static bin_group *
+find_group_by_section(bin_groups *groups, yasm_section *section)
+{
+ bin_group *group, *found;
+ TAILQ_FOREACH(group, groups, link) {
+ if (group->section == section)
+ return group;
+ /* Recurse to loop through follow groups */
+ found = find_group_by_section(&group->follow_groups, section);
+ if (found)
+ return found;
+ }
+ return NULL;
+}
+
+#if 0
+/* Debugging function */
+static void
+print_groups(const bin_groups *groups, int indent_level)
+{
+ bin_group *group;
+ TAILQ_FOREACH(group, groups, link) {
+ printf("%*sSection `%s':\n", indent_level, "",
+ yasm_section_get_name(group->section));
+ bin_section_data_print(group->bsd, stdout, indent_level+1);
+ if (!TAILQ_EMPTY(&group->follow_groups)) {
+ printf("%*sFollowing groups:\n", indent_level, "");
+ print_groups(&group->follow_groups, indent_level+1);
+ }
+ }
+}
+#endif
+
+static void
+bin_group_destroy(/*@only@*/ bin_group *group)
+{
+ bin_group *follow, *group_temp;
+ TAILQ_FOREACH_SAFE(follow, &group->follow_groups, link, group_temp)
+ bin_group_destroy(follow);
+ yasm_xfree(group);
+}
+
+typedef struct bin_objfmt_output_info {
+ yasm_object *object;
+ yasm_errwarns *errwarns;
+ /*@dependent@*/ FILE *f;
+ /*@only@*/ unsigned char *buf;
+ /*@observer@*/ const yasm_section *sect;
+ unsigned long start; /* what normal variables go against */
+
+ yasm_intnum *origin;
+ yasm_intnum *tmp_intn; /* temporary working intnum */
+
+ bin_groups lma_groups, vma_groups;
+} bin_objfmt_output_info;
+
+static int
+bin_objfmt_check_sym(yasm_symrec *sym, /*@null@*/ void *d)
+{
+ /*@null@*/ bin_objfmt_output_info *info = (bin_objfmt_output_info *)d;
+ yasm_sym_vis vis = yasm_symrec_get_visibility(sym);
+ assert(info != NULL);
+
+ /* Don't check internally-generated symbols. Only internally generated
+ * symbols have symrec data, so simply check for its presence.
+ */
+ if (yasm_symrec_get_data(sym, &bin_symrec_data_cb))
+ return 0;
+
+ if (vis & YASM_SYM_EXTERN) {
+ yasm_warn_set(YASM_WARN_GENERAL,
+ N_("binary object format does not support extern variables"));
+ yasm_errwarn_propagate(info->errwarns, yasm_symrec_get_decl_line(sym));
+ } else if (vis & YASM_SYM_GLOBAL) {
+ yasm_warn_set(YASM_WARN_GENERAL,
+ N_("binary object format does not support global variables"));
+ yasm_errwarn_propagate(info->errwarns, yasm_symrec_get_decl_line(sym));
+ } else if (vis & YASM_SYM_COMMON) {
+ yasm_error_set(YASM_ERROR_TYPE,
+ N_("binary object format does not support common variables"));
+ yasm_errwarn_propagate(info->errwarns, yasm_symrec_get_decl_line(sym));
+ }
+ return 0;
+}
+
+static int
+bin_lma_create_group(yasm_section *sect, /*@null@*/ void *d)
+{
+ bin_objfmt_output_info *info = (bin_objfmt_output_info *)d;
+ bin_section_data *bsd = yasm_section_get_data(sect, &bin_section_data_cb);
+ unsigned long align = yasm_section_get_align(sect);
+ bin_group *group;
+
+ assert(info != NULL);
+ assert(bsd != NULL);
+
+ group = yasm_xmalloc(sizeof(bin_group));
+ group->section = sect;
+ group->bsd = bsd;
+ TAILQ_INIT(&group->follow_groups);
+
+ /* Determine section alignment as necessary. */
+ if (!bsd->align)
+ bsd->align = yasm_intnum_create_uint(align > 4 ? align : 4);
+ else {
+ yasm_intnum *align_intn = yasm_intnum_create_uint(align);
+ if (yasm_intnum_compare(align_intn, bsd->align) > 0) {
+ yasm_warn_set(YASM_WARN_GENERAL,
+ N_("section `%s' internal align of %lu is greater than `%s' of %lu; using `%s'"),
+ yasm_section_get_name(sect),
+ yasm_intnum_get_uint(align_intn),
+ N_("align"),
+ yasm_intnum_get_uint(bsd->align),
+ N_("align"));
+ yasm_errwarn_propagate(info->errwarns, 0);
+ }
+ yasm_intnum_destroy(align_intn);
+ }
+
+ /* Calculate section integer start. */
+ if (bsd->start) {
+ bsd->istart = yasm_expr_get_intnum(&bsd->start, 0);
+ if (!bsd->istart) {
+ yasm_error_set(YASM_ERROR_TOO_COMPLEX,
+ N_("start expression is too complex"));
+ yasm_errwarn_propagate(info->errwarns, bsd->start->line);
+ return 1;
+ } else
+ bsd->istart = yasm_intnum_copy(bsd->istart);
+ } else
+ bsd->istart = NULL;
+
+ /* Calculate section integer vstart. */
+ if (bsd->vstart) {
+ bsd->ivstart = yasm_expr_get_intnum(&bsd->vstart, 0);
+ if (!bsd->ivstart) {
+ yasm_error_set(YASM_ERROR_TOO_COMPLEX,
+ N_("vstart expression is too complex"));
+ yasm_errwarn_propagate(info->errwarns, bsd->vstart->line);
+ return 1;
+ } else
+ bsd->ivstart = yasm_intnum_copy(bsd->ivstart);
+ } else
+ bsd->ivstart = NULL;
+
+ /* Calculate section integer length. */
+ bsd->length = yasm_calc_bc_dist(yasm_section_bcs_first(sect),
+ yasm_section_bcs_last(sect));
+
+ TAILQ_INSERT_TAIL(&info->lma_groups, group, link);
+ return 0;
+}
+
+static int
+bin_vma_create_group(yasm_section *sect, /*@null@*/ void *d)
+{
+ bin_objfmt_output_info *info = (bin_objfmt_output_info *)d;
+ bin_section_data *bsd = yasm_section_get_data(sect, &bin_section_data_cb);
+ bin_group *group;
+
+ assert(info != NULL);
+ assert(bsd != NULL);
+
+ group = yasm_xmalloc(sizeof(bin_group));
+ group->section = sect;
+ group->bsd = bsd;
+ TAILQ_INIT(&group->follow_groups);
+
+ TAILQ_INSERT_TAIL(&info->vma_groups, group, link);
+ return 0;
+}
+
+/* Calculates new start address based on alignment constraint.
+ * Start is modified (rounded up) to the closest aligned value greater than
+ * what was passed in.
+ * Align must be a power of 2.
+ */
+static void
+bin_objfmt_align(yasm_intnum *start, const yasm_intnum *align)
+{
+ /* Because alignment is always a power of two, we can use some bit
+ * trickery to do this easily.
+ */
+ yasm_intnum *align_intn =
+ yasm_intnum_create_uint(yasm_intnum_get_uint(align)-1);
+ yasm_intnum_calc(align_intn, YASM_EXPR_AND, start);
+ if (!yasm_intnum_is_zero(align_intn)) {
+ /* start = (start & ~(align-1)) + align; */
+ yasm_intnum_set_uint(align_intn, yasm_intnum_get_uint(align)-1);
+ yasm_intnum_calc(align_intn, YASM_EXPR_NOT, NULL);
+ yasm_intnum_calc(align_intn, YASM_EXPR_AND, start);
+ yasm_intnum_set(start, align);
+ yasm_intnum_calc(start, YASM_EXPR_ADD, align_intn);
+ }
+ yasm_intnum_destroy(align_intn);
+}
+
+/* Recursive function to assign start addresses.
+ * Updates start, last, and vdelta parameters as it goes along.
+ * The tmp parameter is just a working intnum so one doesn't have to be
+ * locally allocated for this purpose.
+ */
+static void
+group_assign_start_recurse(bin_group *group, yasm_intnum *start,
+ yasm_intnum *last, yasm_intnum *vdelta,
+ yasm_intnum *tmp, yasm_errwarns *errwarns)
+{
+ bin_group *follow_group;
+
+ /* Determine LMA */
+ if (group->bsd->istart) {
+ yasm_intnum_set(group->bsd->istart, start);
+ if (group->bsd->align) {
+ bin_objfmt_align(group->bsd->istart, group->bsd->align);
+ if (yasm_intnum_compare(start, group->bsd->istart) != 0) {
+ yasm_warn_set(YASM_WARN_GENERAL,
+ N_("start inconsistent with align; using aligned value"));
+ yasm_errwarn_propagate(errwarns, group->bsd->start->line);
+ }
+ }
+ } else {
+ group->bsd->istart = yasm_intnum_copy(start);
+ if (group->bsd->align != 0)
+ bin_objfmt_align(group->bsd->istart, group->bsd->align);
+ }
+
+ /* Determine VMA if either just valign specified or if no v* specified */
+ if (!group->bsd->vstart) {
+ if (!group->bsd->vfollows && !group->bsd->valign) {
+ /* No v* specified, set VMA=LMA+vdelta. */
+ group->bsd->ivstart = yasm_intnum_copy(group->bsd->istart);
+ yasm_intnum_calc(group->bsd->ivstart, YASM_EXPR_ADD, vdelta);
+ } else if (!group->bsd->vfollows) {
+ /* Just valign specified: set VMA=LMA+vdelta, align VMA, then add
+ * delta between unaligned and aligned to vdelta parameter.
+ */
+ group->bsd->ivstart = yasm_intnum_copy(group->bsd->istart);
+ yasm_intnum_calc(group->bsd->ivstart, YASM_EXPR_ADD, vdelta);
+ yasm_intnum_set(tmp, group->bsd->ivstart);
+ bin_objfmt_align(group->bsd->ivstart, group->bsd->valign);
+ yasm_intnum_calc(vdelta, YASM_EXPR_ADD, group->bsd->ivstart);
+ yasm_intnum_calc(vdelta, YASM_EXPR_SUB, tmp);
+ }
+ }
+
+ /* Find the maximum end value */
+ yasm_intnum_set(tmp, group->bsd->istart);
+ yasm_intnum_calc(tmp, YASM_EXPR_ADD, group->bsd->length);
+ if (yasm_intnum_compare(tmp, last) > 0) /* tmp > last */
+ yasm_intnum_set(last, tmp);
+
+ /* Recurse for each following group. */
+ TAILQ_FOREACH(follow_group, &group->follow_groups, link) {
+ /* Following sections have to follow this one,
+ * so add length to start.
+ */
+ yasm_intnum_set(start, group->bsd->istart);
+ yasm_intnum_calc(start, YASM_EXPR_ADD, group->bsd->length);
+
+ group_assign_start_recurse(follow_group, start, last, vdelta, tmp,
+ errwarns);
+ }
+}
+
+/* Recursive function to assign start addresses.
+ * Updates start parameter as it goes along.
+ * The tmp parameter is just a working intnum so one doesn't have to be
+ * locally allocated for this purpose.
+ */
+static void
+group_assign_vstart_recurse(bin_group *group, yasm_intnum *start,
+ yasm_errwarns *errwarns)
+{
+ bin_group *follow_group;
+
+ /* Determine VMA section alignment as necessary.
+ * Default to LMA alignment if not specified.
+ */
+ if (!group->bsd->valign)
+ group->bsd->valign = yasm_intnum_copy(group->bsd->align);
+ else {
+ unsigned long align = yasm_section_get_align(group->section);
+ yasm_intnum *align_intn = yasm_intnum_create_uint(align);
+ if (yasm_intnum_compare(align_intn, group->bsd->valign) > 0) {
+ yasm_warn_set(YASM_WARN_GENERAL,
+ N_("section `%s' internal align of %lu is greater than `%s' of %lu; using `%s'"),
+ yasm_section_get_name(group->section),
+ yasm_intnum_get_uint(align_intn),
+ N_("valign"),
+ yasm_intnum_get_uint(group->bsd->valign),
+ N_("valign"));
+ yasm_errwarn_propagate(errwarns, 0);
+ }
+ yasm_intnum_destroy(align_intn);
+ }
+
+ /* Determine VMA */
+ if (group->bsd->ivstart) {
+ yasm_intnum_set(group->bsd->ivstart, start);
+ if (group->bsd->valign) {
+ bin_objfmt_align(group->bsd->ivstart, group->bsd->valign);
+ if (yasm_intnum_compare(start, group->bsd->ivstart) != 0) {
+ yasm_error_set(YASM_ERROR_VALUE,
+ N_("vstart inconsistent with valign"));
+ yasm_errwarn_propagate(errwarns, group->bsd->vstart->line);
+ }
+ }
+ } else {
+ group->bsd->ivstart = yasm_intnum_copy(start);
+ if (group->bsd->valign)
+ bin_objfmt_align(group->bsd->ivstart, group->bsd->valign);
+ }
+
+ /* Recurse for each following group. */
+ TAILQ_FOREACH(follow_group, &group->follow_groups, link) {
+ /* Following sections have to follow this one,
+ * so add length to start.
+ */
+ yasm_intnum_set(start, group->bsd->ivstart);
+ yasm_intnum_calc(start, YASM_EXPR_ADD, group->bsd->length);
+
+ group_assign_vstart_recurse(follow_group, start, errwarns);
+ }
+}
+
+static /*@null@*/ const yasm_intnum *
+get_ssym_value(yasm_symrec *sym)
+{
+ bin_symrec_data *bsymd = yasm_symrec_get_data(sym, &bin_symrec_data_cb);
+ bin_section_data *bsd;
+
+ if (!bsymd)
+ return NULL;
+
+ bsd = yasm_section_get_data(bsymd->section, &bin_section_data_cb);
+ assert(bsd != NULL);
+
+ switch (bsymd->which) {
+ case SSYM_START: return bsd->istart;
+ case SSYM_VSTART: return bsd->ivstart;
+ case SSYM_LENGTH: return bsd->length;
+ }
+ return NULL;
+}
+
+static /*@only@*/ yasm_expr *
+bin_objfmt_expr_xform(/*@returned@*/ /*@only@*/ yasm_expr *e,
+ /*@unused@*/ /*@null@*/ void *d)
+{
+ int i;
+ for (i=0; i<e->numterms; i++) {
+ /*@dependent@*/ yasm_section *sect;
+ /*@dependent@*/ /*@null@*/ yasm_bytecode *precbc;
+ /*@null@*/ yasm_intnum *dist;
+ /*@null@*/ const yasm_intnum *ssymval;
+
+ /* Transform symrecs or precbcs that reference sections into
+ * vstart + intnum(dist).
+ */
+ if (((e->terms[i].type == YASM_EXPR_SYM &&
+ yasm_symrec_get_label(e->terms[i].data.sym, &precbc)) ||
+ (e->terms[i].type == YASM_EXPR_PRECBC &&
+ (precbc = e->terms[i].data.precbc))) &&
+ (sect = yasm_bc_get_section(precbc)) &&
+ (dist = yasm_calc_bc_dist(yasm_section_bcs_first(sect), precbc))) {
+ bin_section_data *bsd;
+ bsd = yasm_section_get_data(sect, &bin_section_data_cb);
+ assert(bsd != NULL);
+ yasm_intnum_calc(dist, YASM_EXPR_ADD, bsd->ivstart);
+ e->terms[i].type = YASM_EXPR_INT;
+ e->terms[i].data.intn = dist;
+ }
+
+ /* Transform our special symrecs into the appropriate value */
+ if (e->terms[i].type == YASM_EXPR_SYM &&
+ (ssymval = get_ssym_value(e->terms[i].data.sym))) {
+ e->terms[i].type = YASM_EXPR_INT;
+ e->terms[i].data.intn = yasm_intnum_copy(ssymval);
+ }
+ }
+
+ return e;
+}
+
+typedef struct map_output_info {
+ /* address width */
+ int bytes;
+
+ /* intnum output static data areas */
+ unsigned char *buf;
+ yasm_intnum *intn;
+
+ /* symrec output information */
+ unsigned long count;
+ yasm_section *section; /* NULL for EQUs */
+
+ yasm_object *object; /* object */
+ FILE *f; /* map output file */
+} map_output_info;
+
+static int
+map_prescan_bytes(yasm_section *sect, void *d)
+{
+ bin_section_data *bsd = yasm_section_get_data(sect, &bin_section_data_cb);
+ map_output_info *info = (map_output_info *)d;
+
+ assert(bsd != NULL);
+ assert(info != NULL);
+
+ while (!yasm_intnum_check_size(bsd->length, info->bytes * 8, 0, 0))
+ info->bytes *= 2;
+ while (!yasm_intnum_check_size(bsd->istart, info->bytes * 8, 0, 0))
+ info->bytes *= 2;
+ while (!yasm_intnum_check_size(bsd->ivstart, info->bytes * 8, 0, 0))
+ info->bytes *= 2;
+
+ return 0;
+}
+
+static void
+map_print_intnum(const yasm_intnum *intn, map_output_info *info)
+{
+ size_t i;
+ yasm_intnum_get_sized(intn, info->buf, info->bytes, info->bytes*8, 0, 0,
+ 0);
+ for (i=info->bytes; i != 0; i--)
+ fprintf(info->f, "%02X", info->buf[i-1]);
+}
+
+static void
+map_sections_summary(bin_groups *groups, map_output_info *info)
+{
+ bin_group *group;
+ TAILQ_FOREACH(group, groups, link) {
+ bin_section_data *bsd = group->bsd;
+
+ assert(bsd != NULL);
+ assert(info != NULL);
+
+ map_print_intnum(bsd->ivstart, info);
+ fprintf(info->f, " ");
+
+ yasm_intnum_set(info->intn, bsd->ivstart);
+ yasm_intnum_calc(info->intn, YASM_EXPR_ADD, bsd->length);
+ map_print_intnum(info->intn, info);
+ fprintf(info->f, " ");
+
+ map_print_intnum(bsd->istart, info);
+ fprintf(info->f, " ");
+
+ yasm_intnum_set(info->intn, bsd->istart);
+ yasm_intnum_calc(info->intn, YASM_EXPR_ADD, bsd->length);
+ map_print_intnum(info->intn, info);
+ fprintf(info->f, " ");
+
+ map_print_intnum(bsd->length, info);
+ fprintf(info->f, " ");
+
+ fprintf(info->f, "%-*s", 10, bsd->bss ? "nobits" : "progbits");
+ fprintf(info->f, "%s\n", yasm_section_get_name(group->section));
+
+ /* Recurse to loop through follow groups */
+ map_sections_summary(&group->follow_groups, info);
+ }
+}
+
+static void
+map_sections_detail(bin_groups *groups, map_output_info *info)
+{
+ bin_group *group;
+ TAILQ_FOREACH(group, groups, link) {
+ bin_section_data *bsd = group->bsd;
+ size_t i;
+ const char *s;
+
+ s = yasm_section_get_name(group->section);
+ fprintf(info->f, "---- Section %s ", s);
+ for (i=0; i<(65-strlen(s)); i++)
+ fputc('-', info->f);
+
+ fprintf(info->f, "\n\nclass: %s",
+ bsd->bss ? "nobits" : "progbits");
+ fprintf(info->f, "\nlength: ");
+ map_print_intnum(bsd->length, info);
+ fprintf(info->f, "\nstart: ");
+ map_print_intnum(bsd->istart, info);
+ fprintf(info->f, "\nalign: ");
+ map_print_intnum(bsd->align, info);
+ fprintf(info->f, "\nfollows: %s",
+ bsd->follows ? bsd->follows : "not defined");
+ fprintf(info->f, "\nvstart: ");
+ map_print_intnum(bsd->ivstart, info);
+ fprintf(info->f, "\nvalign: ");
+ map_print_intnum(bsd->valign, info);
+ fprintf(info->f, "\nvfollows: %s\n\n",
+ bsd->vfollows ? bsd->vfollows : "not defined");
+
+ /* Recurse to loop through follow groups */
+ map_sections_detail(&group->follow_groups, info);
+ }
+}
+
+static int
+map_symrec_count(yasm_symrec *sym, void *d)
+{
+ map_output_info *info = (map_output_info *)d;
+ /*@dependent@*/ yasm_bytecode *precbc;
+
+ assert(info != NULL);
+
+ /* TODO: autodetect wider size */
+ if (!info->section && yasm_symrec_get_equ(sym)) {
+ info->count++;
+ } else if (yasm_symrec_get_label(sym, &precbc) &&
+ yasm_bc_get_section(precbc) == info->section) {
+ info->count++;
+ }
+ return 0;
+}
+
+static int
+map_symrec_output(yasm_symrec *sym, void *d)
+{
+ map_output_info *info = (map_output_info *)d;
+ const yasm_expr *equ;
+ /*@dependent@*/ yasm_bytecode *precbc;
+ /*@only@*/ char *name = yasm_symrec_get_global_name(sym, info->object);
+
+ assert(info != NULL);
+
+ if (!info->section && (equ = yasm_symrec_get_equ(sym))) {
+ yasm_expr *realequ = yasm_expr_copy(equ);
+ realequ = yasm_expr__level_tree
+ (realequ, 1, 1, 1, 0, bin_objfmt_expr_xform, NULL);
+ yasm_intnum_set(info->intn, yasm_expr_get_intnum(&realequ, 0));
+ yasm_expr_destroy(realequ);
+ map_print_intnum(info->intn, info);
+ fprintf(info->f, " %s\n", name);
+ } else if (yasm_symrec_get_label(sym, &precbc) &&
+ yasm_bc_get_section(precbc) == info->section) {
+ bin_section_data *bsd =
+ yasm_section_get_data(info->section, &bin_section_data_cb);
+
+ /* Real address */
+ yasm_intnum_set_uint(info->intn, yasm_bc_next_offset(precbc));
+ yasm_intnum_calc(info->intn, YASM_EXPR_ADD, bsd->istart);
+ map_print_intnum(info->intn, info);
+ fprintf(info->f, " ");
+
+ /* Virtual address */
+ yasm_intnum_set_uint(info->intn, yasm_bc_next_offset(precbc));
+ yasm_intnum_calc(info->intn, YASM_EXPR_ADD, bsd->ivstart);
+ map_print_intnum(info->intn, info);
+
+ /* Name */
+ fprintf(info->f, " %s\n", name);
+ }
+ yasm_xfree(name);
+ return 0;
+}
+
+static void
+map_sections_symbols(bin_groups *groups, map_output_info *info)
+{
+ bin_group *group;
+ TAILQ_FOREACH(group, groups, link) {
+ info->count = 0;
+ info->section = group->section;
+ yasm_symtab_traverse(info->object->symtab, info, map_symrec_count);
+
+ if (info->count > 0) {
+ const char *s = yasm_section_get_name(group->section);
+ size_t i;
+ fprintf(info->f, "---- Section %s ", s);
+ for (i=0; i<(65-strlen(s)); i++)
+ fputc('-', info->f);
+ fprintf(info->f, "\n\n%-*s%-*s%s\n",
+ info->bytes*2+2, "Real",
+ info->bytes*2+2, "Virtual",
+ "Name");
+ yasm_symtab_traverse(info->object->symtab, info,
+ map_symrec_output);
+ fprintf(info->f, "\n\n");
+ }
+
+ /* Recurse to loop through follow groups */
+ map_sections_symbols(&group->follow_groups, info);
+ }
+}
+
+static void
+output_map(bin_objfmt_output_info *info)
+{
+ yasm_objfmt_bin *objfmt_bin = (yasm_objfmt_bin *)info->object->objfmt;
+ FILE *f;
+ int i;
+ map_output_info mapinfo;
+
+ if (objfmt_bin->map_flags == NO_MAP)
+ return;
+
+ if (objfmt_bin->map_flags == MAP_NONE)
+ objfmt_bin->map_flags = MAP_BRIEF; /* default to brief */
+
+ if (!objfmt_bin->map_filename)
+ f = stdout; /* default to stdout */
+ else {
+ f = fopen(objfmt_bin->map_filename, "wt");
+ if (!f) {
+ yasm_warn_set(YASM_WARN_GENERAL,
+ N_("unable to open map file `%s'"),
+ objfmt_bin->map_filename);
+ yasm_errwarn_propagate(info->errwarns, 0);
+ return;
+ }
+ }
+
+ mapinfo.object = info->object;
+ mapinfo.f = f;
+
+ /* Temporary intnum */
+ mapinfo.intn = info->tmp_intn;
+
+ /* Prescan all values to figure out what width we should make the output
+ * fields. Start with a minimum of 4.
+ */
+ mapinfo.bytes = 4;
+ while (!yasm_intnum_check_size(info->origin, mapinfo.bytes * 8, 0, 0))
+ mapinfo.bytes *= 2;
+ yasm_object_sections_traverse(info->object, &mapinfo, map_prescan_bytes);
+ mapinfo.buf = yasm_xmalloc(mapinfo.bytes);
+
+ fprintf(f, "\n- YASM Map file ");
+ for (i=0; i<63; i++)
+ fputc('-', f);
+ fprintf(f, "\n\nSource file: %s\n", info->object->src_filename);
+ fprintf(f, "Output file: %s\n\n", info->object->obj_filename);
+
+ fprintf(f, "-- Program origin ");
+ for (i=0; i<61; i++)
+ fputc('-', f);
+ fprintf(f, "\n\n");
+ map_print_intnum(info->origin, &mapinfo);
+ fprintf(f, "\n\n");
+
+ if (objfmt_bin->map_flags & MAP_BRIEF) {
+ fprintf(f, "-- Sections (summary) ");
+ for (i=0; i<57; i++)
+ fputc('-', f);
+ fprintf(f, "\n\n%-*s%-*s%-*s%-*s%-*s%-*s%s\n",
+ mapinfo.bytes*2+2, "Vstart",
+ mapinfo.bytes*2+2, "Vstop",
+ mapinfo.bytes*2+2, "Start",
+ mapinfo.bytes*2+2, "Stop",
+ mapinfo.bytes*2+2, "Length",
+ 10, "Class", "Name");
+
+ map_sections_summary(&info->lma_groups, &mapinfo);
+ fprintf(f, "\n");
+ }
+
+ if (objfmt_bin->map_flags & MAP_SECTIONS) {
+ fprintf(f, "-- Sections (detailed) ");
+ for (i=0; i<56; i++)
+ fputc('-', f);
+ fprintf(f, "\n\n");
+ map_sections_detail(&info->lma_groups, &mapinfo);
+ }
+
+ if (objfmt_bin->map_flags & MAP_SYMBOLS) {
+ fprintf(f, "-- Symbols ");
+ for (i=0; i<68; i++)
+ fputc('-', f);
+ fprintf(f, "\n\n");
+
+ /* We do two passes for EQU and each section; the first pass
+ * determines the byte width to use for the value and whether any
+ * symbols are present, the second pass actually outputs the text.
+ */
+
+ /* EQUs */
+ mapinfo.count = 0;
+ mapinfo.section = NULL;
+ yasm_symtab_traverse(info->object->symtab, &mapinfo, map_symrec_count);
+
+ if (mapinfo.count > 0) {
+ fprintf(f, "---- No Section ");
+ for (i=0; i<63; i++)
+ fputc('-', f);
+ fprintf(f, "\n\n%-*s%s\n", mapinfo.bytes*2+2, "Value", "Name");
+ yasm_symtab_traverse(info->object->symtab, &mapinfo,
+ map_symrec_output);
+ fprintf(f, "\n\n");
+ }
+
+ /* Other sections */
+ map_sections_symbols(&info->lma_groups, &mapinfo);
+ }
+
+ if (f != stdout)
+ fclose(f);
+
+ yasm_xfree(mapinfo.buf);
+}
+
+/* Check for LMA overlap using a simple N^2 algorithm. */
+static int
+check_lma_overlap(yasm_section *sect, /*@null@*/ void *d)
+{
+ bin_section_data *bsd, *bsd2;
+ yasm_section *other = (yasm_section *)d;
+ yasm_intnum *overlap;
+
+ if (!d)
+ return yasm_object_sections_traverse(yasm_section_get_object(sect),
+ sect, check_lma_overlap);
+ if (sect == other)
+ return 0;
+
+ bsd = yasm_section_get_data(sect, &bin_section_data_cb);
+ bsd2 = yasm_section_get_data(other, &bin_section_data_cb);
+
+ if (yasm_intnum_is_zero(bsd->length) ||
+ yasm_intnum_is_zero(bsd2->length))
+ return 0;
+
+ if (yasm_intnum_compare(bsd->istart, bsd2->istart) <= 0) {
+ overlap = yasm_intnum_copy(bsd->istart);
+ yasm_intnum_calc(overlap, YASM_EXPR_ADD, bsd->length);
+ yasm_intnum_calc(overlap, YASM_EXPR_SUB, bsd2->istart);
+ } else {
+ overlap = yasm_intnum_copy(bsd2->istart);
+ yasm_intnum_calc(overlap, YASM_EXPR_ADD, bsd2->length);
+ yasm_intnum_calc(overlap, YASM_EXPR_SUB, bsd->istart);
+ }
+
+ if (yasm_intnum_sign(overlap) > 0) {
+ yasm_error_set(YASM_ERROR_GENERAL,
+ N_("sections `%s' and `%s' overlap by %lu bytes"),
+ yasm_section_get_name(sect),
+ yasm_section_get_name(other),
+ yasm_intnum_get_uint(overlap));
+ yasm_intnum_destroy(overlap);
+ return -1;
+ }
+
+ yasm_intnum_destroy(overlap);
+ return 0;
+}
+
+static int
+bin_objfmt_output_value(yasm_value *value, unsigned char *buf,
+ unsigned int destsize,
+ /*@unused@*/ unsigned long offset, yasm_bytecode *bc,
+ int warn, /*@null@*/ void *d)
+{
+ /*@null@*/ bin_objfmt_output_info *info = (bin_objfmt_output_info *)d;
+ /*@dependent@*/ /*@null@*/ yasm_bytecode *precbc;
+ /*@dependent@*/ yasm_section *sect;
+
+ assert(info != NULL);
+
+ /* Binary objects we need to resolve against object, not against section. */
+ if (value->rel) {
+ unsigned int rshift = (unsigned int)value->rshift;
+ yasm_expr *syme;
+ /*@null@*/ const yasm_intnum *ssymval;
+
+ if (yasm_symrec_is_abs(value->rel)) {
+ syme = yasm_expr_create_ident(yasm_expr_int(
+ yasm_intnum_create_uint(0)), bc->line);
+ } else if (yasm_symrec_get_label(value->rel, &precbc)
+ && (sect = yasm_bc_get_section(precbc))) {
+ syme = yasm_expr_create_ident(yasm_expr_sym(value->rel), bc->line);
+ } else if ((ssymval = get_ssym_value(value->rel))) {
+ syme = yasm_expr_create_ident(yasm_expr_int(
+ yasm_intnum_copy(ssymval)), bc->line);
+ } else
+ goto done;
+
+ /* Handle PC-relative */
+ if (value->curpos_rel) {
+ yasm_expr *sube;
+ sube = yasm_expr_create(YASM_EXPR_SUB, yasm_expr_precbc(bc),
+ yasm_expr_int(yasm_intnum_create_uint(bc->len*bc->mult_int)),
+ bc->line);
+ syme = yasm_expr_create(YASM_EXPR_SUB, yasm_expr_expr(syme),
+ yasm_expr_expr(sube), bc->line);
+ value->curpos_rel = 0;
+ value->ip_rel = 0;
+ }
+
+ if (value->rshift > 0)
+ syme = yasm_expr_create(YASM_EXPR_SHR, yasm_expr_expr(syme),
+ yasm_expr_int(yasm_intnum_create_uint(rshift)), bc->line);
+
+ /* Add into absolute portion */
+ if (!value->abs)
+ value->abs = syme;
+ else
+ value->abs =
+ yasm_expr_create(YASM_EXPR_ADD, yasm_expr_expr(value->abs),
+ yasm_expr_expr(syme), bc->line);
+ value->rel = NULL;
+ value->rshift = 0;
+ }
+done:
+ /* Simplify absolute portion of value, transforming symrecs */
+ if (value->abs)
+ value->abs = yasm_expr__level_tree
+ (value->abs, 1, 1, 1, 0, bin_objfmt_expr_xform, NULL);
+
+ /* Output */
+ switch (yasm_value_output_basic(value, buf, destsize, bc, warn,
+ info->object->arch)) {
+ case -1:
+ return 1;
+ case 0:
+ break;
+ default:
+ return 0;
+ }
+
+ /* Couldn't output, assume it contains an external reference. */
+ yasm_error_set(YASM_ERROR_GENERAL,
+ N_("binary object format does not support external references"));
+ return 1;
+}
+
+static int
+bin_objfmt_output_bytecode(yasm_bytecode *bc, /*@null@*/ void *d)
+{
+ /*@null@*/ bin_objfmt_output_info *info = (bin_objfmt_output_info *)d;
+ /*@null@*/ /*@only@*/ unsigned char *bigbuf;
+ unsigned long size = REGULAR_OUTBUF_SIZE;
+ int gap;
+
+ assert(info != NULL);
+
+ bigbuf = yasm_bc_tobytes(bc, info->buf, &size, &gap, info,
+ bin_objfmt_output_value, NULL);
+
+ /* Don't bother doing anything else if size ended up being 0. */
+ if (size == 0) {
+ if (bigbuf)
+ yasm_xfree(bigbuf);
+ return 0;
+ }
+
+ /* Warn that gaps are converted to 0 and write out the 0's. */
+ if (gap) {
+ unsigned long left;
+ yasm_warn_set(YASM_WARN_UNINIT_CONTENTS,
+ N_("uninitialized space declared in code/data section: zeroing"));
+ /* Write out in chunks */
+ memset(info->buf, 0, REGULAR_OUTBUF_SIZE);
+ left = size;
+ while (left > REGULAR_OUTBUF_SIZE) {
+ fwrite(info->buf, REGULAR_OUTBUF_SIZE, 1, info->f);
+ left -= REGULAR_OUTBUF_SIZE;
+ }
+ fwrite(info->buf, left, 1, info->f);
+ } else {
+ /* Output buf (or bigbuf if non-NULL) to file */
+ fwrite(bigbuf ? bigbuf : info->buf, (size_t)size, 1, info->f);
+ }
+
+ /* If bigbuf was allocated, free it */
+ if (bigbuf)
+ yasm_xfree(bigbuf);
+
+ return 0;
+}
+
+/* Check to ensure bytecode is res* (for BSS sections) */
+static int
+bin_objfmt_no_output_bytecode(yasm_bytecode *bc, /*@null@*/ void *d)
+{
+ /*@null@*/ bin_objfmt_output_info *info = (bin_objfmt_output_info *)d;
+ /*@null@*/ /*@only@*/ unsigned char *bigbuf;
+ unsigned long size = REGULAR_OUTBUF_SIZE;
+ int gap;
+
+ assert(info != NULL);
+
+ bigbuf = yasm_bc_tobytes(bc, info->buf, &size, &gap, info,
+ bin_objfmt_output_value, NULL);
+
+ /* If bigbuf was allocated, free it */
+ if (bigbuf)
+ yasm_xfree(bigbuf);
+
+ /* Don't bother doing anything else if size ended up being 0. */
+ if (size == 0)
+ return 0;
+
+ /* Warn if not a gap. */
+ if (!gap) {
+ yasm_warn_set(YASM_WARN_GENERAL,
+ N_("initialized space declared in nobits section: ignoring"));
+ }
+
+ return 0;
+}
+
+static int
+bin_objfmt_output_section(yasm_section *sect, /*@null@*/ void *d)
+{
+ bin_section_data *bsd = yasm_section_get_data(sect, &bin_section_data_cb);
+ /*@null@*/ bin_objfmt_output_info *info = (bin_objfmt_output_info *)d;
+
+ assert(bsd != NULL);
+ assert(info != NULL);
+
+ if (bsd->bss) {
+ yasm_section_bcs_traverse(sect, info->errwarns,
+ info, bin_objfmt_no_output_bytecode);
+ } else {
+ yasm_intnum_set(info->tmp_intn, bsd->istart);
+ yasm_intnum_calc(info->tmp_intn, YASM_EXPR_SUB, info->origin);
+ if (yasm_intnum_sign(info->tmp_intn) < 0) {
+ yasm_error_set(YASM_ERROR_VALUE,
+ N_("section `%s' starts before origin (ORG)"),
+ yasm_section_get_name(sect));
+ yasm_errwarn_propagate(info->errwarns, 0);
+ return 0;
+ }
+ if (!yasm_intnum_check_size(info->tmp_intn, sizeof(long)*8, 0, 1)) {
+ yasm_error_set(YASM_ERROR_VALUE,
+ N_("section `%s' start value too large"),
+ yasm_section_get_name(sect));
+ yasm_errwarn_propagate(info->errwarns, 0);
+ return 0;
+ }
+ if (fseek(info->f, yasm_intnum_get_int(info->tmp_intn) + info->start,
+ SEEK_SET) < 0)
+ yasm__fatal(N_("could not seek on output file"));
+ yasm_section_bcs_traverse(sect, info->errwarns,
+ info, bin_objfmt_output_bytecode);
+ }
+
+ return 0;
+}
+
+static void
+bin_objfmt_cleanup(bin_objfmt_output_info *info)
+{
+ bin_group *group, *group_temp;
+
+ yasm_xfree(info->buf);
+ yasm_intnum_destroy(info->origin);
+ yasm_intnum_destroy(info->tmp_intn);
+
+ TAILQ_FOREACH_SAFE(group, &info->lma_groups, link, group_temp)
+ bin_group_destroy(group);
+
+ TAILQ_FOREACH_SAFE(group, &info->vma_groups, link, group_temp)
+ bin_group_destroy(group);
+}
+
+static void
+bin_objfmt_output(yasm_object *object, FILE *f, /*@unused@*/ int all_syms,
+ yasm_errwarns *errwarns)
+{
+ yasm_objfmt_bin *objfmt_bin = (yasm_objfmt_bin *)object->objfmt;
+ bin_objfmt_output_info info;
+ bin_group *group, *lma_group, *vma_group, *group_temp;
+ yasm_intnum *start, *last, *vdelta;
+ bin_groups unsorted_groups, bss_groups;
+
+ info.start = ftell(f);
+
+ /* Set ORG to 0 unless otherwise specified */
+ if (objfmt_bin->org) {
+ info.origin = yasm_expr_get_intnum(&objfmt_bin->org, 0);
+ if (!info.origin) {
+ yasm_error_set(YASM_ERROR_TOO_COMPLEX,
+ N_("ORG expression is too complex"));
+ yasm_errwarn_propagate(errwarns, objfmt_bin->org->line);
+ return;
+ }
+ if (yasm_intnum_sign(info.origin) < 0) {
+ yasm_error_set(YASM_ERROR_VALUE, N_("ORG expression is negative"));
+ yasm_errwarn_propagate(errwarns, objfmt_bin->org->line);
+ return;
+ }
+ info.origin = yasm_intnum_copy(info.origin);
+ } else
+ info.origin = yasm_intnum_create_uint(0);
+
+ info.object = object;
+ info.errwarns = errwarns;
+ info.f = f;
+ info.buf = yasm_xmalloc(REGULAR_OUTBUF_SIZE);
+ info.tmp_intn = yasm_intnum_create_uint(0);
+ TAILQ_INIT(&info.lma_groups);
+ TAILQ_INIT(&info.vma_groups);
+
+ /* Check symbol table */
+ yasm_symtab_traverse(object->symtab, &info, bin_objfmt_check_sym);
+
+ /* Create section groups */
+ if (yasm_object_sections_traverse(object, &info, bin_lma_create_group)) {
+ bin_objfmt_cleanup(&info);
+ return; /* error detected */
+ }
+
+ /* Determine section order according to LMA.
+ * Sections can be ordered either by (priority):
+ * - follows
+ * - start
+ * - progbits/nobits setting
+ * - order in the input file
+ */
+
+ /* Look at each group with follows specified, and find the section
+ * that group is supposed to follow.
+ */
+ TAILQ_FOREACH_SAFE(lma_group, &info.lma_groups, link, group_temp) {
+ if (lma_group->bsd->follows) {
+ bin_group *found;
+ /* Need to find group containing section this section follows. */
+ found =
+ find_group_by_name(&info.lma_groups, lma_group->bsd->follows);
+ if (!found) {
+ yasm_error_set(YASM_ERROR_VALUE,
+ N_("section `%s' follows an invalid or unknown section `%s'"),
+ yasm_section_get_name(lma_group->section),
+ lma_group->bsd->follows);
+ yasm_errwarn_propagate(errwarns, 0);
+ bin_objfmt_cleanup(&info);
+ return;
+ }
+
+ /* Check for loops */
+ if (lma_group->section == found->section ||
+ find_group_by_section(&lma_group->follow_groups,
+ found->section)) {
+ yasm_error_set(YASM_ERROR_VALUE,
+ N_("follows loop between section `%s' and section `%s'"),
+ yasm_section_get_name(lma_group->section),
+ yasm_section_get_name(found->section));
+ yasm_errwarn_propagate(errwarns, 0);
+ bin_objfmt_cleanup(&info);
+ return;
+ }
+
+ /* Remove this section from main lma groups list */
+ TAILQ_REMOVE(&info.lma_groups, lma_group, link);
+ /* Add it after the section it's supposed to follow. */
+ TAILQ_INSERT_TAIL(&found->follow_groups, lma_group, link);
+ }
+ }
+
+ /* Sort the top-level groups according to their start address.
+ * Use Shell sort for ease of implementation.
+ * If no start address is specified for a section, don't change the order,
+ * and move BSS sections to a separate list so they can be moved to the
+ * end of the lma list after all other sections are sorted.
+ */
+ unsorted_groups = info.lma_groups; /* structure copy */
+ TAILQ_INIT(&info.lma_groups);
+ TAILQ_INIT(&bss_groups);
+ TAILQ_FOREACH_SAFE(lma_group, &unsorted_groups, link, group_temp) {
+ bin_group *before;
+
+ if (!lma_group->bsd->istart) {
+ if (lma_group->bsd->bss)
+ TAILQ_INSERT_TAIL(&bss_groups, lma_group, link);
+ else
+ TAILQ_INSERT_TAIL(&info.lma_groups, lma_group, link);
+ continue;
+ }
+
+ before = NULL;
+ TAILQ_FOREACH(group, &info.lma_groups, link) {
+ if (!group->bsd->istart)
+ continue;
+ if (yasm_intnum_compare(group->bsd->istart,
+ lma_group->bsd->istart) > 0) {
+ before = group;
+ break;
+ }
+ }
+ if (before)
+ TAILQ_INSERT_BEFORE(before, lma_group, link);
+ else
+ TAILQ_INSERT_TAIL(&info.lma_groups, lma_group, link);
+ }
+
+ /* Move the pure-BSS sections to the end of the LMA list. */
+ TAILQ_FOREACH_SAFE(group, &bss_groups, link, group_temp)
+ TAILQ_INSERT_TAIL(&info.lma_groups, group, link);
+ TAILQ_INIT(&bss_groups); /* For sanity */
+
+ /* Assign a LMA start address to every section.
+ * Also assign VMA=LMA unless otherwise specified.
+ *
+ * We need to assign VMA=LMA here (while walking the tree) for the case:
+ * sect1 start=0 (size=0x11)
+ * sect2 follows=sect1 valign=16 (size=0x104)
+ * sect3 follows=sect2 valign=16
+ * Where the valign of sect2 will result in a sect3 vaddr higher than a
+ * naive segment-by-segment interpretation (where sect3 and sect2 would
+ * have a VMA overlap).
+ *
+ * Algorithm for VMA=LMA setting:
+ * Start with delta=0.
+ * If there's no virtual attributes, we simply set VMA = LMA+delta.
+ * If there's only valign specified, we set VMA = aligned LMA, and add
+ * any new alignment difference to delta.
+ *
+ * We could do the LMA start and VMA=LMA steps in two separate steps,
+ * but it's easier to just recurse once.
+ */
+ start = yasm_intnum_copy(info.origin);
+ last = yasm_intnum_copy(info.origin);
+ vdelta = yasm_intnum_create_uint(0);
+ TAILQ_FOREACH(lma_group, &info.lma_groups, link) {
+ if (lma_group->bsd->istart)
+ yasm_intnum_set(start, lma_group->bsd->istart);
+ group_assign_start_recurse(lma_group, start, last, vdelta,
+ info.tmp_intn, errwarns);
+ yasm_intnum_set(start, last);
+ }
+ yasm_intnum_destroy(last);
+ yasm_intnum_destroy(vdelta);
+
+ /*
+ * Determine section order according to VMA
+ */
+
+ /* Create section groups */
+ if (yasm_object_sections_traverse(object, &info, bin_vma_create_group)) {
+ yasm_intnum_destroy(start);
+ bin_objfmt_cleanup(&info);
+ return; /* error detected */
+ }
+
+ /* Look at each group with vfollows specified, and find the section
+ * that group is supposed to follow.
+ */
+ TAILQ_FOREACH_SAFE(vma_group, &info.vma_groups, link, group_temp) {
+ if (vma_group->bsd->vfollows) {
+ bin_group *found;
+ /* Need to find group containing section this section follows. */
+ found = find_group_by_name(&info.vma_groups,
+ vma_group->bsd->vfollows);
+ if (!found) {
+ yasm_error_set(YASM_ERROR_VALUE,
+ N_("section `%s' vfollows an invalid or unknown section `%s'"),
+ yasm_section_get_name(vma_group->section),
+ vma_group->bsd->vfollows);
+ yasm_errwarn_propagate(errwarns, 0);
+ yasm_intnum_destroy(start);
+ bin_objfmt_cleanup(&info);
+ return;
+ }
+
+ /* Check for loops */
+ if (vma_group->section == found->section ||
+ find_group_by_section(&vma_group->follow_groups,
+ found->section)) {
+ yasm_error_set(YASM_ERROR_VALUE,
+ N_("vfollows loop between section `%s' and section `%s'"),
+ yasm_section_get_name(vma_group->section),
+ yasm_section_get_name(found->section));
+ yasm_errwarn_propagate(errwarns, 0);
+ bin_objfmt_cleanup(&info);
+ return;
+ }
+
+ /* Remove this section from main lma groups list */
+ TAILQ_REMOVE(&info.vma_groups, vma_group, link);
+ /* Add it after the section it's supposed to follow. */
+ TAILQ_INSERT_TAIL(&found->follow_groups, vma_group, link);
+ }
+ }
+
+ /* Due to the combination of steps above, we now know that all top-level
+ * groups have integer ivstart:
+ * Vstart Vfollows Valign Handled by
+ * No No No group_assign_start_recurse()
+ * No No Yes group_assign_start_recurse()
+ * No Yes - vfollows loop (above)
+ * Yes - - bin_lma_create_group()
+ */
+ TAILQ_FOREACH(vma_group, &info.vma_groups, link) {
+ yasm_intnum_set(start, vma_group->bsd->ivstart);
+ group_assign_vstart_recurse(vma_group, start, errwarns);
+ }
+
+ /* Output map file */
+ output_map(&info);
+
+ /* Ensure we don't have overlapping progbits LMAs.
+ * Use a dumb O(N^2) algorithm as the number of sections is essentially
+ * always low.
+ */
+ if (yasm_object_sections_traverse(object, NULL, check_lma_overlap)) {
+ yasm_errwarn_propagate(errwarns, 0);
+ yasm_intnum_destroy(start);
+ bin_objfmt_cleanup(&info);
+ return;
+ }
+
+ /* Output sections */
+ yasm_object_sections_traverse(object, &info, bin_objfmt_output_section);
+
+ /* Clean up */
+ yasm_intnum_destroy(start);
+ bin_objfmt_cleanup(&info);
+}
+
+static void
+bin_objfmt_destroy(yasm_objfmt *objfmt)
+{
+ yasm_objfmt_bin *objfmt_bin = (yasm_objfmt_bin *)objfmt;
+ if (objfmt_bin->map_filename)
+ yasm_xfree(objfmt_bin->map_filename);
+ yasm_expr_destroy(objfmt_bin->org);
+ yasm_xfree(objfmt);
+}
+
+static void
+define_section_symbol(yasm_symtab *symtab, yasm_section *sect,
+ const char *sectname, const char *suffix,
+ enum bin_ssym which, unsigned long line)
+{
+ yasm_symrec *sym;
+ bin_symrec_data *bsymd = yasm_xmalloc(sizeof(bin_symrec_data));
+ char *symname = yasm_xmalloc(8+strlen(sectname)+strlen(suffix)+1);
+
+ strcpy(symname, "section.");
+ strcat(symname, sectname);
+ strcat(symname, suffix);
+
+ bsymd->section = sect;
+ bsymd->which = which;
+
+ sym = yasm_symtab_declare(symtab, symname, YASM_SYM_EXTERN, line);
+ yasm_xfree(symname);
+ yasm_symrec_add_data(sym, &bin_symrec_data_cb, bsymd);
+}
+
+static void
+bin_objfmt_init_new_section(yasm_section *sect, unsigned long line)
+{
+ yasm_object *object = yasm_section_get_object(sect);
+ const char *sectname = yasm_section_get_name(sect);
+ /*yasm_objfmt_bin *objfmt_bin = (yasm_objfmt_bin *)object->objfmt;*/
+ bin_section_data *data;
+
+ data = yasm_xmalloc(sizeof(bin_section_data));
+ data->bss = 0;
+ data->align = NULL;
+ data->valign = NULL;
+ data->start = NULL;
+ data->vstart = NULL;
+ data->follows = NULL;
+ data->vfollows = NULL;
+ data->istart = NULL;
+ data->ivstart = NULL;
+ data->length = NULL;
+ yasm_section_add_data(sect, &bin_section_data_cb, data);
+
+ define_section_symbol(object->symtab, sect, sectname, ".start",
+ SSYM_START, line);
+ define_section_symbol(object->symtab, sect, sectname, ".vstart",
+ SSYM_VSTART, line);
+ define_section_symbol(object->symtab, sect, sectname, ".length",
+ SSYM_LENGTH, line);
+}
+
+static yasm_section *
+bin_objfmt_add_default_section(yasm_object *object)
+{
+ yasm_section *retval;
+ int isnew;
+
+ retval = yasm_object_get_general(object, ".text", 0, 1, 0, &isnew, 0);
+ if (isnew)
+ yasm_section_set_default(retval, 1);
+ return retval;
+}
+
+/* GAS-style flags */
+static int
+bin_helper_gasflags(void *obj, yasm_valparam *vp, unsigned long line, void *d,
+ /*@unused@*/ uintptr_t arg)
+{
+ /* TODO */
+ return 0;
+}
+
+static /*@observer@*/ /*@null@*/ yasm_section *
+bin_objfmt_section_switch(yasm_object *object, yasm_valparamhead *valparams,
+ /*@unused@*/ /*@null@*/
+ yasm_valparamhead *objext_valparams,
+ unsigned long line)
+{
+ yasm_valparam *vp;
+ yasm_section *retval;
+ int isnew;
+ int flags_override = 0;
+ const char *sectname;
+ bin_section_data *bsd = NULL;
+
+ struct bin_section_switch_data {
+ /*@only@*/ /*@null@*/ char *follows;
+ /*@only@*/ /*@null@*/ char *vfollows;
+ /*@only@*/ /*@null@*/ yasm_expr *start;
+ /*@only@*/ /*@null@*/ yasm_expr *vstart;
+ /*@only@*/ /*@null@*/ yasm_intnum *align;
+ /*@only@*/ /*@null@*/ yasm_intnum *valign;
+ unsigned long bss;
+ unsigned long code;
+ } data;
+
+ static const yasm_dir_help help[] = {
+ { "follows", 1, yasm_dir_helper_string,
+ offsetof(struct bin_section_switch_data, follows), 0 },
+ { "vfollows", 1, yasm_dir_helper_string,
+ offsetof(struct bin_section_switch_data, vfollows), 0 },
+ { "start", 1, yasm_dir_helper_expr,
+ offsetof(struct bin_section_switch_data, start), 0 },
+ { "vstart", 1, yasm_dir_helper_expr,
+ offsetof(struct bin_section_switch_data, vstart), 0 },
+ { "align", 1, yasm_dir_helper_intn,
+ offsetof(struct bin_section_switch_data, align), 0 },
+ { "valign", 1, yasm_dir_helper_intn,
+ offsetof(struct bin_section_switch_data, valign), 0 },
+ { "nobits", 0, yasm_dir_helper_flag_set,
+ offsetof(struct bin_section_switch_data, bss), 1 },
+ { "progbits", 0, yasm_dir_helper_flag_set,
+ offsetof(struct bin_section_switch_data, bss), 0 },
+ { "code", 0, yasm_dir_helper_flag_set,
+ offsetof(struct bin_section_switch_data, code), 1 },
+ { "data", 0, yasm_dir_helper_flag_set,
+ offsetof(struct bin_section_switch_data, code), 0 },
+ { "execute", 0, yasm_dir_helper_flag_set,
+ offsetof(struct bin_section_switch_data, code), 1 },
+ { "noexecute", 0, yasm_dir_helper_flag_set,
+ offsetof(struct bin_section_switch_data, code), 0 },
+ { "gasflags", 1, bin_helper_gasflags, 0, 0 }
+ };
+
+ vp = yasm_vps_first(valparams);
+ sectname = yasm_vp_string(vp);
+ if (!sectname)
+ return NULL;
+ vp = yasm_vps_next(vp);
+
+ retval = yasm_object_find_general(object, sectname);
+ if (retval) {
+ bsd = yasm_section_get_data(retval, &bin_section_data_cb);
+ assert(bsd != NULL);
+ data.follows = bsd->follows;
+ data.vfollows = bsd->vfollows;
+ data.start = bsd->start;
+ data.vstart = bsd->vstart;
+ data.align = NULL;
+ data.valign = NULL;
+ data.bss = bsd->bss;
+ data.code = yasm_section_is_code(retval);
+ } else {
+ data.follows = NULL;
+ data.vfollows = NULL;
+ data.start = NULL;
+ data.vstart = NULL;
+ data.align = NULL;
+ data.valign = NULL;
+ data.bss = strcmp(sectname, ".bss") == 0;
+ data.code = strcmp(sectname, ".text") == 0;
+ }
+
+ flags_override = yasm_dir_helper(object, vp, line, help, NELEMS(help),
+ &data, yasm_dir_helper_valparam_warn);
+ if (flags_override < 0)
+ return NULL; /* error occurred */
+
+ if (data.start && data.follows) {
+ yasm_error_set(YASM_ERROR_GENERAL,
+ N_("cannot combine `start' and `follows' section attributes"));
+ return NULL;
+ }
+
+ if (data.vstart && data.vfollows) {
+ yasm_error_set(YASM_ERROR_GENERAL,
+ N_("cannot combine `vstart' and `vfollows' section attributes"));
+ return NULL;
+ }
+
+ if (data.align) {
+ unsigned long align = yasm_intnum_get_uint(data.align);
+
+ /* Alignments must be a power of two. */
+ if (!is_exp2(align)) {
+ yasm_error_set(YASM_ERROR_VALUE,
+ N_("argument to `%s' is not a power of two"),
+ "align");
+ return NULL;
+ }
+ } else
+ data.align = bsd ? bsd->align : NULL;
+
+ if (data.valign) {
+ unsigned long valign = yasm_intnum_get_uint(data.valign);
+
+ /* Alignments must be a power of two. */
+ if (!is_exp2(valign)) {
+ yasm_error_set(YASM_ERROR_VALUE,
+ N_("argument to `%s' is not a power of two"),
+ "valign");
+ return NULL;
+ }
+ } else
+ data.valign = bsd ? bsd->valign : NULL;
+
+ retval = yasm_object_get_general(object, sectname, 0, (int)data.code,
+ (int)data.bss, &isnew, line);
+
+ bsd = yasm_section_get_data(retval, &bin_section_data_cb);
+
+ if (isnew || yasm_section_is_default(retval)) {
+ yasm_section_set_default(retval, 0);
+ }
+
+ /* Update section flags */
+ bsd->bss = data.bss;
+ bsd->align = data.align;
+ bsd->valign = data.valign;
+ bsd->start = data.start;
+ bsd->vstart = data.vstart;
+ bsd->follows = data.follows;
+ bsd->vfollows = data.vfollows;
+
+ return retval;
+}
+
+static /*@observer@*/ /*@null@*/ yasm_symrec *
+bin_objfmt_get_special_sym(yasm_object *object, const char *name,
+ const char *parser)
+{
+ return NULL;
+}
+
+static void
+bin_objfmt_dir_org(yasm_object *object,
+ /*@null@*/ yasm_valparamhead *valparams,
+ /*@unused@*/ /*@null@*/
+ yasm_valparamhead *objext_valparams, unsigned long line)
+{
+ yasm_objfmt_bin *objfmt_bin = (yasm_objfmt_bin *)object->objfmt;
+ yasm_valparam *vp;
+
+ /* We only allow a single ORG in a program. */
+ if (objfmt_bin->org) {
+ yasm_error_set(YASM_ERROR_GENERAL, N_("program origin redefined"));
+ return;
+ }
+
+ /* ORG takes just a simple expression as param */
+ vp = yasm_vps_first(valparams);
+ objfmt_bin->org = yasm_vp_expr(vp, object->symtab, line);
+ if (!objfmt_bin->org) {
+ yasm_error_set(YASM_ERROR_SYNTAX,
+ N_("argument to ORG must be expression"));
+ return;
+ }
+}
+
+struct bin_dir_map_data {
+ unsigned long flags;
+ /*@only@*/ /*@null@*/ char *filename;
+};
+
+static int
+dir_map_filename(void *obj, yasm_valparam *vp, unsigned long line, void *data)
+{
+ struct bin_dir_map_data *mdata = (struct bin_dir_map_data *)data;
+ const char *filename;
+
+ if (mdata->filename) {
+ yasm_warn_set(YASM_WARN_GENERAL, N_("map file already specified"));
+ return 0;
+ }
+
+ filename = yasm_vp_string(vp);
+ if (!filename) {
+ yasm_error_set(YASM_ERROR_SYNTAX,
+ N_("unexpected expression in [map]"));
+ return -1;
+ }
+ mdata->filename = yasm__xstrdup(filename);
+
+ return 1;
+}
+
+static void
+bin_objfmt_dir_map(yasm_object *object,
+ /*@null@*/ yasm_valparamhead *valparams,
+ /*@unused@*/ /*@null@*/
+ yasm_valparamhead *objext_valparams, unsigned long line)
+{
+ yasm_objfmt_bin *objfmt_bin = (yasm_objfmt_bin *)object->objfmt;
+
+ struct bin_dir_map_data data;
+
+ static const yasm_dir_help help[] = {
+ { "all", 0, yasm_dir_helper_flag_or,
+ offsetof(struct bin_dir_map_data, flags),
+ MAP_BRIEF|MAP_SECTIONS|MAP_SYMBOLS },
+ { "brief", 0, yasm_dir_helper_flag_or,
+ offsetof(struct bin_dir_map_data, flags), MAP_BRIEF },
+ { "sections", 0, yasm_dir_helper_flag_or,
+ offsetof(struct bin_dir_map_data, flags), MAP_SECTIONS },
+ { "segments", 0, yasm_dir_helper_flag_or,
+ offsetof(struct bin_dir_map_data, flags), MAP_SECTIONS },
+ { "symbols", 0, yasm_dir_helper_flag_or,
+ offsetof(struct bin_dir_map_data, flags), MAP_SYMBOLS }
+ };
+
+ data.flags = objfmt_bin->map_flags | MAP_NONE;
+ data.filename = objfmt_bin->map_filename;
+
+ if (valparams && yasm_dir_helper(object, yasm_vps_first(valparams), line, help,
+ NELEMS(help), &data, dir_map_filename) < 0)
+ return; /* error occurred */
+
+ objfmt_bin->map_flags = data.flags;
+ objfmt_bin->map_filename = data.filename;
+}
+
+static void
+bin_section_data_destroy(void *data)
+{
+ bin_section_data *bsd = (bin_section_data *)data;
+ if (bsd->start)
+ yasm_expr_destroy(bsd->start);
+ if (bsd->vstart)
+ yasm_expr_destroy(bsd->vstart);
+ if (bsd->follows)
+ yasm_xfree(bsd->follows);
+ if (bsd->vfollows)
+ yasm_xfree(bsd->vfollows);
+ if (bsd->istart)
+ yasm_intnum_destroy(bsd->istart);
+ if (bsd->ivstart)
+ yasm_intnum_destroy(bsd->ivstart);
+ if (bsd->length)
+ yasm_intnum_destroy(bsd->length);
+ yasm_xfree(data);
+}
+
+static void
+bin_section_data_print(void *data, FILE *f, int indent_level)
+{
+ bin_section_data *bsd = (bin_section_data *)data;
+
+ fprintf(f, "%*sbss=%d\n", indent_level, "", bsd->bss);
+
+ fprintf(f, "%*salign=", indent_level, "");
+ if (bsd->align)
+ yasm_intnum_print(bsd->align, f);
+ else
+ fprintf(f, "(nil)");
+ fprintf(f, "\n%*svalign=", indent_level, "");
+ if (bsd->valign)
+ yasm_intnum_print(bsd->valign, f);
+ else
+ fprintf(f, "(nil)");
+
+ fprintf(f, "\n%*sstart=", indent_level, "");
+ yasm_expr_print(bsd->start, f);
+ fprintf(f, "\n%*svstart=", indent_level, "");
+ yasm_expr_print(bsd->vstart, f);
+
+ fprintf(f, "\n%*sfollows=", indent_level, "");
+ if (bsd->follows)
+ fprintf(f, "\"%s\"", bsd->follows);
+ else
+ fprintf(f, "(nil)");
+ fprintf(f, "\n%*svfollows=", indent_level, "");
+ if (bsd->vfollows)
+ fprintf(f, "\"%s\"", bsd->vfollows);
+ else
+ fprintf(f, "(nil)");
+
+ fprintf(f, "\n%*sistart=", indent_level, "");
+ if (bsd->istart)
+ yasm_intnum_print(bsd->istart, f);
+ else
+ fprintf(f, "(nil)");
+ fprintf(f, "\n%*sivstart=", indent_level, "");
+ if (bsd->ivstart)
+ yasm_intnum_print(bsd->ivstart, f);
+ else
+ fprintf(f, "(nil)");
+
+ fprintf(f, "\n%*slength=", indent_level, "");
+ if (bsd->length)
+ yasm_intnum_print(bsd->length, f);
+ else
+ fprintf(f, "(nil)");
+ fprintf(f, "\n");
+}
+
+static void
+bin_symrec_data_destroy(void *data)
+{
+ yasm_xfree(data);
+}
+
+static void
+bin_symrec_data_print(void *data, FILE *f, int indent_level)
+{
+ bin_symrec_data *bsymd = (bin_symrec_data *)data;
+
+ fprintf(f, "%*ssection=\"%s\"\n", indent_level, "",
+ yasm_section_get_name(bsymd->section));
+ fprintf(f, "%*swhich=", indent_level, "");
+ switch (bsymd->which) {
+ case SSYM_START: fprintf(f, "START"); break;
+ case SSYM_VSTART: fprintf(f, "VSTART"); break;
+ case SSYM_LENGTH: fprintf(f, "LENGTH"); break;
+ }
+ fprintf(f, "\n");
+}
+
+
+/* Define valid debug formats to use with this object format */
+static const char *bin_objfmt_dbgfmt_keywords[] = {
+ "null",
+ NULL
+};
+
+static const yasm_directive bin_objfmt_directives[] = {
+ { "org", "nasm", bin_objfmt_dir_org, YASM_DIR_ARG_REQUIRED },
+ { "map", "nasm", bin_objfmt_dir_map, YASM_DIR_ANY },
+ { NULL, NULL, NULL, 0 }
+};
+
+static const char *bin_nasm_stdmac[] = {
+ "%imacro org 1+.nolist",
+ "[org %1]",
+ "%endmacro",
+ NULL
+};
+
+static const yasm_stdmac bin_objfmt_stdmacs[] = {
+ { "nasm", "nasm", bin_nasm_stdmac },
+ { "tasm", "tasm", bin_nasm_stdmac },
+ { NULL, NULL, NULL }
+};
+
+/* Define objfmt structure -- see objfmt.h for details */
+yasm_objfmt_module yasm_bin_LTX_objfmt = {
+ "Flat format binary",
+ "bin",
+ NULL,
+ 16,
+ 0,
+ bin_objfmt_dbgfmt_keywords,
+ "null",
+ bin_objfmt_directives,
+ bin_objfmt_stdmacs,
+ bin_objfmt_create,
+ bin_objfmt_output,
+ bin_objfmt_destroy,
+ bin_objfmt_add_default_section,
+ bin_objfmt_init_new_section,
+ bin_objfmt_section_switch,
+ bin_objfmt_get_special_sym
+};
+
+#define EXE_HEADER_SIZE 0x200
+
+/* DOS .EXE binaries are just raw binaries with a header */
+yasm_objfmt_module yasm_dosexe_LTX_objfmt;
+
+static yasm_objfmt *
+dosexe_objfmt_create(yasm_object *object)
+{
+ yasm_objfmt_bin *objfmt_bin = (yasm_objfmt_bin *) bin_objfmt_create(object);
+ objfmt_bin->objfmt.module = &yasm_dosexe_LTX_objfmt;
+ return (yasm_objfmt *)objfmt_bin;
+}
+
+static unsigned long
+get_sym(yasm_object *object, const char *name) {
+ yasm_symrec *symrec = yasm_symtab_get(object->symtab, name);
+ yasm_bytecode *prevbc;
+ if (!symrec)
+ return 0;
+ if (!yasm_symrec_get_label(symrec, &prevbc))
+ return 0;
+ return prevbc->offset + prevbc->len;
+}
+
+static void
+dosexe_objfmt_output(yasm_object *object, FILE *f, /*@unused@*/ int all_syms,
+ yasm_errwarns *errwarns)
+{
+ unsigned long tot_size, size, bss_size;
+ unsigned long start, bss;
+ unsigned char c;
+
+ fseek(f, EXE_HEADER_SIZE, SEEK_SET);
+
+ bin_objfmt_output(object, f, all_syms, errwarns);
+
+ tot_size = ftell(f);
+
+ /* if there is a __bss_start symbol, data after it is 0, no need to write
+ * it. */
+ bss = get_sym(object, "__bss_start");
+ if (bss)
+ size = bss;
+ else
+ size = tot_size;
+ bss_size = tot_size - size;
+#ifdef HAVE_FTRUNCATE
+ if (size != tot_size)
+ ftruncate(fileno(f), EXE_HEADER_SIZE + size);
+#endif
+ fseek(f, 0, SEEK_SET);
+
+ /* magic */
+ fwrite("MZ", 1, 2, f);
+
+ /* file size */
+ c = size & 0xff;
+ fwrite(&c, 1, 1, f);
+ c = !!(size & 0x100);
+ fwrite(&c, 1, 1, f);
+ c = ((size + 511) >> 9) & 0xff;
+ fwrite(&c, 1, 1, f);
+ c = ((size + 511) >> 17) & 0xff;
+ fwrite(&c, 1, 1, f);
+
+ /* relocation # */
+ c = 0;
+ fwrite(&c, 1, 1, f);
+ fwrite(&c, 1, 1, f);
+
+ /* header size */
+ c = EXE_HEADER_SIZE / 16;
+ fwrite(&c, 1, 1, f);
+ c = 0;
+ fwrite(&c, 1, 1, f);
+
+ /* minimum paragraph # */
+ bss_size = (bss_size + 15) >> 4;
+ c = bss_size & 0xff;
+ fwrite(&c, 1, 1, f);
+ c = (bss_size >> 8) & 0xff;
+ fwrite(&c, 1, 1, f);
+
+ /* maximum paragraph # */
+ c = 0xFF;
+ fwrite(&c, 1, 1, f);
+ fwrite(&c, 1, 1, f);
+
+ /* relative value of stack segment */
+ c = 0;
+ fwrite(&c, 1, 1, f);
+ fwrite(&c, 1, 1, f);
+
+ /* SP at start */
+ c = 0;
+ fwrite(&c, 1, 1, f);
+ fwrite(&c, 1, 1, f);
+
+ /* header checksum */
+ c = 0;
+ fwrite(&c, 1, 1, f);
+ fwrite(&c, 1, 1, f);
+
+ /* IP at start */
+ start = get_sym(object, "start");
+ if (!start) {
+ yasm_error_set(YASM_ERROR_GENERAL,
+ N_("%s: could not find symbol `start'"));
+ return;
+ }
+ c = start & 0xff;
+ fwrite(&c, 1, 1, f);
+ c = (start >> 8) & 0xff;
+ fwrite(&c, 1, 1, f);
+
+ /* CS start */
+ c = 0;
+ fwrite(&c, 1, 1, f);
+ fwrite(&c, 1, 1, f);
+
+ /* reloc start */
+ c = 0x22;
+ fwrite(&c, 1, 1, f);
+ c = 0;
+ fwrite(&c, 1, 1, f);
+
+ /* Overlay number */
+ c = 0;
+ fwrite(&c, 1, 1, f);
+ fwrite(&c, 1, 1, f);
+}
+
+
+/* Define objfmt structure -- see objfmt.h for details */
+yasm_objfmt_module yasm_dosexe_LTX_objfmt = {
+ "DOS .EXE format binary",
+ "dosexe",
+ "exe",
+ 16,
+ 0,
+ bin_objfmt_dbgfmt_keywords,
+ "null",
+ bin_objfmt_directives,
+ bin_objfmt_stdmacs,
+ dosexe_objfmt_create,
+ dosexe_objfmt_output,
+ bin_objfmt_destroy,
+ bin_objfmt_add_default_section,
+ bin_objfmt_init_new_section,
+ bin_objfmt_section_switch,
+ bin_objfmt_get_special_sym
+};