aboutsummaryrefslogtreecommitdiffstats
path: root/contrib/tools/yasm/modules/objfmts
diff options
context:
space:
mode:
authorsomov <somov@yandex-team.ru>2022-02-10 16:45:47 +0300
committerDaniil Cherednik <dcherednik@yandex-team.ru>2022-02-10 16:45:47 +0300
commita5950576e397b1909261050b8c7da16db58f10b1 (patch)
tree7ba7677f6a4c3e19e2cefab34d16df2c8963b4d4 /contrib/tools/yasm/modules/objfmts
parent81eddc8c0b55990194e112b02d127b87d54164a9 (diff)
downloadydb-a5950576e397b1909261050b8c7da16db58f10b1.tar.gz
Restoring authorship annotation for <somov@yandex-team.ru>. Commit 1 of 2.
Diffstat (limited to 'contrib/tools/yasm/modules/objfmts')
-rw-r--r--contrib/tools/yasm/modules/objfmts/bin/bin-objfmt.c3944
-rw-r--r--contrib/tools/yasm/modules/objfmts/coff/coff-objfmt.c5032
-rw-r--r--contrib/tools/yasm/modules/objfmts/coff/coff-objfmt.h154
-rw-r--r--contrib/tools/yasm/modules/objfmts/coff/win64-except.c1118
-rw-r--r--contrib/tools/yasm/modules/objfmts/dbg/dbg-objfmt.c366
-rw-r--r--contrib/tools/yasm/modules/objfmts/elf/elf-machine.h216
-rw-r--r--contrib/tools/yasm/modules/objfmts/elf/elf-objfmt.c2782
-rw-r--r--contrib/tools/yasm/modules/objfmts/elf/elf-x86-amd64.c512
-rw-r--r--contrib/tools/yasm/modules/objfmts/elf/elf-x86-x32.c502
-rw-r--r--contrib/tools/yasm/modules/objfmts/elf/elf-x86-x86.c484
-rw-r--r--contrib/tools/yasm/modules/objfmts/elf/elf.c1920
-rw-r--r--contrib/tools/yasm/modules/objfmts/elf/elf.h1064
-rw-r--r--contrib/tools/yasm/modules/objfmts/macho/macho-objfmt.c3240
-rw-r--r--contrib/tools/yasm/modules/objfmts/rdf/rdf-objfmt.c2176
-rw-r--r--contrib/tools/yasm/modules/objfmts/xdf/xdf-objfmt.c1684
15 files changed, 12597 insertions, 12597 deletions
diff --git a/contrib/tools/yasm/modules/objfmts/bin/bin-objfmt.c b/contrib/tools/yasm/modules/objfmts/bin/bin-objfmt.c
index 5f422245d3..702bda1590 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
+};
diff --git a/contrib/tools/yasm/modules/objfmts/coff/coff-objfmt.c b/contrib/tools/yasm/modules/objfmts/coff/coff-objfmt.c
index 388b09af32..80d9567e05 100644
--- a/contrib/tools/yasm/modules/objfmts/coff/coff-objfmt.c
+++ b/contrib/tools/yasm/modules/objfmts/coff/coff-objfmt.c
@@ -1,2522 +1,2522 @@
-/*
- * COFF (DJGPP) 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>
-#include <time.h>
-
-#include <libyasm.h>
-
-#include "coff-objfmt.h"
-
-
-#define REGULAR_OUTBUF_SIZE 1024
-
-/* Defining this to 0 sets all section VMA's to 0 rather than as the same as
- * the LMA. According to the DJGPP COFF Spec, this should be set to 1
- * (VMA=LMA), and indeed DJGPP's GCC output shows VMA=LMA. However, NASM
- * outputs VMA=0 (as if this was 0), and GNU objdump output looks a lot nicer
- * with VMA=0. Who's right? This is #defined as changing this setting affects
- * several places in the code.
- */
-#define COFF_SET_VMA (!objfmt_coff->win32)
-
-#define COFF_MACHINE_I386 0x014C
-#define COFF_MACHINE_AMD64 0x8664
-
-#define COFF_F_LNNO 0x0004 /* line number info NOT present */
-#define COFF_F_LSYMS 0x0008 /* local symbols NOT present */
-#define COFF_F_AR32WR 0x0100 /* 32-bit little endian file */
-
-typedef struct coff_reloc {
- yasm_reloc reloc;
- enum {
- COFF_RELOC_ABSOLUTE = 0, /* absolute, no reloc needed */
-
- /* I386 relocations */
- COFF_RELOC_I386_ADDR16 = 0x1, /* 16-bit absolute reference */
- COFF_RELOC_I386_REL16 = 0x2, /* 16-bit PC-relative reference */
- COFF_RELOC_I386_ADDR32 = 0x6, /* 32-bit absolute reference */
- COFF_RELOC_I386_ADDR32NB = 0x7, /* 32-bit absolute ref w/o base */
- COFF_RELOC_I386_SEG12 = 0x9, /* 16-bit absolute segment ref */
- COFF_RELOC_I386_SECTION = 0xA, /* section index */
- COFF_RELOC_I386_SECREL = 0xB, /* offset from start of segment */
- COFF_RELOC_I386_TOKEN = 0xC, /* CLR metadata token */
- COFF_RELOC_I386_SECREL7 = 0xD, /* 7-bit offset from base of sect */
- COFF_RELOC_I386_REL32 = 0x14, /* 32-bit PC-relative reference */
-
- /* AMD64 relocations */
- COFF_RELOC_AMD64_ADDR64 = 0x1, /* 64-bit address (VA) */
- COFF_RELOC_AMD64_ADDR32 = 0x2, /* 32-bit address (VA) */
- COFF_RELOC_AMD64_ADDR32NB = 0x3, /* 32-bit address w/o base (RVA) */
- COFF_RELOC_AMD64_REL32 = 0x4, /* 32-bit relative (0 byte dist) */
- COFF_RELOC_AMD64_REL32_1 = 0x5, /* 32-bit relative (1 byte dist) */
- COFF_RELOC_AMD64_REL32_2 = 0x6, /* 32-bit relative (2 byte dist) */
- COFF_RELOC_AMD64_REL32_3 = 0x7, /* 32-bit relative (3 byte dist) */
- COFF_RELOC_AMD64_REL32_4 = 0x8, /* 32-bit relative (4 byte dist) */
- COFF_RELOC_AMD64_REL32_5 = 0x9, /* 32-bit relative (5 byte dist) */
- COFF_RELOC_AMD64_SECTION = 0xA, /* section index */
- COFF_RELOC_AMD64_SECREL = 0xB, /* 32-bit offset from base of sect */
- COFF_RELOC_AMD64_SECREL7 = 0xC, /* 7-bit offset from base of sect */
- COFF_RELOC_AMD64_TOKEN = 0xD /* CLR metadata token */
- } type; /* type of relocation */
-} coff_reloc;
-
-#define COFF_STYP_TEXT 0x00000020UL
-#define COFF_STYP_DATA 0x00000040UL
-#define COFF_STYP_BSS 0x00000080UL
-#define COFF_STYP_INFO 0x00000200UL
-#define COFF_STYP_STD_MASK 0x000003FFUL
-#define COFF_STYP_ALIGN_MASK 0x00F00000UL
-#define COFF_STYP_ALIGN_SHIFT 20
-#define COFF_STYP_NRELOC_OVFL 0x01000000UL
-#define COFF_STYP_DISCARD 0x02000000UL
-#define COFF_STYP_NOCACHE 0x04000000UL
-#define COFF_STYP_NOPAGE 0x08000000UL
-#define COFF_STYP_SHARED 0x10000000UL
-#define COFF_STYP_EXECUTE 0x20000000UL
-#define COFF_STYP_READ 0x40000000UL
-#define COFF_STYP_WRITE 0x80000000UL
-#define COFF_STYP_WIN32_MASK 0xFF000000UL
-
-#define COFF_FLAG_NOBASE (1UL<<0) /* Use no-base (NB) relocs */
-
-typedef struct coff_section_data {
- /*@dependent@*/ yasm_symrec *sym; /* symbol created for this section */
- unsigned int scnum; /* section number (1=first section) */
- unsigned long flags; /* section flags (see COFF_STYP_* above) */
- unsigned long addr; /* starting memory address (first section -> 0) */
- unsigned long scnptr; /* file ptr to raw data */
- unsigned long size; /* size of raw data (section data) in bytes */
- unsigned long relptr; /* file ptr to relocation */
- unsigned long nreloc; /* number of relocation entries >64k -> error */
- unsigned long flags2; /* internal flags (see COFF_FLAG_* above) */
- unsigned long strtab_name; /* strtab offset of name if name > 8 chars */
- int isdebug; /* is a debug section? */
-} coff_section_data;
-
-typedef enum coff_symrec_sclass {
- COFF_SCL_EFCN = 0xff, /* physical end of function */
- COFF_SCL_NULL = 0,
- COFF_SCL_AUTO = 1, /* automatic variable */
- COFF_SCL_EXT = 2, /* external symbol */
- COFF_SCL_STAT = 3, /* static */
- COFF_SCL_REG = 4, /* register variable */
- COFF_SCL_EXTDEF = 5, /* external definition */
- COFF_SCL_LABEL = 6, /* label */
- COFF_SCL_ULABEL = 7, /* undefined label */
- COFF_SCL_MOS = 8, /* member of structure */
- COFF_SCL_ARG = 9, /* function argument */
- COFF_SCL_STRTAG = 10, /* structure tag */
- COFF_SCL_MOU = 11, /* member of union */
- COFF_SCL_UNTAG = 12, /* union tag */
- COFF_SCL_TPDEF = 13, /* type definition */
- COFF_SCL_USTATIC = 14, /* undefined static */
- COFF_SCL_ENTAG = 15, /* enumeration tag */
- COFF_SCL_MOE = 16, /* member of enumeration */
- COFF_SCL_REGPARM = 17, /* register parameter */
- COFF_SCL_FIELD = 18, /* bit field */
- COFF_SCL_AUTOARG = 19, /* auto argument */
- COFF_SCL_LASTENT = 20, /* dummy entry (end of block) */
- COFF_SCL_BLOCK = 100, /* ".bb" or ".eb" */
- COFF_SCL_FCN = 101, /* ".bf" or ".ef" */
- COFF_SCL_EOS = 102, /* end of structure */
- COFF_SCL_FILE = 103, /* file name */
- COFF_SCL_LINE = 104, /* line # reformatted as symbol table entry */
- COFF_SCL_ALIAS = 105, /* duplicate tag */
- COFF_SCL_HIDDEN = 106 /* ext symbol in dmert public lib */
-} coff_symrec_sclass;
-
-typedef union coff_symtab_auxent {
- /* no data needed for section symbol auxent, all info avail from sym */
- /*@owned@*/ char *fname; /* filename aux entry */
-} coff_symtab_auxent;
-
-typedef enum coff_symtab_auxtype {
- COFF_SYMTAB_AUX_NONE = 0,
- COFF_SYMTAB_AUX_SECT,
- COFF_SYMTAB_AUX_FILE
-} coff_symtab_auxtype;
-
-typedef struct coff_symrec_data {
- int forcevis; /* force visibility in symbol table */
- unsigned long index; /* assigned COFF symbol table index */
- unsigned int type; /* type */
- coff_symrec_sclass sclass; /* storage class */
-
- int numaux; /* number of auxiliary entries */
- coff_symtab_auxtype auxtype; /* type of aux entries */
- coff_symtab_auxent aux[1]; /* actually may be any size (including 0) */
-} coff_symrec_data;
-
-typedef struct yasm_objfmt_coff {
- yasm_objfmt_base objfmt; /* base structure */
-
- unsigned int parse_scnum; /* sect numbering in parser */
- int win32; /* nonzero for win32/64 output */
- int win64; /* nonzero for win64 output */
-
- unsigned int machine; /* COFF machine to use */
-
- coff_symrec_data *filesym_data; /* Data for .file symbol */
-
- /* data for .def/.endef and related directives */
- coff_symrec_data *def_sym; /* symbol specified by .def */
-
- /* data for win64 proc_frame and related directives */
- unsigned long proc_frame; /* Line number of start of proc, or 0 */
- unsigned long done_prolog; /* Line number of end of prologue, or 0 */
- /*@null@*/ coff_unwind_info *unwind; /* Unwind info */
-
- yasm_symrec *ssym_imagebase; /* ..imagebase symbol for win64 */
-} yasm_objfmt_coff;
-
-typedef struct coff_objfmt_output_info {
- yasm_object *object;
- yasm_objfmt_coff *objfmt_coff;
- yasm_errwarns *errwarns;
- /*@dependent@*/ FILE *f;
- /*@only@*/ unsigned char *buf;
- yasm_section *sect;
- /*@dependent@*/ coff_section_data *csd;
- unsigned long addr; /* start of next section */
-
- unsigned long indx; /* current symbol index */
- int all_syms; /* outputting all symbols? */
- unsigned long strtab_offset; /* current string table offset */
-} coff_objfmt_output_info;
-
-static void coff_section_data_destroy(/*@only@*/ void *d);
-static void coff_section_data_print(void *data, FILE *f, int indent_level);
-
-static const yasm_assoc_data_callback coff_section_data_cb = {
- coff_section_data_destroy,
- coff_section_data_print
-};
-
-static void coff_symrec_data_destroy(/*@only@*/ void *d);
-static void coff_symrec_data_print(void *data, FILE *f, int indent_level);
-
-static const yasm_assoc_data_callback coff_symrec_data_cb = {
- coff_symrec_data_destroy,
- coff_symrec_data_print
-};
-
-/* Bytecode callback function prototypes */
-static void win32_sxdata_bc_destroy(void *contents);
-static void win32_sxdata_bc_print(const void *contents, FILE *f,
- int indent_level);
-static int win32_sxdata_bc_calc_len
- (yasm_bytecode *bc, yasm_bc_add_span_func add_span, void *add_span_data);
-static int win32_sxdata_bc_tobytes
- (yasm_bytecode *bc, unsigned char **bufp, unsigned char *bufstart, void *d,
- yasm_output_value_func output_value,
- /*@null@*/ yasm_output_reloc_func output_reloc);
-
-/* Bytecode callback structures */
-static const yasm_bytecode_callback win32_sxdata_bc_callback = {
- win32_sxdata_bc_destroy,
- win32_sxdata_bc_print,
- yasm_bc_finalize_common,
- NULL,
- win32_sxdata_bc_calc_len,
- yasm_bc_expand_common,
- win32_sxdata_bc_tobytes,
- 0
-};
-
-yasm_objfmt_module yasm_coff_LTX_objfmt;
-yasm_objfmt_module yasm_win32_LTX_objfmt;
-yasm_objfmt_module yasm_win64_LTX_objfmt;
-
-
-static /*@dependent@*/ coff_symrec_data *
-coff_objfmt_sym_set_data(yasm_symrec *sym, coff_symrec_sclass sclass,
- int numaux, coff_symtab_auxtype auxtype)
-{
- coff_symrec_data *sym_data;
-
- sym_data = yasm_xmalloc(sizeof(coff_symrec_data) +
- (numaux-1)*sizeof(coff_symtab_auxent));
- sym_data->forcevis = 0;
- sym_data->index = 0;
- sym_data->type = 0;
- sym_data->sclass = sclass;
- sym_data->numaux = numaux;
- sym_data->auxtype = auxtype;
-
- yasm_symrec_add_data(sym, &coff_symrec_data_cb, sym_data);
-
- return sym_data;
-}
-
-static yasm_objfmt_coff *
-coff_common_create(yasm_object *object)
-{
- yasm_objfmt_coff *objfmt_coff = yasm_xmalloc(sizeof(yasm_objfmt_coff));
- yasm_symrec *filesym;
-
- /* Only support x86 arch */
- if (yasm__strcasecmp(yasm_arch_keyword(object->arch), "x86") != 0) {
- yasm_xfree(objfmt_coff);
- return NULL;
- }
-
- objfmt_coff->parse_scnum = 1; /* section numbering starts at 1 */
-
- /* FIXME: misuse of NULL bytecode here; it works, but only barely. */
- filesym = yasm_symtab_define_special(object->symtab, ".file",
- YASM_SYM_GLOBAL);
- objfmt_coff->filesym_data =
- coff_objfmt_sym_set_data(filesym, COFF_SCL_FILE, 1,
- COFF_SYMTAB_AUX_FILE);
- /* Filename is set in coff_objfmt_output */
- objfmt_coff->filesym_data->aux[0].fname = NULL;
-
- objfmt_coff->proc_frame = 0;
- objfmt_coff->done_prolog = 0;
- objfmt_coff->unwind = NULL;
- objfmt_coff->ssym_imagebase = NULL;
-
- return objfmt_coff;
-}
-
-static yasm_objfmt *
-coff_objfmt_create(yasm_object *object)
-{
- yasm_objfmt_coff *objfmt_coff = coff_common_create(object);
-
- if (objfmt_coff) {
- /* Support x86 and amd64 machines of x86 arch */
- if (yasm__strcasecmp(yasm_arch_get_machine(object->arch), "x86") == 0)
- objfmt_coff->machine = COFF_MACHINE_I386;
- else if (yasm__strcasecmp(yasm_arch_get_machine(object->arch),
- "amd64") == 0)
- objfmt_coff->machine = COFF_MACHINE_AMD64;
- else {
- yasm_xfree(objfmt_coff);
- return NULL;
- }
-
- objfmt_coff->objfmt.module = &yasm_coff_LTX_objfmt;
- objfmt_coff->win32 = 0;
- objfmt_coff->win64 = 0;
- }
- return (yasm_objfmt *)objfmt_coff;
-}
-
-static yasm_objfmt *
-win32_objfmt_create(yasm_object *object)
-{
- yasm_objfmt_coff *objfmt_coff = coff_common_create(object);
-
- if (objfmt_coff) {
- /* Support x86 and amd64 machines of x86 arch.
- * (amd64 machine supported for backwards compatibility)
- */
- if (yasm__strcasecmp(yasm_arch_get_machine(object->arch),
- "x86") == 0) {
- objfmt_coff->machine = COFF_MACHINE_I386;
- objfmt_coff->objfmt.module = &yasm_win32_LTX_objfmt;
- objfmt_coff->win64 = 0;
- } else if (yasm__strcasecmp(yasm_arch_get_machine(object->arch),
- "amd64") == 0) {
- objfmt_coff->machine = COFF_MACHINE_AMD64;
- objfmt_coff->objfmt.module = &yasm_win64_LTX_objfmt;
- objfmt_coff->win64 = 1;
- } else {
- yasm_xfree(objfmt_coff);
- return NULL;
- }
-
- objfmt_coff->win32 = 1;
- /* Define a @feat.00 symbol for win32 safeseh handling */
- if (!objfmt_coff->win64) {
- yasm_symrec *feat00;
- coff_symrec_data *sym_data;
- feat00 = yasm_symtab_define_equ(object->symtab, "@feat.00",
- yasm_expr_create_ident(yasm_expr_int(
- yasm_intnum_create_uint(1)), 0), 0);
- sym_data = coff_objfmt_sym_set_data(feat00, COFF_SCL_STAT, 0,
- COFF_SYMTAB_AUX_NONE);
- sym_data->forcevis = 1;
- }
- }
- return (yasm_objfmt *)objfmt_coff;
-}
-
-static yasm_objfmt *
-win64_objfmt_create(yasm_object *object)
-{
- yasm_objfmt_coff *objfmt_coff = coff_common_create(object);
-
- if (objfmt_coff) {
- /* Support amd64 machine of x86 arch */
- if (yasm__strcasecmp(yasm_arch_get_machine(object->arch),
- "amd64") == 0) {
- objfmt_coff->machine = COFF_MACHINE_AMD64;
- } else {
- yasm_xfree(objfmt_coff);
- return NULL;
- }
-
- objfmt_coff->objfmt.module = &yasm_win64_LTX_objfmt;
- objfmt_coff->win32 = 1;
- objfmt_coff->win64 = 1;
- objfmt_coff->ssym_imagebase =
- yasm_symtab_define_label(object->symtab, "..imagebase", NULL, 0, 0);
- }
- return (yasm_objfmt *)objfmt_coff;
-}
-
-static void
-coff_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_coff *objfmt_coff = (yasm_objfmt_coff *)object->objfmt;
- coff_section_data *data;
- yasm_symrec *sym;
-
- data = yasm_xmalloc(sizeof(coff_section_data));
- data->scnum = objfmt_coff->parse_scnum++;
- data->flags = 0;
- data->addr = 0;
- data->scnptr = 0;
- data->size = 0;
- data->relptr = 0;
- data->nreloc = 0;
- data->flags2 = 0;
- data->strtab_name = 0;
- data->isdebug = 0;
-
- if (yasm__strncasecmp(sectname, ".debug", 6)==0) {
- data->flags = COFF_STYP_DATA;
- if (objfmt_coff->win32)
- data->flags |= COFF_STYP_DISCARD|COFF_STYP_READ;
- data->isdebug = 1;
- } else
- data->flags = COFF_STYP_TEXT;
-
- yasm_section_add_data(sect, &coff_section_data_cb, data);
-
- sym = yasm_symtab_define_label(object->symtab, sectname,
- yasm_section_bcs_first(sect), 1, line);
- yasm_symrec_declare(sym, YASM_SYM_GLOBAL, line);
- coff_objfmt_sym_set_data(sym, COFF_SCL_STAT, 1, COFF_SYMTAB_AUX_SECT);
- data->sym = sym;
-}
-
-static int
-coff_objfmt_set_section_addr(yasm_section *sect, /*@null@*/ void *d)
-{
- /*@null@*/ coff_objfmt_output_info *info = (coff_objfmt_output_info *)d;
- /*@dependent@*/ /*@null@*/ coff_section_data *csd;
-
- assert(info != NULL);
- csd = yasm_section_get_data(sect, &coff_section_data_cb);
- assert(csd != NULL);
-
- csd->addr = info->addr;
- info->addr += yasm_bc_next_offset(yasm_section_bcs_last(sect));
-
- return 0;
-}
-
-static int
-coff_objfmt_output_value(yasm_value *value, unsigned char *buf,
- unsigned int destsize, unsigned long offset,
- yasm_bytecode *bc, int warn, /*@null@*/ void *d)
-{
- /*@null@*/ coff_objfmt_output_info *info = (coff_objfmt_output_info *)d;
- yasm_objfmt_coff *objfmt_coff;
- /*@only@*/ /*@null@*/ yasm_intnum *dist = NULL;
- /*@dependent@*/ /*@null@*/ yasm_intnum *intn;
- unsigned long intn_val, intn_minus;
- int retval;
- unsigned int valsize = value->size;
-
- assert(info != NULL);
- objfmt_coff = info->objfmt_coff;
-
- if (value->abs)
- value->abs = yasm_expr_simplify(value->abs, 1);
-
- /* Try to output constant and PC-relative section-local first.
- * Note this does NOT output any value with a SEG, WRT, external,
- * cross-section, or non-PC-relative reference (those are handled below).
- */
- switch (yasm_value_output_basic(value, buf, destsize, bc, warn,
- info->object->arch)) {
- case -1:
- return 1;
- case 0:
- break;
- default:
- return 0;
- }
-
- /* Handle other expressions, with relocation if necessary */
- if (value->rshift > 0
- || (value->seg_of && (value->wrt || value->curpos_rel))
- || (value->section_rel && (value->wrt || value->curpos_rel))) {
- yasm_error_set(YASM_ERROR_TOO_COMPLEX,
- N_("coff: relocation too complex"));
- return 1;
- }
-
- intn_val = 0;
- intn_minus = 0;
- if (value->rel) {
- yasm_sym_vis vis = yasm_symrec_get_visibility(value->rel);
- /*@dependent@*/ /*@null@*/ yasm_symrec *sym = value->rel;
- unsigned long addr;
- coff_reloc *reloc;
- int nobase = info->csd->flags2 & COFF_FLAG_NOBASE;
-
- /* Sometimes we want the relocation to be generated against one
- * symbol but the value generated correspond to a different symbol.
- * This is done through (sym being referenced) WRT (sym used for
- * reloc). Note both syms need to be in the same section!
- */
- if (value->wrt && value->wrt == objfmt_coff->ssym_imagebase)
- nobase = 1;
- else if (value->wrt) {
- /*@dependent@*/ /*@null@*/ yasm_bytecode *rel_precbc, *wrt_precbc;
-
- if (!yasm_symrec_get_label(sym, &rel_precbc)
- || !yasm_symrec_get_label(value->wrt, &wrt_precbc)) {
- yasm_error_set(YASM_ERROR_TOO_COMPLEX,
- N_("coff: wrt expression too complex"));
- return 1;
- }
- dist = yasm_calc_bc_dist(wrt_precbc, rel_precbc);
- if (!dist) {
- yasm_error_set(YASM_ERROR_TOO_COMPLEX,
- N_("coff: cannot wrt across sections"));
- return 1;
- }
- sym = value->wrt;
- }
-
- if (vis & YASM_SYM_COMMON) {
- /* In standard COFF, COMMON symbols have their length added in */
- if (!objfmt_coff->win32) {
- /*@dependent@*/ /*@null@*/ yasm_expr **csize_expr;
- /*@dependent@*/ /*@null@*/ yasm_intnum *common_size;
-
- csize_expr = yasm_symrec_get_common_size(sym);
- assert(csize_expr != NULL);
- common_size = yasm_expr_get_intnum(csize_expr, 1);
- if (!common_size) {
- yasm_error_set(YASM_ERROR_TOO_COMPLEX,
- N_("coff: common size too complex"));
- return 1;
- }
-
- if (yasm_intnum_sign(common_size) < 0) {
- yasm_error_set(YASM_ERROR_VALUE,
- N_("coff: common size is negative"));
- return 1;
- }
-
- intn_val += yasm_intnum_get_uint(common_size);
- }
- } else if (!(vis & YASM_SYM_EXTERN) && !objfmt_coff->win64) {
- /*@dependent@*/ /*@null@*/ yasm_bytecode *sym_precbc;
-
- /* Local symbols need relocation to their section's start */
- if (yasm_symrec_get_label(sym, &sym_precbc)) {
- yasm_section *sym_sect = yasm_bc_get_section(sym_precbc);
- /*@null@*/ coff_section_data *sym_csd;
- sym_csd = yasm_section_get_data(sym_sect,
- &coff_section_data_cb);
- assert(sym_csd != NULL);
- sym = sym_csd->sym;
- intn_val = yasm_bc_next_offset(sym_precbc);
- if (COFF_SET_VMA)
- intn_val += sym_csd->addr;
- }
- }
-
- if (value->curpos_rel) {
- /* For standard COFF, need to adjust to start of section, e.g.
- * subtract out the bytecode offset.
- * For Win32 COFF, need to adjust based on value size and position.
- * For Win64 COFF that's IP-relative, adjust to next bytecode;
- * the difference between the offset+destsize and BC length is
- * taken care of by special relocation types.
- */
- if (objfmt_coff->win64 && value->ip_rel)
- intn_val += bc->len*bc->mult_int;
- else if (objfmt_coff->win32)
- intn_val += offset+destsize;
- else
- intn_minus = bc->offset;
- }
-
- if (value->seg_of) {
- /* Segment generation; zero value. */
- intn_val = 0;
- intn_minus = 0;
- }
-
- /* Generate reloc */
- reloc = yasm_xmalloc(sizeof(coff_reloc));
- addr = bc->offset + offset;
- if (COFF_SET_VMA)
- addr += info->addr;
- reloc->reloc.addr = yasm_intnum_create_uint(addr);
- reloc->reloc.sym = sym;
-
- if (value->curpos_rel) {
- if (objfmt_coff->machine == COFF_MACHINE_I386) {
- if (valsize == 32)
- reloc->type = COFF_RELOC_I386_REL32;
- else {
- yasm_error_set(YASM_ERROR_TYPE,
- N_("coff: invalid relocation size"));
- return 1;
- }
- } else if (objfmt_coff->machine == COFF_MACHINE_AMD64) {
- if (valsize != 32) {
- yasm_error_set(YASM_ERROR_TYPE,
- N_("coff: invalid relocation size"));
- return 1;
- }
- if (!value->ip_rel)
- reloc->type = COFF_RELOC_AMD64_REL32;
- else switch (bc->len*bc->mult_int - (offset+destsize)) {
- case 0:
- reloc->type = COFF_RELOC_AMD64_REL32;
- break;
- case 1:
- reloc->type = COFF_RELOC_AMD64_REL32_1;
- break;
- case 2:
- reloc->type = COFF_RELOC_AMD64_REL32_2;
- break;
- case 3:
- reloc->type = COFF_RELOC_AMD64_REL32_3;
- break;
- case 4:
- reloc->type = COFF_RELOC_AMD64_REL32_4;
- break;
- case 5:
- reloc->type = COFF_RELOC_AMD64_REL32_5;
- break;
- default:
- yasm_error_set(YASM_ERROR_TYPE,
- N_("coff: invalid relocation size"));
- return 1;
- }
- } else
- yasm_internal_error(N_("coff objfmt: unrecognized machine"));
- } else if (value->seg_of) {
- if (objfmt_coff->machine == COFF_MACHINE_I386)
- reloc->type = COFF_RELOC_I386_SECTION;
- else if (objfmt_coff->machine == COFF_MACHINE_AMD64)
- reloc->type = COFF_RELOC_AMD64_SECTION;
- else
- yasm_internal_error(N_("coff objfmt: unrecognized machine"));
- } else if (value->section_rel) {
- if (objfmt_coff->machine == COFF_MACHINE_I386)
- reloc->type = COFF_RELOC_I386_SECREL;
- else if (objfmt_coff->machine == COFF_MACHINE_AMD64)
- reloc->type = COFF_RELOC_AMD64_SECREL;
- else
- yasm_internal_error(N_("coff objfmt: unrecognized machine"));
- } else {
- if (objfmt_coff->machine == COFF_MACHINE_I386) {
- if (nobase)
- reloc->type = COFF_RELOC_I386_ADDR32NB;
- else
- reloc->type = COFF_RELOC_I386_ADDR32;
- } else if (objfmt_coff->machine == COFF_MACHINE_AMD64) {
- if (valsize == 32) {
- if (nobase)
- reloc->type = COFF_RELOC_AMD64_ADDR32NB;
- else
- reloc->type = COFF_RELOC_AMD64_ADDR32;
- } else if (valsize == 64)
- reloc->type = COFF_RELOC_AMD64_ADDR64;
- else {
- yasm_error_set(YASM_ERROR_TYPE,
- N_("coff: invalid relocation size"));
- return 1;
- }
- } else
- yasm_internal_error(N_("coff objfmt: unrecognized machine"));
- }
- info->csd->nreloc++;
- yasm_section_add_reloc(info->sect, (yasm_reloc *)reloc, yasm_xfree);
- }
-
- /* Build up final integer output from intn_val, intn_minus, value->abs,
- * and dist. We do all this at the end to avoid creating temporary
- * intnums above (except for dist).
- */
- if (intn_minus <= intn_val)
- intn = yasm_intnum_create_uint(intn_val-intn_minus);
- else {
- intn = yasm_intnum_create_uint(intn_minus-intn_val);
- yasm_intnum_calc(intn, YASM_EXPR_NEG, NULL);
- }
-
- if (value->abs) {
- yasm_intnum *intn2 = yasm_expr_get_intnum(&value->abs, 0);
- if (!intn2) {
- yasm_error_set(YASM_ERROR_TOO_COMPLEX,
- N_("coff: relocation too complex"));
- yasm_intnum_destroy(intn);
- if (dist)
- yasm_intnum_destroy(dist);
- return 1;
- }
- yasm_intnum_calc(intn, YASM_EXPR_ADD, intn2);
- }
-
- if (dist) {
- yasm_intnum_calc(intn, YASM_EXPR_ADD, dist);
- yasm_intnum_destroy(dist);
- }
-
- retval = yasm_arch_intnum_tobytes(info->object->arch, intn, buf, destsize,
- valsize, 0, bc, warn);
- yasm_intnum_destroy(intn);
- return retval;
-}
-
-static int
-coff_objfmt_output_bytecode(yasm_bytecode *bc, /*@null@*/ void *d)
-{
- /*@null@*/ coff_objfmt_output_info *info = (coff_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,
- coff_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;
- }
-
- info->csd->size += size;
-
- /* 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;
-}
-
-static int
-coff_objfmt_output_section(yasm_section *sect, /*@null@*/ void *d)
-{
- /*@null@*/ coff_objfmt_output_info *info = (coff_objfmt_output_info *)d;
- /*@dependent@*/ /*@null@*/ coff_section_data *csd;
- long pos;
- coff_reloc *reloc;
- unsigned char *localbuf;
-
- assert(info != NULL);
- csd = yasm_section_get_data(sect, &coff_section_data_cb);
- assert(csd != NULL);
-
- /* Add to strtab if in win32 format and name > 8 chars */
- if (info->objfmt_coff->win32) {
- size_t namelen = strlen(yasm_section_get_name(sect));
- if (namelen > 8) {
- csd->strtab_name = info->strtab_offset;
- info->strtab_offset += (unsigned long)(namelen + 1);
- }
- }
-
- if (!csd->isdebug)
- csd->addr = info->addr;
-
- if ((csd->flags & COFF_STYP_STD_MASK) == COFF_STYP_BSS) {
- /* Don't output BSS sections.
- * TODO: Check for non-reserve bytecodes?
- */
- pos = 0; /* position = 0 because it's not in the file */
- csd->size = yasm_bc_next_offset(yasm_section_bcs_last(sect));
- } else {
- pos = ftell(info->f);
- if (pos == -1) {
- yasm__fatal(N_("could not get file position on output file"));
- /*@notreached@*/
- return 1;
- }
-
- info->sect = sect;
- info->csd = csd;
- yasm_section_bcs_traverse(sect, info->errwarns, info,
- coff_objfmt_output_bytecode);
-
- /* Sanity check final section size */
- if (yasm_errwarns_num_errors(info->errwarns, 0) == 0 &&
- csd->size != yasm_bc_next_offset(yasm_section_bcs_last(sect)))
- yasm_internal_error(
- N_("coff: section computed size did not match actual size"));
- }
-
- /* Empty? Go on to next section */
- if (csd->size == 0)
- return 0;
-
- if (!csd->isdebug)
- info->addr += csd->size;
- csd->scnptr = (unsigned long)pos;
-
- /* No relocations to output? Go on to next section */
- if (csd->nreloc == 0)
- return 0;
-
- pos = ftell(info->f);
- if (pos == -1) {
- yasm__fatal(N_("could not get file position on output file"));
- /*@notreached@*/
- return 1;
- }
- csd->relptr = (unsigned long)pos;
-
- /* If >=64K relocs (for Win32/64), we set a flag in the section header
- * (NRELOC_OVFL) and the first relocation contains the number of relocs.
- */
- if (csd->nreloc >= 64*1024 && info->objfmt_coff->win32) {
- localbuf = info->buf;
- YASM_WRITE_32_L(localbuf, csd->nreloc+1); /* address of relocation */
- YASM_WRITE_32_L(localbuf, 0); /* relocated symbol */
- YASM_WRITE_16_L(localbuf, 0); /* type of relocation */
- fwrite(info->buf, 10, 1, info->f);
- }
-
- reloc = (coff_reloc *)yasm_section_relocs_first(sect);
- while (reloc) {
- /*@null@*/ coff_symrec_data *csymd;
- localbuf = info->buf;
-
- csymd = yasm_symrec_get_data(reloc->reloc.sym, &coff_symrec_data_cb);
- if (!csymd)
- yasm_internal_error(
- N_("coff: no symbol data for relocated symbol"));
-
- yasm_intnum_get_sized(reloc->reloc.addr, localbuf, 4, 32, 0, 0, 0);
- localbuf += 4; /* address of relocation */
- YASM_WRITE_32_L(localbuf, csymd->index); /* relocated symbol */
- YASM_WRITE_16_L(localbuf, reloc->type); /* type of relocation */
- fwrite(info->buf, 10, 1, info->f);
-
- reloc = (coff_reloc *)yasm_section_reloc_next((yasm_reloc *)reloc);
- }
-
- return 0;
-}
-
-static int
-coff_objfmt_output_sectstr(yasm_section *sect, /*@null@*/ void *d)
-{
- /*@null@*/ coff_objfmt_output_info *info = (coff_objfmt_output_info *)d;
- const char *name;
- size_t len;
-
- /* Add to strtab if in win32 format and name > 8 chars */
- if (!info->objfmt_coff->win32)
- return 0;
-
- name = yasm_section_get_name(sect);
- len = strlen(name);
- if (len > 8)
- fwrite(name, len+1, 1, info->f);
- return 0;
-}
-
-static int
-coff_objfmt_output_secthead(yasm_section *sect, /*@null@*/ void *d)
-{
- /*@null@*/ coff_objfmt_output_info *info = (coff_objfmt_output_info *)d;
- yasm_objfmt_coff *objfmt_coff;
- /*@dependent@*/ /*@null@*/ coff_section_data *csd;
- unsigned char *localbuf;
- unsigned long align = yasm_section_get_align(sect);
-
- assert(info != NULL);
- objfmt_coff = info->objfmt_coff;
- csd = yasm_section_get_data(sect, &coff_section_data_cb);
- assert(csd != NULL);
-
- /* Check to see if alignment is supported size */
- if (align > 8192)
- align = 8192;
-
- /* Convert alignment into flags setting */
- csd->flags &= ~COFF_STYP_ALIGN_MASK;
- while (align != 0) {
- csd->flags += 1<<COFF_STYP_ALIGN_SHIFT;
- align >>= 1;
- }
-
- /* section name */
- localbuf = info->buf;
- if (strlen(yasm_section_get_name(sect)) > 8) {
- char namenum[30];
- sprintf(namenum, "/%ld", csd->strtab_name);
- strncpy((char *)localbuf, namenum, 8);
- } else
- strncpy((char *)localbuf, yasm_section_get_name(sect), 8);
- localbuf += 8;
- if (csd->isdebug) {
- YASM_WRITE_32_L(localbuf, 0); /* physical address */
- YASM_WRITE_32_L(localbuf, 0); /* virtual address */
- } else {
- YASM_WRITE_32_L(localbuf, csd->addr); /* physical address */
- if (COFF_SET_VMA)
- YASM_WRITE_32_L(localbuf, csd->addr);/* virtual address */
- else
- YASM_WRITE_32_L(localbuf, 0); /* virtual address */
- }
- YASM_WRITE_32_L(localbuf, csd->size); /* section size */
- YASM_WRITE_32_L(localbuf, csd->scnptr); /* file ptr to data */
- YASM_WRITE_32_L(localbuf, csd->relptr); /* file ptr to relocs */
- YASM_WRITE_32_L(localbuf, 0); /* file ptr to line nums */
- if (csd->nreloc >= 64*1024) {
- /* Win32/64 has special handling for this case. */
- if (objfmt_coff->win32)
- csd->flags |= COFF_STYP_NRELOC_OVFL;
- else {
- yasm_warn_set(YASM_WARN_GENERAL,
- N_("too many relocations in section `%s'"),
- yasm_section_get_name(sect));
- yasm_errwarn_propagate(info->errwarns, 0);
- }
- YASM_WRITE_16_L(localbuf, 0xFFFF); /* max out */
- } else
- YASM_WRITE_16_L(localbuf, csd->nreloc); /* num of relocation entries */
- YASM_WRITE_16_L(localbuf, 0); /* num of line number entries */
- YASM_WRITE_32_L(localbuf, csd->flags); /* flags */
- fwrite(info->buf, 40, 1, info->f);
-
- return 0;
-}
-
-static int
-coff_objfmt_count_sym(yasm_symrec *sym, /*@null@*/ void *d)
-{
- /*@null@*/ coff_objfmt_output_info *info = (coff_objfmt_output_info *)d;
- yasm_sym_vis vis = yasm_symrec_get_visibility(sym);
- coff_symrec_data *sym_data;
-
- assert(info != NULL);
-
- sym_data = yasm_symrec_get_data(sym, &coff_symrec_data_cb);
-
- if (info->all_syms || vis != YASM_SYM_LOCAL || yasm_symrec_is_abs(sym) ||
- (sym_data && sym_data->forcevis)) {
- /* Save index in symrec data */
- if (!sym_data)
- sym_data = coff_objfmt_sym_set_data(sym, COFF_SCL_NULL, 0,
- COFF_SYMTAB_AUX_NONE);
- /* Set storage class based on visibility if not already set */
- if (sym_data->sclass == COFF_SCL_NULL) {
- if (vis & (YASM_SYM_EXTERN|YASM_SYM_GLOBAL|YASM_SYM_COMMON))
- sym_data->sclass = COFF_SCL_EXT;
- else
- sym_data->sclass = COFF_SCL_STAT;
- }
-
- sym_data->index = info->indx;
-
- info->indx += sym_data->numaux + 1;
- }
- return 0;
-}
-
-static int
-coff_objfmt_output_sym(yasm_symrec *sym, /*@null@*/ void *d)
-{
- /*@null@*/ coff_objfmt_output_info *info = (coff_objfmt_output_info *)d;
- yasm_sym_vis vis = yasm_symrec_get_visibility(sym);
- int is_abs = yasm_symrec_is_abs(sym);
- /*@dependent@*/ /*@null@*/ coff_symrec_data *csymd;
- yasm_valparamhead *objext_valparams =
- yasm_symrec_get_objext_valparams(sym);
- csymd = yasm_symrec_get_data(sym, &coff_symrec_data_cb);
-
- assert(info != NULL);
-
- /* Look for "function" flag on global syms */
- if (csymd && csymd->type == 0 && (vis & YASM_SYM_GLOBAL) != 0) {
- if (objext_valparams) {
- const char *id = yasm_vp_id(yasm_vps_first(objext_valparams));
- if (yasm__strcasecmp(id, "function") == 0)
- csymd->type = 0x20;
- }
- }
-
- /* Don't output local syms unless outputting all syms */
- if (info->all_syms || vis != YASM_SYM_LOCAL || is_abs ||
- (csymd && csymd->forcevis)) {
- /*@only*/ char *name;
- const yasm_expr *equ_val;
- const yasm_intnum *intn;
- unsigned char *localbuf;
- size_t len;
- int aux;
- unsigned long value = 0;
- unsigned int scnum = 0xfffe; /* -2 = debugging symbol */
- /*@dependent@*/ /*@null@*/ yasm_section *sect;
- /*@dependent@*/ /*@null@*/ yasm_bytecode *precbc;
- unsigned long scnlen = 0; /* for sect auxent */
- unsigned long nreloc = 0; /* for sect auxent */
- yasm_objfmt_coff *objfmt_coff = info->objfmt_coff;
-
- if (is_abs)
- name = yasm__xstrdup(".absolut");
- else
- name = yasm_symrec_get_global_name(sym, info->object);
- len = strlen(name);
-
- /* Get symrec's of_data (needed for storage class) */
- if (!csymd)
- yasm_internal_error(N_("coff: expected sym data to be present"));
-
- /* Look at symrec for value/scnum/etc. */
- if (yasm_symrec_get_label(sym, &precbc)) {
- if (precbc)
- sect = yasm_bc_get_section(precbc);
- else
- sect = NULL;
- /* it's a label: get value and offset.
- * If there is not a section, leave as debugging symbol.
- */
- if (sect) {
- /*@dependent@*/ /*@null@*/ coff_section_data *csectd;
- csectd = yasm_section_get_data(sect, &coff_section_data_cb);
- if (csectd) {
- scnum = csectd->scnum;
- scnlen = csectd->size;
- nreloc = csectd->nreloc;
- if (COFF_SET_VMA)
- value = csectd->addr;
- } else
- yasm_internal_error(N_("didn't understand section"));
- if (precbc)
- value += yasm_bc_next_offset(precbc);
- }
- } else if ((equ_val = yasm_symrec_get_equ(sym))) {
- yasm_expr *equ_val_copy = yasm_expr_copy(equ_val);
- intn = yasm_expr_get_intnum(&equ_val_copy, 1);
- if (!intn) {
- if (vis & YASM_SYM_GLOBAL) {
- yasm_error_set(YASM_ERROR_NOT_CONSTANT,
- N_("global EQU value not an integer expression"));
- yasm_errwarn_propagate(info->errwarns, equ_val->line);
- }
- } else
- value = yasm_intnum_get_uint(intn);
- yasm_expr_destroy(equ_val_copy);
-
- scnum = 0xffff; /* -1 = absolute symbol */
- } else {
- if (vis & YASM_SYM_COMMON) {
- /*@dependent@*/ /*@null@*/ yasm_expr **csize_expr;
- csize_expr = yasm_symrec_get_common_size(sym);
- assert(csize_expr != NULL);
- intn = yasm_expr_get_intnum(csize_expr, 1);
- if (!intn) {
- yasm_error_set(YASM_ERROR_NOT_CONSTANT,
- N_("COMMON data size not an integer expression"));
- yasm_errwarn_propagate(info->errwarns,
- (*csize_expr)->line);
- } else
- value = yasm_intnum_get_uint(intn);
- scnum = 0;
- }
- if (vis & YASM_SYM_EXTERN)
- scnum = 0;
- }
-
- localbuf = info->buf;
- if (len > 8) {
- YASM_WRITE_32_L(localbuf, 0); /* "zeros" field */
- YASM_WRITE_32_L(localbuf, info->strtab_offset); /* strtab offset */
- info->strtab_offset += (unsigned long)(len+1);
- } else {
- /* <8 chars, so no string table entry needed */
- strncpy((char *)localbuf, name, 8);
- localbuf += 8;
- }
- YASM_WRITE_32_L(localbuf, value); /* value */
- YASM_WRITE_16_L(localbuf, scnum); /* section number */
- YASM_WRITE_16_L(localbuf, csymd->type); /* type */
- YASM_WRITE_8(localbuf, csymd->sclass); /* storage class */
- YASM_WRITE_8(localbuf, csymd->numaux); /* number of aux entries */
- fwrite(info->buf, 18, 1, info->f);
- for (aux=0; aux<csymd->numaux; aux++) {
- localbuf = info->buf;
- memset(localbuf, 0, 18);
- switch (csymd->auxtype) {
- case COFF_SYMTAB_AUX_NONE:
- break;
- case COFF_SYMTAB_AUX_SECT:
- YASM_WRITE_32_L(localbuf, scnlen); /* section length */
- YASM_WRITE_16_L(localbuf, nreloc); /* number relocs */
- YASM_WRITE_16_L(localbuf, 0); /* number line nums */
- break;
- case COFF_SYMTAB_AUX_FILE:
- len = strlen(csymd->aux[0].fname);
- if (len > 14) {
- YASM_WRITE_32_L(localbuf, 0);
- YASM_WRITE_32_L(localbuf, info->strtab_offset);
- info->strtab_offset += (unsigned long)(len+1);
- } else
- strncpy((char *)localbuf, csymd->aux[0].fname, 14);
- break;
- default:
- yasm_internal_error(
- N_("coff: unrecognized aux symtab type"));
- }
- fwrite(info->buf, 18, 1, info->f);
- }
- yasm_xfree(name);
- }
- return 0;
-}
-
-static int
-coff_objfmt_output_str(yasm_symrec *sym, /*@null@*/ void *d)
-{
- /*@null@*/ coff_objfmt_output_info *info = (coff_objfmt_output_info *)d;
- yasm_sym_vis vis = yasm_symrec_get_visibility(sym);
- /*@dependent@*/ /*@null@*/ coff_symrec_data *csymd;
- csymd = yasm_symrec_get_data(sym, &coff_symrec_data_cb);
-
- assert(info != NULL);
-
- /* Don't output local syms unless outputting all syms */
- if (info->all_syms || vis != YASM_SYM_LOCAL ||
- (csymd && csymd->forcevis)) {
- /*@only@*/ char *name = yasm_symrec_get_global_name(sym, info->object);
- size_t len = strlen(name);
- int aux;
-
- if (!csymd)
- yasm_internal_error(N_("coff: expected sym data to be present"));
-
- if (len > 8)
- fwrite(name, len+1, 1, info->f);
- for (aux=0; aux<csymd->numaux; aux++) {
- switch (csymd->auxtype) {
- case COFF_SYMTAB_AUX_FILE:
- len = strlen(csymd->aux[0].fname);
- if (len > 14)
- fwrite(csymd->aux[0].fname, len+1, 1, info->f);
- break;
- default:
- break;
- }
- }
- yasm_xfree(name);
- }
- return 0;
-}
-
-static void
-coff_objfmt_output(yasm_object *object, FILE *f, int all_syms,
- yasm_errwarns *errwarns)
-{
- yasm_objfmt_coff *objfmt_coff = (yasm_objfmt_coff *)object->objfmt;
- coff_objfmt_output_info info;
- unsigned char *localbuf;
- long pos;
- unsigned long symtab_pos;
- unsigned long symtab_count;
- unsigned int flags;
- unsigned long ts;
-
- if (objfmt_coff->proc_frame) {
- yasm_error_set_xref(objfmt_coff->proc_frame,
- N_("procedure started here"));
- yasm_error_set(YASM_ERROR_GENERAL,
- N_("end of file in procedure frame"));
- yasm_errwarn_propagate(errwarns, 0);
- return;
- }
-
- if (objfmt_coff->filesym_data->aux[0].fname)
- yasm_xfree(objfmt_coff->filesym_data->aux[0].fname);
+/*
+ * COFF (DJGPP) 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>
+#include <time.h>
+
+#include <libyasm.h>
+
+#include "coff-objfmt.h"
+
+
+#define REGULAR_OUTBUF_SIZE 1024
+
+/* Defining this to 0 sets all section VMA's to 0 rather than as the same as
+ * the LMA. According to the DJGPP COFF Spec, this should be set to 1
+ * (VMA=LMA), and indeed DJGPP's GCC output shows VMA=LMA. However, NASM
+ * outputs VMA=0 (as if this was 0), and GNU objdump output looks a lot nicer
+ * with VMA=0. Who's right? This is #defined as changing this setting affects
+ * several places in the code.
+ */
+#define COFF_SET_VMA (!objfmt_coff->win32)
+
+#define COFF_MACHINE_I386 0x014C
+#define COFF_MACHINE_AMD64 0x8664
+
+#define COFF_F_LNNO 0x0004 /* line number info NOT present */
+#define COFF_F_LSYMS 0x0008 /* local symbols NOT present */
+#define COFF_F_AR32WR 0x0100 /* 32-bit little endian file */
+
+typedef struct coff_reloc {
+ yasm_reloc reloc;
+ enum {
+ COFF_RELOC_ABSOLUTE = 0, /* absolute, no reloc needed */
+
+ /* I386 relocations */
+ COFF_RELOC_I386_ADDR16 = 0x1, /* 16-bit absolute reference */
+ COFF_RELOC_I386_REL16 = 0x2, /* 16-bit PC-relative reference */
+ COFF_RELOC_I386_ADDR32 = 0x6, /* 32-bit absolute reference */
+ COFF_RELOC_I386_ADDR32NB = 0x7, /* 32-bit absolute ref w/o base */
+ COFF_RELOC_I386_SEG12 = 0x9, /* 16-bit absolute segment ref */
+ COFF_RELOC_I386_SECTION = 0xA, /* section index */
+ COFF_RELOC_I386_SECREL = 0xB, /* offset from start of segment */
+ COFF_RELOC_I386_TOKEN = 0xC, /* CLR metadata token */
+ COFF_RELOC_I386_SECREL7 = 0xD, /* 7-bit offset from base of sect */
+ COFF_RELOC_I386_REL32 = 0x14, /* 32-bit PC-relative reference */
+
+ /* AMD64 relocations */
+ COFF_RELOC_AMD64_ADDR64 = 0x1, /* 64-bit address (VA) */
+ COFF_RELOC_AMD64_ADDR32 = 0x2, /* 32-bit address (VA) */
+ COFF_RELOC_AMD64_ADDR32NB = 0x3, /* 32-bit address w/o base (RVA) */
+ COFF_RELOC_AMD64_REL32 = 0x4, /* 32-bit relative (0 byte dist) */
+ COFF_RELOC_AMD64_REL32_1 = 0x5, /* 32-bit relative (1 byte dist) */
+ COFF_RELOC_AMD64_REL32_2 = 0x6, /* 32-bit relative (2 byte dist) */
+ COFF_RELOC_AMD64_REL32_3 = 0x7, /* 32-bit relative (3 byte dist) */
+ COFF_RELOC_AMD64_REL32_4 = 0x8, /* 32-bit relative (4 byte dist) */
+ COFF_RELOC_AMD64_REL32_5 = 0x9, /* 32-bit relative (5 byte dist) */
+ COFF_RELOC_AMD64_SECTION = 0xA, /* section index */
+ COFF_RELOC_AMD64_SECREL = 0xB, /* 32-bit offset from base of sect */
+ COFF_RELOC_AMD64_SECREL7 = 0xC, /* 7-bit offset from base of sect */
+ COFF_RELOC_AMD64_TOKEN = 0xD /* CLR metadata token */
+ } type; /* type of relocation */
+} coff_reloc;
+
+#define COFF_STYP_TEXT 0x00000020UL
+#define COFF_STYP_DATA 0x00000040UL
+#define COFF_STYP_BSS 0x00000080UL
+#define COFF_STYP_INFO 0x00000200UL
+#define COFF_STYP_STD_MASK 0x000003FFUL
+#define COFF_STYP_ALIGN_MASK 0x00F00000UL
+#define COFF_STYP_ALIGN_SHIFT 20
+#define COFF_STYP_NRELOC_OVFL 0x01000000UL
+#define COFF_STYP_DISCARD 0x02000000UL
+#define COFF_STYP_NOCACHE 0x04000000UL
+#define COFF_STYP_NOPAGE 0x08000000UL
+#define COFF_STYP_SHARED 0x10000000UL
+#define COFF_STYP_EXECUTE 0x20000000UL
+#define COFF_STYP_READ 0x40000000UL
+#define COFF_STYP_WRITE 0x80000000UL
+#define COFF_STYP_WIN32_MASK 0xFF000000UL
+
+#define COFF_FLAG_NOBASE (1UL<<0) /* Use no-base (NB) relocs */
+
+typedef struct coff_section_data {
+ /*@dependent@*/ yasm_symrec *sym; /* symbol created for this section */
+ unsigned int scnum; /* section number (1=first section) */
+ unsigned long flags; /* section flags (see COFF_STYP_* above) */
+ unsigned long addr; /* starting memory address (first section -> 0) */
+ unsigned long scnptr; /* file ptr to raw data */
+ unsigned long size; /* size of raw data (section data) in bytes */
+ unsigned long relptr; /* file ptr to relocation */
+ unsigned long nreloc; /* number of relocation entries >64k -> error */
+ unsigned long flags2; /* internal flags (see COFF_FLAG_* above) */
+ unsigned long strtab_name; /* strtab offset of name if name > 8 chars */
+ int isdebug; /* is a debug section? */
+} coff_section_data;
+
+typedef enum coff_symrec_sclass {
+ COFF_SCL_EFCN = 0xff, /* physical end of function */
+ COFF_SCL_NULL = 0,
+ COFF_SCL_AUTO = 1, /* automatic variable */
+ COFF_SCL_EXT = 2, /* external symbol */
+ COFF_SCL_STAT = 3, /* static */
+ COFF_SCL_REG = 4, /* register variable */
+ COFF_SCL_EXTDEF = 5, /* external definition */
+ COFF_SCL_LABEL = 6, /* label */
+ COFF_SCL_ULABEL = 7, /* undefined label */
+ COFF_SCL_MOS = 8, /* member of structure */
+ COFF_SCL_ARG = 9, /* function argument */
+ COFF_SCL_STRTAG = 10, /* structure tag */
+ COFF_SCL_MOU = 11, /* member of union */
+ COFF_SCL_UNTAG = 12, /* union tag */
+ COFF_SCL_TPDEF = 13, /* type definition */
+ COFF_SCL_USTATIC = 14, /* undefined static */
+ COFF_SCL_ENTAG = 15, /* enumeration tag */
+ COFF_SCL_MOE = 16, /* member of enumeration */
+ COFF_SCL_REGPARM = 17, /* register parameter */
+ COFF_SCL_FIELD = 18, /* bit field */
+ COFF_SCL_AUTOARG = 19, /* auto argument */
+ COFF_SCL_LASTENT = 20, /* dummy entry (end of block) */
+ COFF_SCL_BLOCK = 100, /* ".bb" or ".eb" */
+ COFF_SCL_FCN = 101, /* ".bf" or ".ef" */
+ COFF_SCL_EOS = 102, /* end of structure */
+ COFF_SCL_FILE = 103, /* file name */
+ COFF_SCL_LINE = 104, /* line # reformatted as symbol table entry */
+ COFF_SCL_ALIAS = 105, /* duplicate tag */
+ COFF_SCL_HIDDEN = 106 /* ext symbol in dmert public lib */
+} coff_symrec_sclass;
+
+typedef union coff_symtab_auxent {
+ /* no data needed for section symbol auxent, all info avail from sym */
+ /*@owned@*/ char *fname; /* filename aux entry */
+} coff_symtab_auxent;
+
+typedef enum coff_symtab_auxtype {
+ COFF_SYMTAB_AUX_NONE = 0,
+ COFF_SYMTAB_AUX_SECT,
+ COFF_SYMTAB_AUX_FILE
+} coff_symtab_auxtype;
+
+typedef struct coff_symrec_data {
+ int forcevis; /* force visibility in symbol table */
+ unsigned long index; /* assigned COFF symbol table index */
+ unsigned int type; /* type */
+ coff_symrec_sclass sclass; /* storage class */
+
+ int numaux; /* number of auxiliary entries */
+ coff_symtab_auxtype auxtype; /* type of aux entries */
+ coff_symtab_auxent aux[1]; /* actually may be any size (including 0) */
+} coff_symrec_data;
+
+typedef struct yasm_objfmt_coff {
+ yasm_objfmt_base objfmt; /* base structure */
+
+ unsigned int parse_scnum; /* sect numbering in parser */
+ int win32; /* nonzero for win32/64 output */
+ int win64; /* nonzero for win64 output */
+
+ unsigned int machine; /* COFF machine to use */
+
+ coff_symrec_data *filesym_data; /* Data for .file symbol */
+
+ /* data for .def/.endef and related directives */
+ coff_symrec_data *def_sym; /* symbol specified by .def */
+
+ /* data for win64 proc_frame and related directives */
+ unsigned long proc_frame; /* Line number of start of proc, or 0 */
+ unsigned long done_prolog; /* Line number of end of prologue, or 0 */
+ /*@null@*/ coff_unwind_info *unwind; /* Unwind info */
+
+ yasm_symrec *ssym_imagebase; /* ..imagebase symbol for win64 */
+} yasm_objfmt_coff;
+
+typedef struct coff_objfmt_output_info {
+ yasm_object *object;
+ yasm_objfmt_coff *objfmt_coff;
+ yasm_errwarns *errwarns;
+ /*@dependent@*/ FILE *f;
+ /*@only@*/ unsigned char *buf;
+ yasm_section *sect;
+ /*@dependent@*/ coff_section_data *csd;
+ unsigned long addr; /* start of next section */
+
+ unsigned long indx; /* current symbol index */
+ int all_syms; /* outputting all symbols? */
+ unsigned long strtab_offset; /* current string table offset */
+} coff_objfmt_output_info;
+
+static void coff_section_data_destroy(/*@only@*/ void *d);
+static void coff_section_data_print(void *data, FILE *f, int indent_level);
+
+static const yasm_assoc_data_callback coff_section_data_cb = {
+ coff_section_data_destroy,
+ coff_section_data_print
+};
+
+static void coff_symrec_data_destroy(/*@only@*/ void *d);
+static void coff_symrec_data_print(void *data, FILE *f, int indent_level);
+
+static const yasm_assoc_data_callback coff_symrec_data_cb = {
+ coff_symrec_data_destroy,
+ coff_symrec_data_print
+};
+
+/* Bytecode callback function prototypes */
+static void win32_sxdata_bc_destroy(void *contents);
+static void win32_sxdata_bc_print(const void *contents, FILE *f,
+ int indent_level);
+static int win32_sxdata_bc_calc_len
+ (yasm_bytecode *bc, yasm_bc_add_span_func add_span, void *add_span_data);
+static int win32_sxdata_bc_tobytes
+ (yasm_bytecode *bc, unsigned char **bufp, unsigned char *bufstart, void *d,
+ yasm_output_value_func output_value,
+ /*@null@*/ yasm_output_reloc_func output_reloc);
+
+/* Bytecode callback structures */
+static const yasm_bytecode_callback win32_sxdata_bc_callback = {
+ win32_sxdata_bc_destroy,
+ win32_sxdata_bc_print,
+ yasm_bc_finalize_common,
+ NULL,
+ win32_sxdata_bc_calc_len,
+ yasm_bc_expand_common,
+ win32_sxdata_bc_tobytes,
+ 0
+};
+
+yasm_objfmt_module yasm_coff_LTX_objfmt;
+yasm_objfmt_module yasm_win32_LTX_objfmt;
+yasm_objfmt_module yasm_win64_LTX_objfmt;
+
+
+static /*@dependent@*/ coff_symrec_data *
+coff_objfmt_sym_set_data(yasm_symrec *sym, coff_symrec_sclass sclass,
+ int numaux, coff_symtab_auxtype auxtype)
+{
+ coff_symrec_data *sym_data;
+
+ sym_data = yasm_xmalloc(sizeof(coff_symrec_data) +
+ (numaux-1)*sizeof(coff_symtab_auxent));
+ sym_data->forcevis = 0;
+ sym_data->index = 0;
+ sym_data->type = 0;
+ sym_data->sclass = sclass;
+ sym_data->numaux = numaux;
+ sym_data->auxtype = auxtype;
+
+ yasm_symrec_add_data(sym, &coff_symrec_data_cb, sym_data);
+
+ return sym_data;
+}
+
+static yasm_objfmt_coff *
+coff_common_create(yasm_object *object)
+{
+ yasm_objfmt_coff *objfmt_coff = yasm_xmalloc(sizeof(yasm_objfmt_coff));
+ yasm_symrec *filesym;
+
+ /* Only support x86 arch */
+ if (yasm__strcasecmp(yasm_arch_keyword(object->arch), "x86") != 0) {
+ yasm_xfree(objfmt_coff);
+ return NULL;
+ }
+
+ objfmt_coff->parse_scnum = 1; /* section numbering starts at 1 */
+
+ /* FIXME: misuse of NULL bytecode here; it works, but only barely. */
+ filesym = yasm_symtab_define_special(object->symtab, ".file",
+ YASM_SYM_GLOBAL);
+ objfmt_coff->filesym_data =
+ coff_objfmt_sym_set_data(filesym, COFF_SCL_FILE, 1,
+ COFF_SYMTAB_AUX_FILE);
+ /* Filename is set in coff_objfmt_output */
+ objfmt_coff->filesym_data->aux[0].fname = NULL;
+
+ objfmt_coff->proc_frame = 0;
+ objfmt_coff->done_prolog = 0;
+ objfmt_coff->unwind = NULL;
+ objfmt_coff->ssym_imagebase = NULL;
+
+ return objfmt_coff;
+}
+
+static yasm_objfmt *
+coff_objfmt_create(yasm_object *object)
+{
+ yasm_objfmt_coff *objfmt_coff = coff_common_create(object);
+
+ if (objfmt_coff) {
+ /* Support x86 and amd64 machines of x86 arch */
+ if (yasm__strcasecmp(yasm_arch_get_machine(object->arch), "x86") == 0)
+ objfmt_coff->machine = COFF_MACHINE_I386;
+ else if (yasm__strcasecmp(yasm_arch_get_machine(object->arch),
+ "amd64") == 0)
+ objfmt_coff->machine = COFF_MACHINE_AMD64;
+ else {
+ yasm_xfree(objfmt_coff);
+ return NULL;
+ }
+
+ objfmt_coff->objfmt.module = &yasm_coff_LTX_objfmt;
+ objfmt_coff->win32 = 0;
+ objfmt_coff->win64 = 0;
+ }
+ return (yasm_objfmt *)objfmt_coff;
+}
+
+static yasm_objfmt *
+win32_objfmt_create(yasm_object *object)
+{
+ yasm_objfmt_coff *objfmt_coff = coff_common_create(object);
+
+ if (objfmt_coff) {
+ /* Support x86 and amd64 machines of x86 arch.
+ * (amd64 machine supported for backwards compatibility)
+ */
+ if (yasm__strcasecmp(yasm_arch_get_machine(object->arch),
+ "x86") == 0) {
+ objfmt_coff->machine = COFF_MACHINE_I386;
+ objfmt_coff->objfmt.module = &yasm_win32_LTX_objfmt;
+ objfmt_coff->win64 = 0;
+ } else if (yasm__strcasecmp(yasm_arch_get_machine(object->arch),
+ "amd64") == 0) {
+ objfmt_coff->machine = COFF_MACHINE_AMD64;
+ objfmt_coff->objfmt.module = &yasm_win64_LTX_objfmt;
+ objfmt_coff->win64 = 1;
+ } else {
+ yasm_xfree(objfmt_coff);
+ return NULL;
+ }
+
+ objfmt_coff->win32 = 1;
+ /* Define a @feat.00 symbol for win32 safeseh handling */
+ if (!objfmt_coff->win64) {
+ yasm_symrec *feat00;
+ coff_symrec_data *sym_data;
+ feat00 = yasm_symtab_define_equ(object->symtab, "@feat.00",
+ yasm_expr_create_ident(yasm_expr_int(
+ yasm_intnum_create_uint(1)), 0), 0);
+ sym_data = coff_objfmt_sym_set_data(feat00, COFF_SCL_STAT, 0,
+ COFF_SYMTAB_AUX_NONE);
+ sym_data->forcevis = 1;
+ }
+ }
+ return (yasm_objfmt *)objfmt_coff;
+}
+
+static yasm_objfmt *
+win64_objfmt_create(yasm_object *object)
+{
+ yasm_objfmt_coff *objfmt_coff = coff_common_create(object);
+
+ if (objfmt_coff) {
+ /* Support amd64 machine of x86 arch */
+ if (yasm__strcasecmp(yasm_arch_get_machine(object->arch),
+ "amd64") == 0) {
+ objfmt_coff->machine = COFF_MACHINE_AMD64;
+ } else {
+ yasm_xfree(objfmt_coff);
+ return NULL;
+ }
+
+ objfmt_coff->objfmt.module = &yasm_win64_LTX_objfmt;
+ objfmt_coff->win32 = 1;
+ objfmt_coff->win64 = 1;
+ objfmt_coff->ssym_imagebase =
+ yasm_symtab_define_label(object->symtab, "..imagebase", NULL, 0, 0);
+ }
+ return (yasm_objfmt *)objfmt_coff;
+}
+
+static void
+coff_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_coff *objfmt_coff = (yasm_objfmt_coff *)object->objfmt;
+ coff_section_data *data;
+ yasm_symrec *sym;
+
+ data = yasm_xmalloc(sizeof(coff_section_data));
+ data->scnum = objfmt_coff->parse_scnum++;
+ data->flags = 0;
+ data->addr = 0;
+ data->scnptr = 0;
+ data->size = 0;
+ data->relptr = 0;
+ data->nreloc = 0;
+ data->flags2 = 0;
+ data->strtab_name = 0;
+ data->isdebug = 0;
+
+ if (yasm__strncasecmp(sectname, ".debug", 6)==0) {
+ data->flags = COFF_STYP_DATA;
+ if (objfmt_coff->win32)
+ data->flags |= COFF_STYP_DISCARD|COFF_STYP_READ;
+ data->isdebug = 1;
+ } else
+ data->flags = COFF_STYP_TEXT;
+
+ yasm_section_add_data(sect, &coff_section_data_cb, data);
+
+ sym = yasm_symtab_define_label(object->symtab, sectname,
+ yasm_section_bcs_first(sect), 1, line);
+ yasm_symrec_declare(sym, YASM_SYM_GLOBAL, line);
+ coff_objfmt_sym_set_data(sym, COFF_SCL_STAT, 1, COFF_SYMTAB_AUX_SECT);
+ data->sym = sym;
+}
+
+static int
+coff_objfmt_set_section_addr(yasm_section *sect, /*@null@*/ void *d)
+{
+ /*@null@*/ coff_objfmt_output_info *info = (coff_objfmt_output_info *)d;
+ /*@dependent@*/ /*@null@*/ coff_section_data *csd;
+
+ assert(info != NULL);
+ csd = yasm_section_get_data(sect, &coff_section_data_cb);
+ assert(csd != NULL);
+
+ csd->addr = info->addr;
+ info->addr += yasm_bc_next_offset(yasm_section_bcs_last(sect));
+
+ return 0;
+}
+
+static int
+coff_objfmt_output_value(yasm_value *value, unsigned char *buf,
+ unsigned int destsize, unsigned long offset,
+ yasm_bytecode *bc, int warn, /*@null@*/ void *d)
+{
+ /*@null@*/ coff_objfmt_output_info *info = (coff_objfmt_output_info *)d;
+ yasm_objfmt_coff *objfmt_coff;
+ /*@only@*/ /*@null@*/ yasm_intnum *dist = NULL;
+ /*@dependent@*/ /*@null@*/ yasm_intnum *intn;
+ unsigned long intn_val, intn_minus;
+ int retval;
+ unsigned int valsize = value->size;
+
+ assert(info != NULL);
+ objfmt_coff = info->objfmt_coff;
+
+ if (value->abs)
+ value->abs = yasm_expr_simplify(value->abs, 1);
+
+ /* Try to output constant and PC-relative section-local first.
+ * Note this does NOT output any value with a SEG, WRT, external,
+ * cross-section, or non-PC-relative reference (those are handled below).
+ */
+ switch (yasm_value_output_basic(value, buf, destsize, bc, warn,
+ info->object->arch)) {
+ case -1:
+ return 1;
+ case 0:
+ break;
+ default:
+ return 0;
+ }
+
+ /* Handle other expressions, with relocation if necessary */
+ if (value->rshift > 0
+ || (value->seg_of && (value->wrt || value->curpos_rel))
+ || (value->section_rel && (value->wrt || value->curpos_rel))) {
+ yasm_error_set(YASM_ERROR_TOO_COMPLEX,
+ N_("coff: relocation too complex"));
+ return 1;
+ }
+
+ intn_val = 0;
+ intn_minus = 0;
+ if (value->rel) {
+ yasm_sym_vis vis = yasm_symrec_get_visibility(value->rel);
+ /*@dependent@*/ /*@null@*/ yasm_symrec *sym = value->rel;
+ unsigned long addr;
+ coff_reloc *reloc;
+ int nobase = info->csd->flags2 & COFF_FLAG_NOBASE;
+
+ /* Sometimes we want the relocation to be generated against one
+ * symbol but the value generated correspond to a different symbol.
+ * This is done through (sym being referenced) WRT (sym used for
+ * reloc). Note both syms need to be in the same section!
+ */
+ if (value->wrt && value->wrt == objfmt_coff->ssym_imagebase)
+ nobase = 1;
+ else if (value->wrt) {
+ /*@dependent@*/ /*@null@*/ yasm_bytecode *rel_precbc, *wrt_precbc;
+
+ if (!yasm_symrec_get_label(sym, &rel_precbc)
+ || !yasm_symrec_get_label(value->wrt, &wrt_precbc)) {
+ yasm_error_set(YASM_ERROR_TOO_COMPLEX,
+ N_("coff: wrt expression too complex"));
+ return 1;
+ }
+ dist = yasm_calc_bc_dist(wrt_precbc, rel_precbc);
+ if (!dist) {
+ yasm_error_set(YASM_ERROR_TOO_COMPLEX,
+ N_("coff: cannot wrt across sections"));
+ return 1;
+ }
+ sym = value->wrt;
+ }
+
+ if (vis & YASM_SYM_COMMON) {
+ /* In standard COFF, COMMON symbols have their length added in */
+ if (!objfmt_coff->win32) {
+ /*@dependent@*/ /*@null@*/ yasm_expr **csize_expr;
+ /*@dependent@*/ /*@null@*/ yasm_intnum *common_size;
+
+ csize_expr = yasm_symrec_get_common_size(sym);
+ assert(csize_expr != NULL);
+ common_size = yasm_expr_get_intnum(csize_expr, 1);
+ if (!common_size) {
+ yasm_error_set(YASM_ERROR_TOO_COMPLEX,
+ N_("coff: common size too complex"));
+ return 1;
+ }
+
+ if (yasm_intnum_sign(common_size) < 0) {
+ yasm_error_set(YASM_ERROR_VALUE,
+ N_("coff: common size is negative"));
+ return 1;
+ }
+
+ intn_val += yasm_intnum_get_uint(common_size);
+ }
+ } else if (!(vis & YASM_SYM_EXTERN) && !objfmt_coff->win64) {
+ /*@dependent@*/ /*@null@*/ yasm_bytecode *sym_precbc;
+
+ /* Local symbols need relocation to their section's start */
+ if (yasm_symrec_get_label(sym, &sym_precbc)) {
+ yasm_section *sym_sect = yasm_bc_get_section(sym_precbc);
+ /*@null@*/ coff_section_data *sym_csd;
+ sym_csd = yasm_section_get_data(sym_sect,
+ &coff_section_data_cb);
+ assert(sym_csd != NULL);
+ sym = sym_csd->sym;
+ intn_val = yasm_bc_next_offset(sym_precbc);
+ if (COFF_SET_VMA)
+ intn_val += sym_csd->addr;
+ }
+ }
+
+ if (value->curpos_rel) {
+ /* For standard COFF, need to adjust to start of section, e.g.
+ * subtract out the bytecode offset.
+ * For Win32 COFF, need to adjust based on value size and position.
+ * For Win64 COFF that's IP-relative, adjust to next bytecode;
+ * the difference between the offset+destsize and BC length is
+ * taken care of by special relocation types.
+ */
+ if (objfmt_coff->win64 && value->ip_rel)
+ intn_val += bc->len*bc->mult_int;
+ else if (objfmt_coff->win32)
+ intn_val += offset+destsize;
+ else
+ intn_minus = bc->offset;
+ }
+
+ if (value->seg_of) {
+ /* Segment generation; zero value. */
+ intn_val = 0;
+ intn_minus = 0;
+ }
+
+ /* Generate reloc */
+ reloc = yasm_xmalloc(sizeof(coff_reloc));
+ addr = bc->offset + offset;
+ if (COFF_SET_VMA)
+ addr += info->addr;
+ reloc->reloc.addr = yasm_intnum_create_uint(addr);
+ reloc->reloc.sym = sym;
+
+ if (value->curpos_rel) {
+ if (objfmt_coff->machine == COFF_MACHINE_I386) {
+ if (valsize == 32)
+ reloc->type = COFF_RELOC_I386_REL32;
+ else {
+ yasm_error_set(YASM_ERROR_TYPE,
+ N_("coff: invalid relocation size"));
+ return 1;
+ }
+ } else if (objfmt_coff->machine == COFF_MACHINE_AMD64) {
+ if (valsize != 32) {
+ yasm_error_set(YASM_ERROR_TYPE,
+ N_("coff: invalid relocation size"));
+ return 1;
+ }
+ if (!value->ip_rel)
+ reloc->type = COFF_RELOC_AMD64_REL32;
+ else switch (bc->len*bc->mult_int - (offset+destsize)) {
+ case 0:
+ reloc->type = COFF_RELOC_AMD64_REL32;
+ break;
+ case 1:
+ reloc->type = COFF_RELOC_AMD64_REL32_1;
+ break;
+ case 2:
+ reloc->type = COFF_RELOC_AMD64_REL32_2;
+ break;
+ case 3:
+ reloc->type = COFF_RELOC_AMD64_REL32_3;
+ break;
+ case 4:
+ reloc->type = COFF_RELOC_AMD64_REL32_4;
+ break;
+ case 5:
+ reloc->type = COFF_RELOC_AMD64_REL32_5;
+ break;
+ default:
+ yasm_error_set(YASM_ERROR_TYPE,
+ N_("coff: invalid relocation size"));
+ return 1;
+ }
+ } else
+ yasm_internal_error(N_("coff objfmt: unrecognized machine"));
+ } else if (value->seg_of) {
+ if (objfmt_coff->machine == COFF_MACHINE_I386)
+ reloc->type = COFF_RELOC_I386_SECTION;
+ else if (objfmt_coff->machine == COFF_MACHINE_AMD64)
+ reloc->type = COFF_RELOC_AMD64_SECTION;
+ else
+ yasm_internal_error(N_("coff objfmt: unrecognized machine"));
+ } else if (value->section_rel) {
+ if (objfmt_coff->machine == COFF_MACHINE_I386)
+ reloc->type = COFF_RELOC_I386_SECREL;
+ else if (objfmt_coff->machine == COFF_MACHINE_AMD64)
+ reloc->type = COFF_RELOC_AMD64_SECREL;
+ else
+ yasm_internal_error(N_("coff objfmt: unrecognized machine"));
+ } else {
+ if (objfmt_coff->machine == COFF_MACHINE_I386) {
+ if (nobase)
+ reloc->type = COFF_RELOC_I386_ADDR32NB;
+ else
+ reloc->type = COFF_RELOC_I386_ADDR32;
+ } else if (objfmt_coff->machine == COFF_MACHINE_AMD64) {
+ if (valsize == 32) {
+ if (nobase)
+ reloc->type = COFF_RELOC_AMD64_ADDR32NB;
+ else
+ reloc->type = COFF_RELOC_AMD64_ADDR32;
+ } else if (valsize == 64)
+ reloc->type = COFF_RELOC_AMD64_ADDR64;
+ else {
+ yasm_error_set(YASM_ERROR_TYPE,
+ N_("coff: invalid relocation size"));
+ return 1;
+ }
+ } else
+ yasm_internal_error(N_("coff objfmt: unrecognized machine"));
+ }
+ info->csd->nreloc++;
+ yasm_section_add_reloc(info->sect, (yasm_reloc *)reloc, yasm_xfree);
+ }
+
+ /* Build up final integer output from intn_val, intn_minus, value->abs,
+ * and dist. We do all this at the end to avoid creating temporary
+ * intnums above (except for dist).
+ */
+ if (intn_minus <= intn_val)
+ intn = yasm_intnum_create_uint(intn_val-intn_minus);
+ else {
+ intn = yasm_intnum_create_uint(intn_minus-intn_val);
+ yasm_intnum_calc(intn, YASM_EXPR_NEG, NULL);
+ }
+
+ if (value->abs) {
+ yasm_intnum *intn2 = yasm_expr_get_intnum(&value->abs, 0);
+ if (!intn2) {
+ yasm_error_set(YASM_ERROR_TOO_COMPLEX,
+ N_("coff: relocation too complex"));
+ yasm_intnum_destroy(intn);
+ if (dist)
+ yasm_intnum_destroy(dist);
+ return 1;
+ }
+ yasm_intnum_calc(intn, YASM_EXPR_ADD, intn2);
+ }
+
+ if (dist) {
+ yasm_intnum_calc(intn, YASM_EXPR_ADD, dist);
+ yasm_intnum_destroy(dist);
+ }
+
+ retval = yasm_arch_intnum_tobytes(info->object->arch, intn, buf, destsize,
+ valsize, 0, bc, warn);
+ yasm_intnum_destroy(intn);
+ return retval;
+}
+
+static int
+coff_objfmt_output_bytecode(yasm_bytecode *bc, /*@null@*/ void *d)
+{
+ /*@null@*/ coff_objfmt_output_info *info = (coff_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,
+ coff_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;
+ }
+
+ info->csd->size += size;
+
+ /* 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;
+}
+
+static int
+coff_objfmt_output_section(yasm_section *sect, /*@null@*/ void *d)
+{
+ /*@null@*/ coff_objfmt_output_info *info = (coff_objfmt_output_info *)d;
+ /*@dependent@*/ /*@null@*/ coff_section_data *csd;
+ long pos;
+ coff_reloc *reloc;
+ unsigned char *localbuf;
+
+ assert(info != NULL);
+ csd = yasm_section_get_data(sect, &coff_section_data_cb);
+ assert(csd != NULL);
+
+ /* Add to strtab if in win32 format and name > 8 chars */
+ if (info->objfmt_coff->win32) {
+ size_t namelen = strlen(yasm_section_get_name(sect));
+ if (namelen > 8) {
+ csd->strtab_name = info->strtab_offset;
+ info->strtab_offset += (unsigned long)(namelen + 1);
+ }
+ }
+
+ if (!csd->isdebug)
+ csd->addr = info->addr;
+
+ if ((csd->flags & COFF_STYP_STD_MASK) == COFF_STYP_BSS) {
+ /* Don't output BSS sections.
+ * TODO: Check for non-reserve bytecodes?
+ */
+ pos = 0; /* position = 0 because it's not in the file */
+ csd->size = yasm_bc_next_offset(yasm_section_bcs_last(sect));
+ } else {
+ pos = ftell(info->f);
+ if (pos == -1) {
+ yasm__fatal(N_("could not get file position on output file"));
+ /*@notreached@*/
+ return 1;
+ }
+
+ info->sect = sect;
+ info->csd = csd;
+ yasm_section_bcs_traverse(sect, info->errwarns, info,
+ coff_objfmt_output_bytecode);
+
+ /* Sanity check final section size */
+ if (yasm_errwarns_num_errors(info->errwarns, 0) == 0 &&
+ csd->size != yasm_bc_next_offset(yasm_section_bcs_last(sect)))
+ yasm_internal_error(
+ N_("coff: section computed size did not match actual size"));
+ }
+
+ /* Empty? Go on to next section */
+ if (csd->size == 0)
+ return 0;
+
+ if (!csd->isdebug)
+ info->addr += csd->size;
+ csd->scnptr = (unsigned long)pos;
+
+ /* No relocations to output? Go on to next section */
+ if (csd->nreloc == 0)
+ return 0;
+
+ pos = ftell(info->f);
+ if (pos == -1) {
+ yasm__fatal(N_("could not get file position on output file"));
+ /*@notreached@*/
+ return 1;
+ }
+ csd->relptr = (unsigned long)pos;
+
+ /* If >=64K relocs (for Win32/64), we set a flag in the section header
+ * (NRELOC_OVFL) and the first relocation contains the number of relocs.
+ */
+ if (csd->nreloc >= 64*1024 && info->objfmt_coff->win32) {
+ localbuf = info->buf;
+ YASM_WRITE_32_L(localbuf, csd->nreloc+1); /* address of relocation */
+ YASM_WRITE_32_L(localbuf, 0); /* relocated symbol */
+ YASM_WRITE_16_L(localbuf, 0); /* type of relocation */
+ fwrite(info->buf, 10, 1, info->f);
+ }
+
+ reloc = (coff_reloc *)yasm_section_relocs_first(sect);
+ while (reloc) {
+ /*@null@*/ coff_symrec_data *csymd;
+ localbuf = info->buf;
+
+ csymd = yasm_symrec_get_data(reloc->reloc.sym, &coff_symrec_data_cb);
+ if (!csymd)
+ yasm_internal_error(
+ N_("coff: no symbol data for relocated symbol"));
+
+ yasm_intnum_get_sized(reloc->reloc.addr, localbuf, 4, 32, 0, 0, 0);
+ localbuf += 4; /* address of relocation */
+ YASM_WRITE_32_L(localbuf, csymd->index); /* relocated symbol */
+ YASM_WRITE_16_L(localbuf, reloc->type); /* type of relocation */
+ fwrite(info->buf, 10, 1, info->f);
+
+ reloc = (coff_reloc *)yasm_section_reloc_next((yasm_reloc *)reloc);
+ }
+
+ return 0;
+}
+
+static int
+coff_objfmt_output_sectstr(yasm_section *sect, /*@null@*/ void *d)
+{
+ /*@null@*/ coff_objfmt_output_info *info = (coff_objfmt_output_info *)d;
+ const char *name;
+ size_t len;
+
+ /* Add to strtab if in win32 format and name > 8 chars */
+ if (!info->objfmt_coff->win32)
+ return 0;
+
+ name = yasm_section_get_name(sect);
+ len = strlen(name);
+ if (len > 8)
+ fwrite(name, len+1, 1, info->f);
+ return 0;
+}
+
+static int
+coff_objfmt_output_secthead(yasm_section *sect, /*@null@*/ void *d)
+{
+ /*@null@*/ coff_objfmt_output_info *info = (coff_objfmt_output_info *)d;
+ yasm_objfmt_coff *objfmt_coff;
+ /*@dependent@*/ /*@null@*/ coff_section_data *csd;
+ unsigned char *localbuf;
+ unsigned long align = yasm_section_get_align(sect);
+
+ assert(info != NULL);
+ objfmt_coff = info->objfmt_coff;
+ csd = yasm_section_get_data(sect, &coff_section_data_cb);
+ assert(csd != NULL);
+
+ /* Check to see if alignment is supported size */
+ if (align > 8192)
+ align = 8192;
+
+ /* Convert alignment into flags setting */
+ csd->flags &= ~COFF_STYP_ALIGN_MASK;
+ while (align != 0) {
+ csd->flags += 1<<COFF_STYP_ALIGN_SHIFT;
+ align >>= 1;
+ }
+
+ /* section name */
+ localbuf = info->buf;
+ if (strlen(yasm_section_get_name(sect)) > 8) {
+ char namenum[30];
+ sprintf(namenum, "/%ld", csd->strtab_name);
+ strncpy((char *)localbuf, namenum, 8);
+ } else
+ strncpy((char *)localbuf, yasm_section_get_name(sect), 8);
+ localbuf += 8;
+ if (csd->isdebug) {
+ YASM_WRITE_32_L(localbuf, 0); /* physical address */
+ YASM_WRITE_32_L(localbuf, 0); /* virtual address */
+ } else {
+ YASM_WRITE_32_L(localbuf, csd->addr); /* physical address */
+ if (COFF_SET_VMA)
+ YASM_WRITE_32_L(localbuf, csd->addr);/* virtual address */
+ else
+ YASM_WRITE_32_L(localbuf, 0); /* virtual address */
+ }
+ YASM_WRITE_32_L(localbuf, csd->size); /* section size */
+ YASM_WRITE_32_L(localbuf, csd->scnptr); /* file ptr to data */
+ YASM_WRITE_32_L(localbuf, csd->relptr); /* file ptr to relocs */
+ YASM_WRITE_32_L(localbuf, 0); /* file ptr to line nums */
+ if (csd->nreloc >= 64*1024) {
+ /* Win32/64 has special handling for this case. */
+ if (objfmt_coff->win32)
+ csd->flags |= COFF_STYP_NRELOC_OVFL;
+ else {
+ yasm_warn_set(YASM_WARN_GENERAL,
+ N_("too many relocations in section `%s'"),
+ yasm_section_get_name(sect));
+ yasm_errwarn_propagate(info->errwarns, 0);
+ }
+ YASM_WRITE_16_L(localbuf, 0xFFFF); /* max out */
+ } else
+ YASM_WRITE_16_L(localbuf, csd->nreloc); /* num of relocation entries */
+ YASM_WRITE_16_L(localbuf, 0); /* num of line number entries */
+ YASM_WRITE_32_L(localbuf, csd->flags); /* flags */
+ fwrite(info->buf, 40, 1, info->f);
+
+ return 0;
+}
+
+static int
+coff_objfmt_count_sym(yasm_symrec *sym, /*@null@*/ void *d)
+{
+ /*@null@*/ coff_objfmt_output_info *info = (coff_objfmt_output_info *)d;
+ yasm_sym_vis vis = yasm_symrec_get_visibility(sym);
+ coff_symrec_data *sym_data;
+
+ assert(info != NULL);
+
+ sym_data = yasm_symrec_get_data(sym, &coff_symrec_data_cb);
+
+ if (info->all_syms || vis != YASM_SYM_LOCAL || yasm_symrec_is_abs(sym) ||
+ (sym_data && sym_data->forcevis)) {
+ /* Save index in symrec data */
+ if (!sym_data)
+ sym_data = coff_objfmt_sym_set_data(sym, COFF_SCL_NULL, 0,
+ COFF_SYMTAB_AUX_NONE);
+ /* Set storage class based on visibility if not already set */
+ if (sym_data->sclass == COFF_SCL_NULL) {
+ if (vis & (YASM_SYM_EXTERN|YASM_SYM_GLOBAL|YASM_SYM_COMMON))
+ sym_data->sclass = COFF_SCL_EXT;
+ else
+ sym_data->sclass = COFF_SCL_STAT;
+ }
+
+ sym_data->index = info->indx;
+
+ info->indx += sym_data->numaux + 1;
+ }
+ return 0;
+}
+
+static int
+coff_objfmt_output_sym(yasm_symrec *sym, /*@null@*/ void *d)
+{
+ /*@null@*/ coff_objfmt_output_info *info = (coff_objfmt_output_info *)d;
+ yasm_sym_vis vis = yasm_symrec_get_visibility(sym);
+ int is_abs = yasm_symrec_is_abs(sym);
+ /*@dependent@*/ /*@null@*/ coff_symrec_data *csymd;
+ yasm_valparamhead *objext_valparams =
+ yasm_symrec_get_objext_valparams(sym);
+ csymd = yasm_symrec_get_data(sym, &coff_symrec_data_cb);
+
+ assert(info != NULL);
+
+ /* Look for "function" flag on global syms */
+ if (csymd && csymd->type == 0 && (vis & YASM_SYM_GLOBAL) != 0) {
+ if (objext_valparams) {
+ const char *id = yasm_vp_id(yasm_vps_first(objext_valparams));
+ if (yasm__strcasecmp(id, "function") == 0)
+ csymd->type = 0x20;
+ }
+ }
+
+ /* Don't output local syms unless outputting all syms */
+ if (info->all_syms || vis != YASM_SYM_LOCAL || is_abs ||
+ (csymd && csymd->forcevis)) {
+ /*@only*/ char *name;
+ const yasm_expr *equ_val;
+ const yasm_intnum *intn;
+ unsigned char *localbuf;
+ size_t len;
+ int aux;
+ unsigned long value = 0;
+ unsigned int scnum = 0xfffe; /* -2 = debugging symbol */
+ /*@dependent@*/ /*@null@*/ yasm_section *sect;
+ /*@dependent@*/ /*@null@*/ yasm_bytecode *precbc;
+ unsigned long scnlen = 0; /* for sect auxent */
+ unsigned long nreloc = 0; /* for sect auxent */
+ yasm_objfmt_coff *objfmt_coff = info->objfmt_coff;
+
+ if (is_abs)
+ name = yasm__xstrdup(".absolut");
+ else
+ name = yasm_symrec_get_global_name(sym, info->object);
+ len = strlen(name);
+
+ /* Get symrec's of_data (needed for storage class) */
+ if (!csymd)
+ yasm_internal_error(N_("coff: expected sym data to be present"));
+
+ /* Look at symrec for value/scnum/etc. */
+ if (yasm_symrec_get_label(sym, &precbc)) {
+ if (precbc)
+ sect = yasm_bc_get_section(precbc);
+ else
+ sect = NULL;
+ /* it's a label: get value and offset.
+ * If there is not a section, leave as debugging symbol.
+ */
+ if (sect) {
+ /*@dependent@*/ /*@null@*/ coff_section_data *csectd;
+ csectd = yasm_section_get_data(sect, &coff_section_data_cb);
+ if (csectd) {
+ scnum = csectd->scnum;
+ scnlen = csectd->size;
+ nreloc = csectd->nreloc;
+ if (COFF_SET_VMA)
+ value = csectd->addr;
+ } else
+ yasm_internal_error(N_("didn't understand section"));
+ if (precbc)
+ value += yasm_bc_next_offset(precbc);
+ }
+ } else if ((equ_val = yasm_symrec_get_equ(sym))) {
+ yasm_expr *equ_val_copy = yasm_expr_copy(equ_val);
+ intn = yasm_expr_get_intnum(&equ_val_copy, 1);
+ if (!intn) {
+ if (vis & YASM_SYM_GLOBAL) {
+ yasm_error_set(YASM_ERROR_NOT_CONSTANT,
+ N_("global EQU value not an integer expression"));
+ yasm_errwarn_propagate(info->errwarns, equ_val->line);
+ }
+ } else
+ value = yasm_intnum_get_uint(intn);
+ yasm_expr_destroy(equ_val_copy);
+
+ scnum = 0xffff; /* -1 = absolute symbol */
+ } else {
+ if (vis & YASM_SYM_COMMON) {
+ /*@dependent@*/ /*@null@*/ yasm_expr **csize_expr;
+ csize_expr = yasm_symrec_get_common_size(sym);
+ assert(csize_expr != NULL);
+ intn = yasm_expr_get_intnum(csize_expr, 1);
+ if (!intn) {
+ yasm_error_set(YASM_ERROR_NOT_CONSTANT,
+ N_("COMMON data size not an integer expression"));
+ yasm_errwarn_propagate(info->errwarns,
+ (*csize_expr)->line);
+ } else
+ value = yasm_intnum_get_uint(intn);
+ scnum = 0;
+ }
+ if (vis & YASM_SYM_EXTERN)
+ scnum = 0;
+ }
+
+ localbuf = info->buf;
+ if (len > 8) {
+ YASM_WRITE_32_L(localbuf, 0); /* "zeros" field */
+ YASM_WRITE_32_L(localbuf, info->strtab_offset); /* strtab offset */
+ info->strtab_offset += (unsigned long)(len+1);
+ } else {
+ /* <8 chars, so no string table entry needed */
+ strncpy((char *)localbuf, name, 8);
+ localbuf += 8;
+ }
+ YASM_WRITE_32_L(localbuf, value); /* value */
+ YASM_WRITE_16_L(localbuf, scnum); /* section number */
+ YASM_WRITE_16_L(localbuf, csymd->type); /* type */
+ YASM_WRITE_8(localbuf, csymd->sclass); /* storage class */
+ YASM_WRITE_8(localbuf, csymd->numaux); /* number of aux entries */
+ fwrite(info->buf, 18, 1, info->f);
+ for (aux=0; aux<csymd->numaux; aux++) {
+ localbuf = info->buf;
+ memset(localbuf, 0, 18);
+ switch (csymd->auxtype) {
+ case COFF_SYMTAB_AUX_NONE:
+ break;
+ case COFF_SYMTAB_AUX_SECT:
+ YASM_WRITE_32_L(localbuf, scnlen); /* section length */
+ YASM_WRITE_16_L(localbuf, nreloc); /* number relocs */
+ YASM_WRITE_16_L(localbuf, 0); /* number line nums */
+ break;
+ case COFF_SYMTAB_AUX_FILE:
+ len = strlen(csymd->aux[0].fname);
+ if (len > 14) {
+ YASM_WRITE_32_L(localbuf, 0);
+ YASM_WRITE_32_L(localbuf, info->strtab_offset);
+ info->strtab_offset += (unsigned long)(len+1);
+ } else
+ strncpy((char *)localbuf, csymd->aux[0].fname, 14);
+ break;
+ default:
+ yasm_internal_error(
+ N_("coff: unrecognized aux symtab type"));
+ }
+ fwrite(info->buf, 18, 1, info->f);
+ }
+ yasm_xfree(name);
+ }
+ return 0;
+}
+
+static int
+coff_objfmt_output_str(yasm_symrec *sym, /*@null@*/ void *d)
+{
+ /*@null@*/ coff_objfmt_output_info *info = (coff_objfmt_output_info *)d;
+ yasm_sym_vis vis = yasm_symrec_get_visibility(sym);
+ /*@dependent@*/ /*@null@*/ coff_symrec_data *csymd;
+ csymd = yasm_symrec_get_data(sym, &coff_symrec_data_cb);
+
+ assert(info != NULL);
+
+ /* Don't output local syms unless outputting all syms */
+ if (info->all_syms || vis != YASM_SYM_LOCAL ||
+ (csymd && csymd->forcevis)) {
+ /*@only@*/ char *name = yasm_symrec_get_global_name(sym, info->object);
+ size_t len = strlen(name);
+ int aux;
+
+ if (!csymd)
+ yasm_internal_error(N_("coff: expected sym data to be present"));
+
+ if (len > 8)
+ fwrite(name, len+1, 1, info->f);
+ for (aux=0; aux<csymd->numaux; aux++) {
+ switch (csymd->auxtype) {
+ case COFF_SYMTAB_AUX_FILE:
+ len = strlen(csymd->aux[0].fname);
+ if (len > 14)
+ fwrite(csymd->aux[0].fname, len+1, 1, info->f);
+ break;
+ default:
+ break;
+ }
+ }
+ yasm_xfree(name);
+ }
+ return 0;
+}
+
+static void
+coff_objfmt_output(yasm_object *object, FILE *f, int all_syms,
+ yasm_errwarns *errwarns)
+{
+ yasm_objfmt_coff *objfmt_coff = (yasm_objfmt_coff *)object->objfmt;
+ coff_objfmt_output_info info;
+ unsigned char *localbuf;
+ long pos;
+ unsigned long symtab_pos;
+ unsigned long symtab_count;
+ unsigned int flags;
+ unsigned long ts;
+
+ if (objfmt_coff->proc_frame) {
+ yasm_error_set_xref(objfmt_coff->proc_frame,
+ N_("procedure started here"));
+ yasm_error_set(YASM_ERROR_GENERAL,
+ N_("end of file in procedure frame"));
+ yasm_errwarn_propagate(errwarns, 0);
+ return;
+ }
+
+ if (objfmt_coff->filesym_data->aux[0].fname)
+ yasm_xfree(objfmt_coff->filesym_data->aux[0].fname);
if (!object->deb_filename) {
object->deb_filename = yasm_replace_path(
objfmt_coff->objfmt.module->replace_map, objfmt_coff->objfmt.module->replace_map_size,
object->src_filename, strlen(object->src_filename));
}
- objfmt_coff->filesym_data->aux[0].fname =
+ objfmt_coff->filesym_data->aux[0].fname =
yasm__xstrdup(object->deb_filename);
-
- /* Force all syms for win64 because they're needed for relocations.
- * FIXME: Not *all* syms need to be output, only the ones needed for
- * relocation. Find a way to do that someday.
- */
- all_syms |= objfmt_coff->win64;
-
- info.strtab_offset = 4;
- info.object = object;
- info.objfmt_coff = objfmt_coff;
- info.errwarns = errwarns;
- info.f = f;
- info.buf = yasm_xmalloc(REGULAR_OUTBUF_SIZE);
-
- /* Allocate space for headers by seeking forward */
- if (fseek(f, (long)(20+40*(objfmt_coff->parse_scnum-1)), SEEK_SET) < 0) {
- yasm__fatal(N_("could not seek on output file"));
- /*@notreached@*/
- return;
- }
-
- /* Finalize symbol table (assign index to each symbol) */
- info.indx = 0;
- info.all_syms = all_syms;
- yasm_symtab_traverse(object->symtab, &info, coff_objfmt_count_sym);
- symtab_count = info.indx;
-
- /* Section data/relocs */
- if (COFF_SET_VMA) {
- /* If we're setting the VMA, we need to do a first section pass to
- * determine each section's addr value before actually outputting
- * relocations, as a relocation's section address is added into the
- * addends in the generated code.
- */
- info.addr = 0;
- if (yasm_object_sections_traverse(object, &info,
- coff_objfmt_set_section_addr))
- return;
- }
- info.addr = 0;
- if (yasm_object_sections_traverse(object, &info,
- coff_objfmt_output_section))
- return;
-
- /* Symbol table */
- pos = ftell(f);
- if (pos == -1) {
- yasm__fatal(N_("could not get file position on output file"));
- /*@notreached@*/
- return;
- }
- symtab_pos = (unsigned long)pos;
- yasm_symtab_traverse(object->symtab, &info, coff_objfmt_output_sym);
-
- /* String table */
- yasm_fwrite_32_l(info.strtab_offset, f); /* total length */
- yasm_object_sections_traverse(object, &info, coff_objfmt_output_sectstr);
- yasm_symtab_traverse(object->symtab, &info, coff_objfmt_output_str);
-
- /* Write headers */
- if (fseek(f, 0, SEEK_SET) < 0) {
- yasm__fatal(N_("could not seek on output file"));
- /*@notreached@*/
- return;
- }
-
- localbuf = info.buf;
- YASM_WRITE_16_L(localbuf, objfmt_coff->machine); /* magic number */
- YASM_WRITE_16_L(localbuf, objfmt_coff->parse_scnum-1);/* number of sects */
- if (getenv("YASM_TEST_SUITE"))
- ts = 0;
- else
- ts = (unsigned long)time(NULL);
- YASM_WRITE_32_L(localbuf, ts); /* time/date stamp */
- YASM_WRITE_32_L(localbuf, symtab_pos); /* file ptr to symtab */
- YASM_WRITE_32_L(localbuf, symtab_count); /* number of symtabs */
- YASM_WRITE_16_L(localbuf, 0); /* size of optional header (none) */
- /* flags */
- flags = 0;
- if (strcmp(yasm_dbgfmt_keyword(object->dbgfmt), "null")==0)
- flags = COFF_F_LNNO;
- if (!all_syms)
- flags |= COFF_F_LSYMS;
- if (objfmt_coff->machine != COFF_MACHINE_AMD64)
- flags |= COFF_F_AR32WR;
- YASM_WRITE_16_L(localbuf, flags);
- fwrite(info.buf, 20, 1, f);
-
- yasm_object_sections_traverse(object, &info, coff_objfmt_output_secthead);
-
- yasm_xfree(info.buf);
-}
-
-static void
-coff_objfmt_destroy(yasm_objfmt *objfmt)
-{
- yasm_objfmt_coff *objfmt_coff = (yasm_objfmt_coff *)objfmt;
- if (objfmt_coff->filesym_data->aux[0].fname)
- yasm_xfree(objfmt_coff->filesym_data->aux[0].fname);
- if (objfmt_coff->unwind)
- yasm_win64__uwinfo_destroy(objfmt_coff->unwind);
- yasm_xfree(objfmt);
-}
-
-static yasm_section *
-coff_objfmt_add_default_section(yasm_object *object)
-{
- yasm_objfmt_coff *objfmt_coff = (yasm_objfmt_coff *)object->objfmt;
- yasm_section *retval;
- coff_section_data *csd;
- int isnew;
-
- retval = yasm_object_get_general(object, ".text", 16, 1, 0, &isnew, 0);
- if (isnew) {
- csd = yasm_section_get_data(retval, &coff_section_data_cb);
- csd->flags = COFF_STYP_TEXT;
- if (objfmt_coff->win32)
- csd->flags |= COFF_STYP_EXECUTE | COFF_STYP_READ;
- yasm_section_set_default(retval, 1);
- }
- return retval;
-}
-
-struct coff_section_switch_data {
- int isdefault;
- int gasflags;
- unsigned long flags;
- unsigned long flags2;
- /*@only@*/ /*@null@*/ yasm_intnum *align_intn;
-};
-
-/* GAS-style flags */
-static int
-coff_helper_gasflags(void *obj, yasm_valparam *vp, unsigned long line, void *d,
- /*@unused@*/ uintptr_t arg)
-{
- struct coff_section_switch_data *data =
- (struct coff_section_switch_data *)d;
- int alloc = 0, load = 0, readonly = 0, code = 0, datasect = 0;
- int shared = 0;
- const char *s = yasm_vp_string(vp);
- size_t i;
-
- if (!s) {
- yasm_error_set(YASM_ERROR_VALUE, N_("non-string section attribute"));
- return -1;
- }
-
- /* For GAS, default to read/write data */
- if (data->isdefault)
- data->flags = COFF_STYP_TEXT | COFF_STYP_READ | COFF_STYP_WRITE;
-
- for (i=0; i<strlen(s); i++) {
- switch (s[i]) {
- case 'a':
- break;
- case 'b':
- alloc = 1;
- load = 0;
- break;
- case 'n':
- load = 0;
- break;
- case 's':
- shared = 1;
- /*@fallthrough@*/
- case 'd':
- datasect = 1;
- load = 1;
- readonly = 0;
- break;
- case 'x':
- code = 1;
- load = 1;
- break;
- case 'r':
- datasect = 1;
- load = 1;
- readonly = 1;
- break;
- case 'w':
- readonly = 0;
- break;
- default:
- yasm_warn_set(YASM_WARN_GENERAL,
- N_("unrecognized section attribute: `%c'"),
- s[i]);
- }
- }
-
- if (code)
- data->flags = COFF_STYP_TEXT | COFF_STYP_EXECUTE | COFF_STYP_READ;
- else if (datasect)
- data->flags = COFF_STYP_DATA | COFF_STYP_READ | COFF_STYP_WRITE;
- else if (readonly)
- data->flags = COFF_STYP_DATA | COFF_STYP_READ;
- else if (load)
- data->flags = COFF_STYP_TEXT;
- else if (alloc)
- data->flags = COFF_STYP_BSS;
-
- if (shared)
- data->flags |= COFF_STYP_SHARED;
-
- data->gasflags = 1;
- return 0;
-}
-
-static /*@observer@*/ /*@null@*/ yasm_section *
-coff_objfmt_section_switch(yasm_object *object, yasm_valparamhead *valparams,
- /*@unused@*/ /*@null@*/
- yasm_valparamhead *objext_valparams,
- unsigned long line)
-{
- yasm_objfmt_coff *objfmt_coff = (yasm_objfmt_coff *)object->objfmt;
- yasm_valparam *vp;
- yasm_section *retval;
- int isnew;
- int iscode = 0;
- int flags_override;
- const char *sectname;
- char *realname;
- int resonly = 0;
- unsigned long align = 0;
- coff_section_data *csd;
-
- struct coff_section_switch_data data;
-
- static const yasm_dir_help help[] = {
- { "code", 0, yasm_dir_helper_flag_set,
- offsetof(struct coff_section_switch_data, flags),
- COFF_STYP_TEXT | COFF_STYP_EXECUTE | COFF_STYP_READ },
- { "text", 0, yasm_dir_helper_flag_set,
- offsetof(struct coff_section_switch_data, flags),
- COFF_STYP_TEXT | COFF_STYP_EXECUTE | COFF_STYP_READ },
- { "data", 0, yasm_dir_helper_flag_set,
- offsetof(struct coff_section_switch_data, flags),
- COFF_STYP_DATA | COFF_STYP_READ | COFF_STYP_WRITE },
- { "rdata", 0, yasm_dir_helper_flag_set,
- offsetof(struct coff_section_switch_data, flags),
- COFF_STYP_DATA | COFF_STYP_READ },
- { "bss", 0, yasm_dir_helper_flag_set,
- offsetof(struct coff_section_switch_data, flags),
- COFF_STYP_BSS | COFF_STYP_READ | COFF_STYP_WRITE },
- { "info", 0, yasm_dir_helper_flag_set,
- offsetof(struct coff_section_switch_data, flags),
- COFF_STYP_INFO | COFF_STYP_DISCARD | COFF_STYP_READ },
- { "gasflags", 1, coff_helper_gasflags, 0, 0 },
- /* Win32 only below this point */
- { "discard", 0, yasm_dir_helper_flag_or,
- offsetof(struct coff_section_switch_data, flags), COFF_STYP_DISCARD},
- { "nodiscard", 0, yasm_dir_helper_flag_and,
- offsetof(struct coff_section_switch_data, flags), COFF_STYP_DISCARD},
- { "cache", 0, yasm_dir_helper_flag_and,
- offsetof(struct coff_section_switch_data, flags), COFF_STYP_NOCACHE},
- { "nocache", 0, yasm_dir_helper_flag_or,
- offsetof(struct coff_section_switch_data, flags), COFF_STYP_NOCACHE},
- { "page", 0, yasm_dir_helper_flag_and,
- offsetof(struct coff_section_switch_data, flags), COFF_STYP_NOPAGE },
- { "nopage", 0, yasm_dir_helper_flag_or,
- offsetof(struct coff_section_switch_data, flags), COFF_STYP_NOPAGE },
- { "share", 0, yasm_dir_helper_flag_or,
- offsetof(struct coff_section_switch_data, flags), COFF_STYP_SHARED },
- { "noshare", 0, yasm_dir_helper_flag_and,
- offsetof(struct coff_section_switch_data, flags), COFF_STYP_SHARED },
- { "execute", 0, yasm_dir_helper_flag_or,
- offsetof(struct coff_section_switch_data, flags), COFF_STYP_EXECUTE},
- { "noexecute", 0, yasm_dir_helper_flag_and,
- offsetof(struct coff_section_switch_data, flags), COFF_STYP_EXECUTE},
- { "read", 0, yasm_dir_helper_flag_or,
- offsetof(struct coff_section_switch_data, flags), COFF_STYP_READ },
- { "noread", 0, yasm_dir_helper_flag_and,
- offsetof(struct coff_section_switch_data, flags), COFF_STYP_READ },
- { "write", 0, yasm_dir_helper_flag_or,
- offsetof(struct coff_section_switch_data, flags), COFF_STYP_WRITE },
- { "nowrite", 0, yasm_dir_helper_flag_and,
- offsetof(struct coff_section_switch_data, flags), COFF_STYP_WRITE },
- { "base", 0, yasm_dir_helper_flag_and,
- offsetof(struct coff_section_switch_data, flags2), COFF_FLAG_NOBASE},
- { "nobase", 0, yasm_dir_helper_flag_or,
- offsetof(struct coff_section_switch_data, flags2), COFF_FLAG_NOBASE},
- { "align", 1, yasm_dir_helper_intn,
- offsetof(struct coff_section_switch_data, align_intn), 0 }
- };
-
- vp = yasm_vps_first(valparams);
- sectname = yasm_vp_string(vp);
- if (!sectname)
- return NULL;
- vp = yasm_vps_next(vp);
-
- data.isdefault = 0;
- data.gasflags = 0;
- data.flags = 0;
- data.flags2 = 0;
- data.align_intn = NULL;
-
- if (strcmp(sectname, ".data") == 0) {
- data.flags = COFF_STYP_DATA | COFF_STYP_READ | COFF_STYP_WRITE;
- if (objfmt_coff->win32) {
- if (objfmt_coff->machine == COFF_MACHINE_AMD64)
- align = 16;
- else
- align = 4;
- }
- } else if (strcmp(sectname, ".bss") == 0) {
- data.flags = COFF_STYP_BSS | COFF_STYP_READ | COFF_STYP_WRITE;
- if (objfmt_coff->win32) {
- if (objfmt_coff->machine == COFF_MACHINE_AMD64)
- align = 16;
- else
- align = 4;
- }
- resonly = 1;
- } else if (strcmp(sectname, ".text") == 0) {
- data.flags = COFF_STYP_TEXT | COFF_STYP_EXECUTE | COFF_STYP_READ;
- if (objfmt_coff->win32)
- align = 16;
- } else if (strcmp(sectname, ".rdata") == 0
- || strncmp(sectname, ".rodata", 7) == 0
- || strncmp(sectname, ".rdata$", 7) == 0) {
- data.flags = COFF_STYP_DATA | COFF_STYP_READ;
- if (objfmt_coff->win32)
- align = 8;
- else
- yasm_warn_set(YASM_WARN_GENERAL,
- N_("Standard COFF does not support read-only data sections"));
- } else if (strcmp(sectname, ".drectve") == 0) {
- data.flags = COFF_STYP_INFO;
- if (objfmt_coff->win32)
- data.flags |= COFF_STYP_DISCARD | COFF_STYP_READ;
- } else if (objfmt_coff->win64 && strcmp(sectname, ".pdata") == 0) {
- data.flags = COFF_STYP_DATA | COFF_STYP_READ;
- align = 4;
- data.flags2 = COFF_FLAG_NOBASE;
- } else if (objfmt_coff->win64 && strcmp(sectname, ".xdata") == 0) {
- data.flags = COFF_STYP_DATA | COFF_STYP_READ;
- align = 8;
- data.flags2 = COFF_FLAG_NOBASE;
- } else if (objfmt_coff->win32 && strcmp(sectname, ".sxdata") == 0) {
- data.flags = COFF_STYP_INFO;
- } else if (strcmp(sectname, ".comment") == 0) {
- data.flags = COFF_STYP_INFO | COFF_STYP_DISCARD | COFF_STYP_READ;
- } else if (yasm__strncasecmp(sectname, ".debug", 6)==0) {
- data.flags = COFF_STYP_DATA | COFF_STYP_DISCARD | COFF_STYP_READ;
- align = 1;
- } else {
- /* Default to code, but set a flag so if we get gasflags we can
- * change it (NASM and GAS have different defaults).
- */
- data.isdefault = 1;
- data.flags = COFF_STYP_TEXT | COFF_STYP_EXECUTE | COFF_STYP_READ;
- }
-
- flags_override = yasm_dir_helper(object, vp, line, help,
- objfmt_coff->win32 ? NELEMS(help) : 7,
- &data, yasm_dir_helper_valparam_warn);
- if (flags_override < 0)
- return NULL; /* error occurred */
-
- if (data.flags & COFF_STYP_EXECUTE)
- iscode = 1;
-
- if (!objfmt_coff->win32)
- data.flags &= ~COFF_STYP_WIN32_MASK;
-
- if (data.align_intn) {
- align = yasm_intnum_get_uint(data.align_intn);
- yasm_intnum_destroy(data.align_intn);
-
- /* 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;
- }
-
- /* Check to see if alignment is supported size */
- if (align > 8192) {
- yasm_error_set(YASM_ERROR_VALUE,
- N_("Win32 does not support alignments > 8192"));
- return NULL;
- }
- }
-
- realname = yasm__xstrdup(sectname);
- if (strlen(sectname) > 8 && !objfmt_coff->win32) {
- /* win32 format supports >8 character section names in object
- * files via "/nnnn" (where nnnn is decimal offset into string table),
- * so only warn for regular COFF.
- */
- yasm_warn_set(YASM_WARN_GENERAL,
- N_("COFF section names limited to 8 characters: truncating"));
- realname[8] = '\0';
- }
-
- retval = yasm_object_get_general(object, realname, align, iscode,
- resonly, &isnew, line);
- yasm_xfree(realname);
-
- csd = yasm_section_get_data(retval, &coff_section_data_cb);
-
- if (isnew || yasm_section_is_default(retval)) {
- yasm_section_set_default(retval, 0);
- csd->flags = data.flags;
- csd->flags2 = data.flags2;
- yasm_section_set_align(retval, align, line);
- } else if (flags_override && !data.gasflags)
- yasm_warn_set(YASM_WARN_GENERAL,
- N_("section flags ignored on section redeclaration"));
- return retval;
-}
-
-static /*@observer@*/ /*@null@*/ yasm_symrec *
-coff_objfmt_get_special_sym(yasm_object *object, const char *name,
- const char *parser)
-{
- return NULL;
-}
-
-static /*@observer@*/ /*@null@*/ yasm_symrec *
-win64_objfmt_get_special_sym(yasm_object *object, const char *name,
- const char *parser)
-{
- if (yasm__strcasecmp(name, "imagebase") == 0) {
- yasm_objfmt_coff *objfmt_coff = (yasm_objfmt_coff *)object->objfmt;
- return objfmt_coff->ssym_imagebase;
- }
- return NULL;
-}
-
-static void
-coff_section_data_destroy(void *data)
-{
- yasm_xfree(data);
-}
-
-static void
-coff_section_data_print(void *data, FILE *f, int indent_level)
-{
- coff_section_data *csd = (coff_section_data *)data;
-
- fprintf(f, "%*ssym=\n", indent_level, "");
- yasm_symrec_print(csd->sym, f, indent_level+1);
- fprintf(f, "%*sscnum=%d\n", indent_level, "", csd->scnum);
- fprintf(f, "%*sflags=", indent_level, "");
- switch (csd->flags & COFF_STYP_STD_MASK) {
- case COFF_STYP_TEXT:
- fprintf(f, "TEXT");
- break;
- case COFF_STYP_DATA:
- fprintf(f, "DATA");
- break;
- case COFF_STYP_BSS:
- fprintf(f, "BSS");
- break;
- default:
- fprintf(f, "UNKNOWN");
- break;
- }
- fprintf(f, "\n%*saddr=0x%lx\n", indent_level, "", csd->addr);
- fprintf(f, "%*sscnptr=0x%lx\n", indent_level, "", csd->scnptr);
- fprintf(f, "%*ssize=%ld\n", indent_level, "", csd->size);
- fprintf(f, "%*srelptr=0x%lx\n", indent_level, "", csd->relptr);
- fprintf(f, "%*snreloc=%ld\n", indent_level, "", csd->nreloc);
- fprintf(f, "%*srelocs:\n", indent_level, "");
-}
-
-static void
-coff_symrec_data_destroy(void *data)
-{
- yasm_xfree(data);
-}
-
-static void
-coff_symrec_data_print(void *data, FILE *f, int indent_level)
-{
- coff_symrec_data *csd = (coff_symrec_data *)data;
-
- fprintf(f, "%*ssymtab index=%lu\n", indent_level, "", csd->index);
- fprintf(f, "%*ssclass=%d\n", indent_level, "", csd->sclass);
-}
-
-static void
-dir_export(yasm_object *object, yasm_valparamhead *valparams,
- yasm_valparamhead *objext_valparams, unsigned long line)
-{
- yasm_valparam *vp;
- /*@null@*/ const char *symname;
- int isnew;
- yasm_section *sect;
- yasm_datavalhead dvs;
-
- /* Reference exported symbol (to generate error if not declared) */
- vp = yasm_vps_first(valparams);
- symname = yasm_vp_id(vp);
- if (symname)
- yasm_symtab_use(object->symtab, symname, line);
- else {
- yasm_error_set(YASM_ERROR_SYNTAX,
- N_("argument to EXPORT must be symbol name"));
- return;
- }
-
- /* Add to end of linker directives */
- sect = yasm_object_get_general(object, ".drectve", 0, 0, 0, &isnew, line);
-
- /* Initialize directive section if needed */
- if (isnew) {
- coff_section_data *csd;
- csd = yasm_section_get_data(sect, &coff_section_data_cb);
- csd->flags = COFF_STYP_INFO | COFF_STYP_DISCARD | COFF_STYP_READ;
- }
-
- /* Add text as data bytecode */
- yasm_dvs_initialize(&dvs);
- yasm_dvs_append(&dvs, yasm_dv_create_string(yasm__xstrdup("-export:"),
- strlen("-export:")));
- yasm_dvs_append(&dvs, yasm_dv_create_string(yasm__xstrdup(symname),
- strlen(symname)));
- yasm_dvs_append(&dvs, yasm_dv_create_string(yasm__xstrdup(" "), 1));
- yasm_section_bcs_append(sect, yasm_bc_create_data(&dvs, 1, 0, NULL, line));
-}
-
-static void
-dir_safeseh(yasm_object *object, yasm_valparamhead *valparams,
- yasm_valparamhead *objext_valparams, unsigned long line)
-{
- yasm_valparam *vp;
- /*@null@*/ const char *symname;
- yasm_symrec *sym;
- int isnew;
- yasm_section *sect;
-
- /* Reference symbol (to generate error if not declared).
- * Also, symbol must be externally visible, so force it.
- */
- vp = yasm_vps_first(valparams);
- symname = yasm_vp_id(vp);
- if (symname) {
- coff_symrec_data *sym_data;
- sym = yasm_symtab_use(object->symtab, symname, line);
- sym_data = yasm_symrec_get_data(sym, &coff_symrec_data_cb);
- if (!sym_data) {
- sym_data = coff_objfmt_sym_set_data(sym, COFF_SCL_NULL, 0,
- COFF_SYMTAB_AUX_NONE);
- }
- sym_data->forcevis = 1;
- sym_data->type = 0x20; /* function */
- } else {
- yasm_error_set(YASM_ERROR_SYNTAX,
- N_("argument to SAFESEH must be symbol name"));
- return;
- }
-
- /*
- * Add symbol number to end of .sxdata section.
- */
-
- sect = yasm_object_get_general(object, ".sxdata", 0, 0, 0, &isnew, line);
-
- /* Initialize sxdata section if needed */
- if (isnew) {
- coff_section_data *csd;
- csd = yasm_section_get_data(sect, &coff_section_data_cb);
- csd->flags = COFF_STYP_INFO;
- }
-
- /* Add as sxdata bytecode */
- yasm_section_bcs_append(sect,
- yasm_bc_create_common(&win32_sxdata_bc_callback,
- sym, line));
-}
-
-static void
-win32_sxdata_bc_destroy(void *contents)
-{
- /* Contents is just the symbol pointer, so no need to delete */
-}
-
-static void
-win32_sxdata_bc_print(const void *contents, FILE *f, int indent_level)
-{
- /* TODO */
-}
-
-static int
-win32_sxdata_bc_calc_len(yasm_bytecode *bc, yasm_bc_add_span_func add_span,
- void *add_span_data)
-{
- bc->len += 4;
- return 0;
-}
-
-static int
-win32_sxdata_bc_tobytes(yasm_bytecode *bc, unsigned char **bufp,
- unsigned char *bufstart, void *d,
- yasm_output_value_func output_value,
- yasm_output_reloc_func output_reloc)
-{
- yasm_symrec *sym = (yasm_symrec *)bc->contents;
- unsigned char *buf = *bufp;
- coff_symrec_data *csymd;
-
- csymd = yasm_symrec_get_data(sym, &coff_symrec_data_cb);
- if (!csymd)
- yasm_internal_error(N_("coff: no symbol data for SAFESEH symbol"));
-
- YASM_WRITE_32_L(buf, csymd->index);
-
- *bufp = buf;
- return 0;
-}
-
-static void
-dir_ident(yasm_object *object, yasm_valparamhead *valparams,
- yasm_valparamhead *objext_valparams, unsigned long line)
-{
- yasm_objfmt_coff *objfmt_coff = (yasm_objfmt_coff *)object->objfmt;
- yasm_valparamhead sect_vps;
- yasm_datavalhead dvs;
- yasm_section *comment;
- const char *sectname;
- yasm_valparam *vp, *vp2;
-
- /* Accept, but do nothing with empty ident */
- if (!valparams)
- return;
-
- vp = yasm_vps_first(valparams);
- if (!vp)
- return;
-
- if (objfmt_coff->win32) {
- /* Put ident data into .comment section for COFF, or .rdata$zzz
- * to be compatible with the GNU linker, which doesn't ignore
- * .comment (see binutils/gas/config/obj-coff.c:476-502).
- */
- sectname = ".rdata$zzz";
- } else {
- sectname = ".comment";
- }
- yasm_vps_initialize(&sect_vps);
- vp2 = yasm_vp_create_id(NULL, yasm__xstrdup(sectname), '\0');
- yasm_vps_append(&sect_vps, vp2);
- comment = coff_objfmt_section_switch(object, &sect_vps, NULL, line);
- yasm_vps_delete(&sect_vps);
-
- /* To match GAS output, if the comment section is empty, put an
- * initial 0 byte in the section.
- */
- if (yasm_section_bcs_first(comment) == yasm_section_bcs_last(comment)) {
- yasm_dvs_initialize(&dvs);
- yasm_dvs_append(&dvs, yasm_dv_create_expr(
- yasm_expr_create_ident(yasm_expr_int(yasm_intnum_create_uint(0)),
- line)));
- yasm_section_bcs_append(comment,
- yasm_bc_create_data(&dvs, 1, 0, object->arch, line));
- }
-
- yasm_dvs_initialize(&dvs);
- do {
- const char *s = yasm_vp_string(vp);
- if (!s) {
- yasm_error_set(YASM_ERROR_VALUE,
- N_(".comment requires string parameters"));
- yasm_dvs_delete(&dvs);
- return;
- }
- yasm_dvs_append(&dvs,
- yasm_dv_create_string(yasm__xstrdup(s), strlen(s)));
- } while ((vp = yasm_vps_next(vp)));
-
- yasm_section_bcs_append(comment,
- yasm_bc_create_data(&dvs, 1, 1, object->arch, line));
-}
-
-static void
-dir_secrel32(yasm_object *object, yasm_valparamhead *valparams,
- yasm_valparamhead *objext_valparams, unsigned long line)
-{
- yasm_datavalhead dvs;
- yasm_valparam *vp;
-
- if (!object->cur_section) {
- yasm_error_set(YASM_ERROR_SYNTAX,
- N_(".secrel32 can only be used inside of a section"));
- return;
- }
-
- vp = yasm_vps_first(valparams);
- yasm_dvs_initialize(&dvs);
- do {
- yasm_expr *e = yasm_vp_expr(vp, object->symtab, line);
- yasm_dataval *dv;
- if (!e) {
- yasm_error_set(YASM_ERROR_VALUE,
- N_(".secrel32 requires expressions"));
- yasm_dvs_delete(&dvs);
- return;
- }
- dv = yasm_dv_create_expr(e);
- yasm_dv_get_value(dv)->section_rel = 1;
- yasm_dvs_append(&dvs, dv);
- } while ((vp = yasm_vps_next(vp)));
-
- yasm_section_bcs_append(object->cur_section,
- yasm_bc_create_data(&dvs, 4, 0, object->arch, line));
-}
-
-static void
-dir_def(yasm_object *object, yasm_valparamhead *valparams,
- yasm_valparamhead *objext_valparams, unsigned long line)
-{
- yasm_objfmt_coff *objfmt_coff = (yasm_objfmt_coff *)object->objfmt;
- yasm_valparam *vp;
- const char *symname;
- yasm_symrec *sym;
- coff_symrec_data *sym_data;
-
- if (objfmt_coff->def_sym) {
- yasm_warn_set(YASM_WARN_GENERAL,
- N_(".def pseudo-op used inside of .def/.endef; ignored"));
- return;
- }
-
- vp = yasm_vps_first(valparams);
- symname = yasm_vp_id(vp);
- if (!symname) {
- yasm_error_set(YASM_ERROR_SYNTAX,
- N_("argument to SAFESEH must be symbol name"));
- return;
- }
-
- sym = yasm_symtab_use(object->symtab, symname, line);
- sym_data = yasm_symrec_get_data(sym, &coff_symrec_data_cb);
- if (!sym_data) {
- sym_data = coff_objfmt_sym_set_data(sym, COFF_SCL_NULL, 0,
- COFF_SYMTAB_AUX_NONE);
- }
- objfmt_coff->def_sym = sym_data;
-}
-
-static void
-dir_scl(yasm_object *object, yasm_valparamhead *valparams,
- yasm_valparamhead *objext_valparams, unsigned long line)
-{
- yasm_objfmt_coff *objfmt_coff = (yasm_objfmt_coff *)object->objfmt;
- yasm_intnum *intn = NULL;
-
- if (!objfmt_coff->def_sym) {
- yasm_warn_set(YASM_WARN_GENERAL,
- N_("%s pseudo-op used outside of .def/.endef; ignored"),
- ".scl");
- return;
- }
-
- if (yasm_dir_helper_intn(object, yasm_vps_first(valparams), line,
- &intn, 0) < 0)
- return;
- if (!intn)
- return;
- objfmt_coff->def_sym->sclass = yasm_intnum_get_uint(intn);
- yasm_intnum_destroy(intn);
-}
-
-static void
-dir_type(yasm_object *object, yasm_valparamhead *valparams,
- yasm_valparamhead *objext_valparams, unsigned long line)
-{
- yasm_objfmt_coff *objfmt_coff = (yasm_objfmt_coff *)object->objfmt;
- yasm_intnum *intn = NULL;
-
- if (!objfmt_coff->def_sym) {
- yasm_warn_set(YASM_WARN_GENERAL,
- N_("%s pseudo-op used outside of .def/.endef; ignored"),
- ".type");
- return;
- }
-
- if (yasm_dir_helper_intn(object, yasm_vps_first(valparams), line,
- &intn, 0) < 0)
- return;
- if (!intn)
- return;
- objfmt_coff->def_sym->type = yasm_intnum_get_uint(intn);
- yasm_intnum_destroy(intn);
-}
-
-static void
-dir_endef(yasm_object *object, yasm_valparamhead *valparams,
- yasm_valparamhead *objext_valparams, unsigned long line)
-{
- yasm_objfmt_coff *objfmt_coff = (yasm_objfmt_coff *)object->objfmt;
- if (!objfmt_coff->def_sym) {
- yasm_warn_set(YASM_WARN_GENERAL,
- N_(".endef pseudo-op used before .def; ignored"));
- return;
- }
- objfmt_coff->def_sym = NULL;
-}
-
-static void
-dir_proc_frame(yasm_object *object, /*@null@*/ yasm_valparamhead *valparams,
- yasm_valparamhead *objext_valparams, unsigned long line)
-{
- yasm_objfmt_coff *objfmt_coff = (yasm_objfmt_coff *)object->objfmt;
- yasm_valparam *vp = yasm_vps_first(valparams);
- const char *name = yasm_vp_id(vp);
-
- if (objfmt_coff->proc_frame) {
- yasm_error_set_xref(objfmt_coff->proc_frame,
- N_("previous procedure started here"));
- yasm_error_set(YASM_ERROR_SYNTAX,
- N_("nested procedures not supported (didn't use [ENDPROC_FRAME]?)"));
- return;
- }
- objfmt_coff->proc_frame = line;
- objfmt_coff->done_prolog = 0;
- objfmt_coff->unwind = yasm_win64__uwinfo_create();
- objfmt_coff->unwind->proc = yasm_symtab_use(object->symtab, name, line);
-
- /* Optional error handler */
- vp = yasm_vps_next(vp);
- if (!vp || !(name = yasm_vp_id(vp)))
- return;
- objfmt_coff->unwind->ehandler =
- yasm_symtab_use(object->symtab, name, line);
-}
-
-static int
-procframe_checkstate(yasm_objfmt_coff *objfmt_coff, const char *dirname)
-{
- if (!objfmt_coff->proc_frame) {
- yasm_error_set(YASM_ERROR_SYNTAX,
- N_("[%s] without preceding [PROC_FRAME]"), dirname);
- return 0;
- }
- if (objfmt_coff->done_prolog) {
- yasm_error_set_xref(objfmt_coff->done_prolog,
- N_("prologue ended here"));
- yasm_error_set(YASM_ERROR_SYNTAX, N_("[%s] after end of prologue"),
- dirname);
- return 0;
- }
- if (!objfmt_coff->unwind)
- yasm_internal_error(N_("unwind info not present"));
- return 1;
-}
-
-/* Get current assembly position.
- * XXX: There should be a better way to do this.
- */
-static yasm_symrec *
-get_curpos(yasm_object *object, const char *dirname, unsigned long line)
-{
- if (!object->cur_section) {
- yasm_error_set(YASM_ERROR_SYNTAX,
- N_("[%s] can only be used inside of a section"),
- dirname);
- return NULL;
- }
- return yasm_symtab_define_curpos(object->symtab, "$",
- yasm_section_bcs_last(object->cur_section), line);
-}
-
-static void
-dir_pushreg(yasm_object *object, yasm_valparamhead *valparams,
- yasm_valparamhead *objext_valparams, unsigned long line)
-{
- yasm_objfmt_coff *objfmt_coff = (yasm_objfmt_coff *)object->objfmt;
- yasm_valparam *vp = yasm_vps_first(valparams);
- coff_unwind_code *code;
- const uintptr_t *reg;
-
- if (!procframe_checkstate(objfmt_coff, "PUSHREG"))
- return;
-
- if (vp->type != YASM_PARAM_EXPR ||
- !(reg = yasm_expr_get_reg(&vp->param.e, 0))) {
- yasm_error_set(YASM_ERROR_SYNTAX,
- N_("[%s] requires a register as the first parameter"),
- "PUSHREG");
- return;
- }
-
- /* Generate a PUSH_NONVOL unwind code. */
- code = yasm_xmalloc(sizeof(coff_unwind_code));
- code->proc = objfmt_coff->unwind->proc;
- code->loc = get_curpos(object, "PUSHREG", line);
- code->opcode = UWOP_PUSH_NONVOL;
- code->info = (unsigned int)(*reg & 0xF);
- yasm_value_initialize(&code->off, NULL, 0);
- SLIST_INSERT_HEAD(&objfmt_coff->unwind->codes, code, link);
-}
-
-static void
-dir_setframe(yasm_object *object, yasm_valparamhead *valparams,
- yasm_valparamhead *objext_valparams, unsigned long line)
-{
- yasm_objfmt_coff *objfmt_coff = (yasm_objfmt_coff *)object->objfmt;
- yasm_valparam *vp = yasm_vps_first(valparams);
- coff_unwind_code *code;
- const uintptr_t *reg;
- yasm_expr *off = NULL;
-
- if (!procframe_checkstate(objfmt_coff, "SETFRAME"))
- return;
-
- if (vp->type != YASM_PARAM_EXPR ||
- !(reg = yasm_expr_get_reg(&vp->param.e, 0))) {
- yasm_error_set(YASM_ERROR_SYNTAX,
- N_("[%s] requires a register as the first parameter"),
- "SETFRAME");
- return;
- }
-
- vp = yasm_vps_next(vp);
- if (vp)
- off = yasm_vp_expr(vp, object->symtab, line);
-
- /* Set the frame fields in the unwind info */
- objfmt_coff->unwind->framereg = (unsigned long)(*reg);
- yasm_value_initialize(&objfmt_coff->unwind->frameoff, off, 8);
-
- /* Generate a SET_FPREG unwind code */
- code = yasm_xmalloc(sizeof(coff_unwind_code));
- code->proc = objfmt_coff->unwind->proc;
- code->loc = get_curpos(object, "SETFRAME", line);
- code->opcode = UWOP_SET_FPREG;
- code->info = (unsigned int)(*reg & 0xF);
- yasm_value_initialize(&code->off, off ? yasm_expr_copy(off) : NULL, 8);
- SLIST_INSERT_HEAD(&objfmt_coff->unwind->codes, code, link);
-}
-
-static void
-dir_allocstack(yasm_object *object, yasm_valparamhead *valparams,
- yasm_valparamhead *objext_valparams, unsigned long line)
-{
- yasm_objfmt_coff *objfmt_coff = (yasm_objfmt_coff *)object->objfmt;
- yasm_valparam *vp = yasm_vps_first(valparams);
- /*@null@*/ /*@only@*/ yasm_expr *size;
- coff_unwind_code *code;
-
- if (!procframe_checkstate(objfmt_coff, "ALLOCSTACK"))
- return;
-
- size = yasm_vp_expr(vp, object->symtab, line);
- if (!size) {
- yasm_error_set(YASM_ERROR_SYNTAX, N_("[%s] requires a size"),
- "ALLOCSTACK");
- return;
- }
-
- /* Generate an ALLOC_SMALL unwind code; this will get enlarged to an
- * ALLOC_LARGE if necessary.
- */
- code = yasm_xmalloc(sizeof(coff_unwind_code));
- code->proc = objfmt_coff->unwind->proc;
- code->loc = get_curpos(object, "ALLOCSTACK", line);
- code->opcode = UWOP_ALLOC_SMALL;
- code->info = 0;
- yasm_value_initialize(&code->off, size, 7);
- SLIST_INSERT_HEAD(&objfmt_coff->unwind->codes, code, link);
-}
-
-static void
-dir_save_common(yasm_object *object, yasm_valparamhead *valparams,
- unsigned long line, const char *name, int op)
-{
- yasm_objfmt_coff *objfmt_coff = (yasm_objfmt_coff *)object->objfmt;
- yasm_valparam *vp = yasm_vps_first(valparams);
- coff_unwind_code *code;
- const uintptr_t *reg;
- /*@only@*/ /*@null@*/ yasm_expr *offset;
-
- if (!procframe_checkstate(objfmt_coff, name))
- return;
-
- if (vp->type != YASM_PARAM_EXPR ||
- !(reg = yasm_expr_get_reg(&vp->param.e, 0))) {
- yasm_error_set(YASM_ERROR_SYNTAX,
- N_("[%s] requires a register as the first parameter"),
- name);
- return;
- }
-
- vp = yasm_vps_next(vp);
- offset = yasm_vp_expr(vp, object->symtab, line);
- if (!offset) {
- yasm_error_set(YASM_ERROR_SYNTAX,
- N_("[%s] requires an offset as the second parameter"),
- name);
- return;
- }
-
- /* Generate a SAVE_XXX unwind code; this will get enlarged to a
- * SAVE_XXX_FAR if necessary.
- */
- code = yasm_xmalloc(sizeof(coff_unwind_code));
- code->proc = objfmt_coff->unwind->proc;
- code->loc = get_curpos(object, name, line);
- code->opcode = op;
- code->info = (unsigned int)(*reg & 0xF);
- yasm_value_initialize(&code->off, offset, 16);
- SLIST_INSERT_HEAD(&objfmt_coff->unwind->codes, code, link);
-}
-
-static void
-dir_savereg(yasm_object *object, yasm_valparamhead *valparams,
- yasm_valparamhead *objext_valparams, unsigned long line)
-{
- dir_save_common(object, valparams, line, "SAVEREG", UWOP_SAVE_NONVOL);
-}
-
-static void
-dir_savexmm128(yasm_object *object, yasm_valparamhead *valparams,
- yasm_valparamhead *objext_valparams, unsigned long line)
-{
- dir_save_common(object, valparams, line, "SAVEXMM128", UWOP_SAVE_XMM128);
-}
-
-static void
-dir_pushframe(yasm_object *object, /*@null@*/ yasm_valparamhead *valparams,
- yasm_valparamhead *objext_valparams, unsigned long line)
-{
- yasm_objfmt_coff *objfmt_coff = (yasm_objfmt_coff *)object->objfmt;
- yasm_valparam *vp = yasm_vps_first(valparams);
- coff_unwind_code *code;
-
- if (!procframe_checkstate(objfmt_coff, "PUSHFRAME"))
- return;
-
- /* Generate a PUSH_MACHFRAME unwind code. If there's any parameter,
- * we set info to 1. Otherwise we set info to 0.
- */
- code = yasm_xmalloc(sizeof(coff_unwind_code));
- code->proc = objfmt_coff->unwind->proc;
- code->loc = get_curpos(object, "PUSHFRAME", line);
- code->opcode = UWOP_PUSH_MACHFRAME;
- code->info = vp != NULL;
- yasm_value_initialize(&code->off, NULL, 0);
- SLIST_INSERT_HEAD(&objfmt_coff->unwind->codes, code, link);
-}
-
-static void
-dir_endprolog(yasm_object *object, /*@null@*/ yasm_valparamhead *valparams,
- yasm_valparamhead *objext_valparams, unsigned long line)
-{
- yasm_objfmt_coff *objfmt_coff = (yasm_objfmt_coff *)object->objfmt;
- if (!procframe_checkstate(objfmt_coff, "ENDPROLOG"))
- return;
- objfmt_coff->done_prolog = line;
-
- objfmt_coff->unwind->prolog = get_curpos(object, "ENDPROLOG", line);
-}
-
-static void
-dir_endproc_frame(yasm_object *object, /*@null@*/ yasm_valparamhead *valparams,
- yasm_valparamhead *objext_valparams, unsigned long line)
-{
- yasm_objfmt_coff *objfmt_coff = (yasm_objfmt_coff *)object->objfmt;
- yasm_section *sect;
- coff_section_data *csd;
- yasm_datavalhead dvs;
- int isnew;
- /*@dependent@*/ yasm_symrec *curpos, *unwindpos, *proc_sym, *xdata_sym;
-
- if (!objfmt_coff->proc_frame) {
- yasm_error_set(YASM_ERROR_SYNTAX,
- N_("[%s] without preceding [PROC_FRAME]"),
- "ENDPROC_FRAME");
- return;
- }
- if (!objfmt_coff->done_prolog) {
- yasm_error_set_xref(objfmt_coff->proc_frame,
- N_("procedure started here"));
- yasm_error_set(YASM_ERROR_SYNTAX,
- N_("ended procedure without ending prologue"),
- "ENDPROC_FRAME");
- objfmt_coff->proc_frame = 0;
- yasm_win64__uwinfo_destroy(objfmt_coff->unwind);
- objfmt_coff->unwind = NULL;
- return;
- }
- if (!objfmt_coff->unwind)
- yasm_internal_error(N_("unwind info not present"));
-
- proc_sym = objfmt_coff->unwind->proc;
-
- curpos = get_curpos(object, "ENDPROC_FRAME", line);
-
- /*
- * Add unwind info to end of .xdata section.
- */
-
- sect = yasm_object_get_general(object, ".xdata", 0, 0, 0, &isnew, line);
-
- /* Initialize xdata section if needed */
- if (isnew) {
- csd = yasm_section_get_data(sect, &coff_section_data_cb);
- csd->flags = COFF_STYP_DATA | COFF_STYP_READ;
- yasm_section_set_align(sect, 8, line);
- }
-
- /* Get current position in .xdata section */
- unwindpos = yasm_symtab_define_curpos(object->symtab, "$",
- yasm_section_bcs_last(sect), line);
- /* Get symbol for .xdata as we'll want to reference it with WRT */
- csd = yasm_section_get_data(sect, &coff_section_data_cb);
- xdata_sym = csd->sym;
-
- /* Add unwind info. Use line number of start of procedure. */
- yasm_win64__unwind_generate(sect, objfmt_coff->unwind,
- objfmt_coff->proc_frame);
- objfmt_coff->unwind = NULL; /* generate keeps the unwind pointer */
-
- /*
- * Add function lookup to end of .pdata section.
- */
-
- sect = yasm_object_get_general(object, ".pdata", 0, 0, 0, &isnew, line);
-
- /* Initialize pdata section if needed */
- if (isnew) {
- csd = yasm_section_get_data(sect, &coff_section_data_cb);
- csd->flags = COFF_STYP_DATA | COFF_STYP_READ;
- csd->flags2 = COFF_FLAG_NOBASE;
- yasm_section_set_align(sect, 4, line);
- }
-
- /* Add function structure as data bytecode */
- yasm_dvs_initialize(&dvs);
- yasm_dvs_append(&dvs, yasm_dv_create_expr(
- yasm_expr_create_ident(yasm_expr_sym(proc_sym), line)));
- yasm_dvs_append(&dvs, yasm_dv_create_expr(
- yasm_expr_create(YASM_EXPR_WRT, yasm_expr_sym(curpos),
- yasm_expr_sym(proc_sym), line)));
- yasm_dvs_append(&dvs, yasm_dv_create_expr(
- yasm_expr_create(YASM_EXPR_WRT, yasm_expr_sym(unwindpos),
- yasm_expr_sym(xdata_sym), line)));
- yasm_section_bcs_append(sect, yasm_bc_create_data(&dvs, 4, 0, NULL, line));
-
- objfmt_coff->proc_frame = 0;
- objfmt_coff->done_prolog = 0;
-}
-
-/* Define valid debug formats to use with this object format */
-static const char *coff_objfmt_dbgfmt_keywords[] = {
- "null",
- "dwarf2",
- NULL
-};
-
-static const yasm_directive coff_objfmt_directives[] = {
- { ".ident", "gas", dir_ident, YASM_DIR_ANY },
- { "ident", "nasm", dir_ident, YASM_DIR_ANY },
- { ".def", "gas", dir_def, YASM_DIR_ID_REQUIRED },
- { ".endef", "gas", dir_endef, YASM_DIR_ANY },
- { ".scl", "gas", dir_scl, YASM_DIR_ARG_REQUIRED },
- { ".type", "gas", dir_type, YASM_DIR_ARG_REQUIRED },
- { ".secrel32", "gas", dir_secrel32, YASM_DIR_ARG_REQUIRED },
- { NULL, NULL, NULL, 0 }
-};
-
-/* Define objfmt structure -- see objfmt.h for details */
-yasm_objfmt_module yasm_coff_LTX_objfmt = {
- "COFF (DJGPP)",
- "coff",
- "o",
- 32,
- 0,
- coff_objfmt_dbgfmt_keywords,
- "null",
- coff_objfmt_directives,
- NULL, /* no standard macros */
- coff_objfmt_create,
- coff_objfmt_output,
- coff_objfmt_destroy,
- coff_objfmt_add_default_section,
- coff_objfmt_init_new_section,
- coff_objfmt_section_switch,
- coff_objfmt_get_special_sym
-};
-
-/* Define valid debug formats to use with this object format */
-static const char *winXX_objfmt_dbgfmt_keywords[] = {
- "null",
- "dwarf2",
- "cv8",
- NULL
-};
-
-static const yasm_directive win32_objfmt_directives[] = {
- { ".ident", "gas", dir_ident, YASM_DIR_ANY },
- { "ident", "nasm", dir_ident, YASM_DIR_ANY },
- { ".def", "gas", dir_def, YASM_DIR_ID_REQUIRED },
- { ".endef", "gas", dir_endef, YASM_DIR_ANY },
- { ".scl", "gas", dir_scl, YASM_DIR_ARG_REQUIRED },
- { ".type", "gas", dir_type, YASM_DIR_ARG_REQUIRED },
- { ".secrel32", "gas", dir_secrel32, YASM_DIR_ARG_REQUIRED },
- { ".export", "gas", dir_export, YASM_DIR_ID_REQUIRED },
- { "export", "nasm", dir_export, YASM_DIR_ID_REQUIRED },
- { ".safeseh", "gas", dir_safeseh, YASM_DIR_ID_REQUIRED },
- { "safeseh", "nasm", dir_safeseh, YASM_DIR_ID_REQUIRED },
- { NULL, NULL, NULL, 0 }
-};
-
-static const char *win32_nasm_stdmac[] = {
- "%imacro export 1+.nolist",
- "[export %1]",
- "%endmacro",
- "%imacro safeseh 1+.nolist",
- "[safeseh %1]",
- "%endmacro",
- NULL
-};
-
-static const yasm_stdmac win32_objfmt_stdmacs[] = {
- { "nasm", "nasm", win32_nasm_stdmac },
- { NULL, NULL, NULL }
-};
-
-/* Define objfmt structure -- see objfmt.h for details */
-yasm_objfmt_module yasm_win32_LTX_objfmt = {
- "Win32",
- "win32",
- "obj",
- 32,
- 1,
- winXX_objfmt_dbgfmt_keywords,
- "null",
- win32_objfmt_directives,
- win32_objfmt_stdmacs,
- win32_objfmt_create,
- coff_objfmt_output,
- coff_objfmt_destroy,
- coff_objfmt_add_default_section,
- coff_objfmt_init_new_section,
- coff_objfmt_section_switch,
- coff_objfmt_get_special_sym
-};
-
-static const yasm_directive win64_objfmt_directives[] = {
- { ".ident", "gas", dir_ident, YASM_DIR_ANY },
- { "ident", "nasm", dir_ident, YASM_DIR_ANY },
- { ".def", "gas", dir_def, YASM_DIR_ID_REQUIRED },
- { ".endef", "gas", dir_endef, YASM_DIR_ANY },
- { ".scl", "gas", dir_scl, YASM_DIR_ARG_REQUIRED },
- { ".type", "gas", dir_type, YASM_DIR_ARG_REQUIRED },
- { ".secrel32", "gas", dir_secrel32, YASM_DIR_ARG_REQUIRED },
- { ".export", "gas", dir_export, YASM_DIR_ID_REQUIRED },
- { "export", "nasm", dir_export, YASM_DIR_ID_REQUIRED },
- { ".proc_frame", "gas", dir_proc_frame, YASM_DIR_ID_REQUIRED },
- { "proc_frame", "nasm", dir_proc_frame, YASM_DIR_ID_REQUIRED },
- { ".pushreg", "gas", dir_pushreg, YASM_DIR_ARG_REQUIRED },
- { "pushreg", "nasm", dir_pushreg, YASM_DIR_ARG_REQUIRED },
- { ".setframe", "gas", dir_setframe, YASM_DIR_ARG_REQUIRED },
- { "setframe", "nasm", dir_setframe, YASM_DIR_ARG_REQUIRED },
- { ".allocstack", "gas", dir_allocstack, YASM_DIR_ARG_REQUIRED },
- { "allocstack", "nasm", dir_allocstack, YASM_DIR_ARG_REQUIRED },
- { ".savereg", "gas", dir_savereg, YASM_DIR_ARG_REQUIRED },
- { "savereg", "nasm", dir_savereg, YASM_DIR_ARG_REQUIRED },
- { ".savexmm128", "gas", dir_savexmm128, YASM_DIR_ARG_REQUIRED },
- { "savexmm128", "nasm", dir_savexmm128, YASM_DIR_ARG_REQUIRED },
- { ".pushframe", "gas", dir_pushframe, YASM_DIR_ANY },
- { "pushframe", "nasm", dir_pushframe, YASM_DIR_ANY },
- { ".endprolog", "gas", dir_endprolog, YASM_DIR_ANY },
- { "endprolog", "nasm", dir_endprolog, YASM_DIR_ANY },
- { ".endproc_frame", "gas", dir_endproc_frame, YASM_DIR_ANY },
- { "endproc_frame", "nasm", dir_endproc_frame, YASM_DIR_ANY },
- { NULL, NULL, NULL, 0 }
-};
-
-#include "win64-nasm.c"
-#include "win64-gas.c"
-
-static const yasm_stdmac win64_objfmt_stdmacs[] = {
- { "nasm", "nasm", win64_nasm_stdmac },
- { "gas", "nasm", win64_gas_stdmac },
- { NULL, NULL, NULL }
-};
-
-/* Define objfmt structure -- see objfmt.h for details */
-yasm_objfmt_module yasm_win64_LTX_objfmt = {
- "Win64",
- "win64",
- "obj",
- 64,
- 1,
- winXX_objfmt_dbgfmt_keywords,
- "null",
- win64_objfmt_directives,
- win64_objfmt_stdmacs,
- win64_objfmt_create,
- coff_objfmt_output,
- coff_objfmt_destroy,
- coff_objfmt_add_default_section,
- coff_objfmt_init_new_section,
- coff_objfmt_section_switch,
- win64_objfmt_get_special_sym
-};
-yasm_objfmt_module yasm_x64_LTX_objfmt = {
- "Win64",
- "x64",
- "obj",
- 64,
- 1,
- winXX_objfmt_dbgfmt_keywords,
- "null",
- win64_objfmt_directives,
- win64_objfmt_stdmacs,
- win64_objfmt_create,
- coff_objfmt_output,
- coff_objfmt_destroy,
- coff_objfmt_add_default_section,
- coff_objfmt_init_new_section,
- coff_objfmt_section_switch,
- win64_objfmt_get_special_sym
-};
+
+ /* Force all syms for win64 because they're needed for relocations.
+ * FIXME: Not *all* syms need to be output, only the ones needed for
+ * relocation. Find a way to do that someday.
+ */
+ all_syms |= objfmt_coff->win64;
+
+ info.strtab_offset = 4;
+ info.object = object;
+ info.objfmt_coff = objfmt_coff;
+ info.errwarns = errwarns;
+ info.f = f;
+ info.buf = yasm_xmalloc(REGULAR_OUTBUF_SIZE);
+
+ /* Allocate space for headers by seeking forward */
+ if (fseek(f, (long)(20+40*(objfmt_coff->parse_scnum-1)), SEEK_SET) < 0) {
+ yasm__fatal(N_("could not seek on output file"));
+ /*@notreached@*/
+ return;
+ }
+
+ /* Finalize symbol table (assign index to each symbol) */
+ info.indx = 0;
+ info.all_syms = all_syms;
+ yasm_symtab_traverse(object->symtab, &info, coff_objfmt_count_sym);
+ symtab_count = info.indx;
+
+ /* Section data/relocs */
+ if (COFF_SET_VMA) {
+ /* If we're setting the VMA, we need to do a first section pass to
+ * determine each section's addr value before actually outputting
+ * relocations, as a relocation's section address is added into the
+ * addends in the generated code.
+ */
+ info.addr = 0;
+ if (yasm_object_sections_traverse(object, &info,
+ coff_objfmt_set_section_addr))
+ return;
+ }
+ info.addr = 0;
+ if (yasm_object_sections_traverse(object, &info,
+ coff_objfmt_output_section))
+ return;
+
+ /* Symbol table */
+ pos = ftell(f);
+ if (pos == -1) {
+ yasm__fatal(N_("could not get file position on output file"));
+ /*@notreached@*/
+ return;
+ }
+ symtab_pos = (unsigned long)pos;
+ yasm_symtab_traverse(object->symtab, &info, coff_objfmt_output_sym);
+
+ /* String table */
+ yasm_fwrite_32_l(info.strtab_offset, f); /* total length */
+ yasm_object_sections_traverse(object, &info, coff_objfmt_output_sectstr);
+ yasm_symtab_traverse(object->symtab, &info, coff_objfmt_output_str);
+
+ /* Write headers */
+ if (fseek(f, 0, SEEK_SET) < 0) {
+ yasm__fatal(N_("could not seek on output file"));
+ /*@notreached@*/
+ return;
+ }
+
+ localbuf = info.buf;
+ YASM_WRITE_16_L(localbuf, objfmt_coff->machine); /* magic number */
+ YASM_WRITE_16_L(localbuf, objfmt_coff->parse_scnum-1);/* number of sects */
+ if (getenv("YASM_TEST_SUITE"))
+ ts = 0;
+ else
+ ts = (unsigned long)time(NULL);
+ YASM_WRITE_32_L(localbuf, ts); /* time/date stamp */
+ YASM_WRITE_32_L(localbuf, symtab_pos); /* file ptr to symtab */
+ YASM_WRITE_32_L(localbuf, symtab_count); /* number of symtabs */
+ YASM_WRITE_16_L(localbuf, 0); /* size of optional header (none) */
+ /* flags */
+ flags = 0;
+ if (strcmp(yasm_dbgfmt_keyword(object->dbgfmt), "null")==0)
+ flags = COFF_F_LNNO;
+ if (!all_syms)
+ flags |= COFF_F_LSYMS;
+ if (objfmt_coff->machine != COFF_MACHINE_AMD64)
+ flags |= COFF_F_AR32WR;
+ YASM_WRITE_16_L(localbuf, flags);
+ fwrite(info.buf, 20, 1, f);
+
+ yasm_object_sections_traverse(object, &info, coff_objfmt_output_secthead);
+
+ yasm_xfree(info.buf);
+}
+
+static void
+coff_objfmt_destroy(yasm_objfmt *objfmt)
+{
+ yasm_objfmt_coff *objfmt_coff = (yasm_objfmt_coff *)objfmt;
+ if (objfmt_coff->filesym_data->aux[0].fname)
+ yasm_xfree(objfmt_coff->filesym_data->aux[0].fname);
+ if (objfmt_coff->unwind)
+ yasm_win64__uwinfo_destroy(objfmt_coff->unwind);
+ yasm_xfree(objfmt);
+}
+
+static yasm_section *
+coff_objfmt_add_default_section(yasm_object *object)
+{
+ yasm_objfmt_coff *objfmt_coff = (yasm_objfmt_coff *)object->objfmt;
+ yasm_section *retval;
+ coff_section_data *csd;
+ int isnew;
+
+ retval = yasm_object_get_general(object, ".text", 16, 1, 0, &isnew, 0);
+ if (isnew) {
+ csd = yasm_section_get_data(retval, &coff_section_data_cb);
+ csd->flags = COFF_STYP_TEXT;
+ if (objfmt_coff->win32)
+ csd->flags |= COFF_STYP_EXECUTE | COFF_STYP_READ;
+ yasm_section_set_default(retval, 1);
+ }
+ return retval;
+}
+
+struct coff_section_switch_data {
+ int isdefault;
+ int gasflags;
+ unsigned long flags;
+ unsigned long flags2;
+ /*@only@*/ /*@null@*/ yasm_intnum *align_intn;
+};
+
+/* GAS-style flags */
+static int
+coff_helper_gasflags(void *obj, yasm_valparam *vp, unsigned long line, void *d,
+ /*@unused@*/ uintptr_t arg)
+{
+ struct coff_section_switch_data *data =
+ (struct coff_section_switch_data *)d;
+ int alloc = 0, load = 0, readonly = 0, code = 0, datasect = 0;
+ int shared = 0;
+ const char *s = yasm_vp_string(vp);
+ size_t i;
+
+ if (!s) {
+ yasm_error_set(YASM_ERROR_VALUE, N_("non-string section attribute"));
+ return -1;
+ }
+
+ /* For GAS, default to read/write data */
+ if (data->isdefault)
+ data->flags = COFF_STYP_TEXT | COFF_STYP_READ | COFF_STYP_WRITE;
+
+ for (i=0; i<strlen(s); i++) {
+ switch (s[i]) {
+ case 'a':
+ break;
+ case 'b':
+ alloc = 1;
+ load = 0;
+ break;
+ case 'n':
+ load = 0;
+ break;
+ case 's':
+ shared = 1;
+ /*@fallthrough@*/
+ case 'd':
+ datasect = 1;
+ load = 1;
+ readonly = 0;
+ break;
+ case 'x':
+ code = 1;
+ load = 1;
+ break;
+ case 'r':
+ datasect = 1;
+ load = 1;
+ readonly = 1;
+ break;
+ case 'w':
+ readonly = 0;
+ break;
+ default:
+ yasm_warn_set(YASM_WARN_GENERAL,
+ N_("unrecognized section attribute: `%c'"),
+ s[i]);
+ }
+ }
+
+ if (code)
+ data->flags = COFF_STYP_TEXT | COFF_STYP_EXECUTE | COFF_STYP_READ;
+ else if (datasect)
+ data->flags = COFF_STYP_DATA | COFF_STYP_READ | COFF_STYP_WRITE;
+ else if (readonly)
+ data->flags = COFF_STYP_DATA | COFF_STYP_READ;
+ else if (load)
+ data->flags = COFF_STYP_TEXT;
+ else if (alloc)
+ data->flags = COFF_STYP_BSS;
+
+ if (shared)
+ data->flags |= COFF_STYP_SHARED;
+
+ data->gasflags = 1;
+ return 0;
+}
+
+static /*@observer@*/ /*@null@*/ yasm_section *
+coff_objfmt_section_switch(yasm_object *object, yasm_valparamhead *valparams,
+ /*@unused@*/ /*@null@*/
+ yasm_valparamhead *objext_valparams,
+ unsigned long line)
+{
+ yasm_objfmt_coff *objfmt_coff = (yasm_objfmt_coff *)object->objfmt;
+ yasm_valparam *vp;
+ yasm_section *retval;
+ int isnew;
+ int iscode = 0;
+ int flags_override;
+ const char *sectname;
+ char *realname;
+ int resonly = 0;
+ unsigned long align = 0;
+ coff_section_data *csd;
+
+ struct coff_section_switch_data data;
+
+ static const yasm_dir_help help[] = {
+ { "code", 0, yasm_dir_helper_flag_set,
+ offsetof(struct coff_section_switch_data, flags),
+ COFF_STYP_TEXT | COFF_STYP_EXECUTE | COFF_STYP_READ },
+ { "text", 0, yasm_dir_helper_flag_set,
+ offsetof(struct coff_section_switch_data, flags),
+ COFF_STYP_TEXT | COFF_STYP_EXECUTE | COFF_STYP_READ },
+ { "data", 0, yasm_dir_helper_flag_set,
+ offsetof(struct coff_section_switch_data, flags),
+ COFF_STYP_DATA | COFF_STYP_READ | COFF_STYP_WRITE },
+ { "rdata", 0, yasm_dir_helper_flag_set,
+ offsetof(struct coff_section_switch_data, flags),
+ COFF_STYP_DATA | COFF_STYP_READ },
+ { "bss", 0, yasm_dir_helper_flag_set,
+ offsetof(struct coff_section_switch_data, flags),
+ COFF_STYP_BSS | COFF_STYP_READ | COFF_STYP_WRITE },
+ { "info", 0, yasm_dir_helper_flag_set,
+ offsetof(struct coff_section_switch_data, flags),
+ COFF_STYP_INFO | COFF_STYP_DISCARD | COFF_STYP_READ },
+ { "gasflags", 1, coff_helper_gasflags, 0, 0 },
+ /* Win32 only below this point */
+ { "discard", 0, yasm_dir_helper_flag_or,
+ offsetof(struct coff_section_switch_data, flags), COFF_STYP_DISCARD},
+ { "nodiscard", 0, yasm_dir_helper_flag_and,
+ offsetof(struct coff_section_switch_data, flags), COFF_STYP_DISCARD},
+ { "cache", 0, yasm_dir_helper_flag_and,
+ offsetof(struct coff_section_switch_data, flags), COFF_STYP_NOCACHE},
+ { "nocache", 0, yasm_dir_helper_flag_or,
+ offsetof(struct coff_section_switch_data, flags), COFF_STYP_NOCACHE},
+ { "page", 0, yasm_dir_helper_flag_and,
+ offsetof(struct coff_section_switch_data, flags), COFF_STYP_NOPAGE },
+ { "nopage", 0, yasm_dir_helper_flag_or,
+ offsetof(struct coff_section_switch_data, flags), COFF_STYP_NOPAGE },
+ { "share", 0, yasm_dir_helper_flag_or,
+ offsetof(struct coff_section_switch_data, flags), COFF_STYP_SHARED },
+ { "noshare", 0, yasm_dir_helper_flag_and,
+ offsetof(struct coff_section_switch_data, flags), COFF_STYP_SHARED },
+ { "execute", 0, yasm_dir_helper_flag_or,
+ offsetof(struct coff_section_switch_data, flags), COFF_STYP_EXECUTE},
+ { "noexecute", 0, yasm_dir_helper_flag_and,
+ offsetof(struct coff_section_switch_data, flags), COFF_STYP_EXECUTE},
+ { "read", 0, yasm_dir_helper_flag_or,
+ offsetof(struct coff_section_switch_data, flags), COFF_STYP_READ },
+ { "noread", 0, yasm_dir_helper_flag_and,
+ offsetof(struct coff_section_switch_data, flags), COFF_STYP_READ },
+ { "write", 0, yasm_dir_helper_flag_or,
+ offsetof(struct coff_section_switch_data, flags), COFF_STYP_WRITE },
+ { "nowrite", 0, yasm_dir_helper_flag_and,
+ offsetof(struct coff_section_switch_data, flags), COFF_STYP_WRITE },
+ { "base", 0, yasm_dir_helper_flag_and,
+ offsetof(struct coff_section_switch_data, flags2), COFF_FLAG_NOBASE},
+ { "nobase", 0, yasm_dir_helper_flag_or,
+ offsetof(struct coff_section_switch_data, flags2), COFF_FLAG_NOBASE},
+ { "align", 1, yasm_dir_helper_intn,
+ offsetof(struct coff_section_switch_data, align_intn), 0 }
+ };
+
+ vp = yasm_vps_first(valparams);
+ sectname = yasm_vp_string(vp);
+ if (!sectname)
+ return NULL;
+ vp = yasm_vps_next(vp);
+
+ data.isdefault = 0;
+ data.gasflags = 0;
+ data.flags = 0;
+ data.flags2 = 0;
+ data.align_intn = NULL;
+
+ if (strcmp(sectname, ".data") == 0) {
+ data.flags = COFF_STYP_DATA | COFF_STYP_READ | COFF_STYP_WRITE;
+ if (objfmt_coff->win32) {
+ if (objfmt_coff->machine == COFF_MACHINE_AMD64)
+ align = 16;
+ else
+ align = 4;
+ }
+ } else if (strcmp(sectname, ".bss") == 0) {
+ data.flags = COFF_STYP_BSS | COFF_STYP_READ | COFF_STYP_WRITE;
+ if (objfmt_coff->win32) {
+ if (objfmt_coff->machine == COFF_MACHINE_AMD64)
+ align = 16;
+ else
+ align = 4;
+ }
+ resonly = 1;
+ } else if (strcmp(sectname, ".text") == 0) {
+ data.flags = COFF_STYP_TEXT | COFF_STYP_EXECUTE | COFF_STYP_READ;
+ if (objfmt_coff->win32)
+ align = 16;
+ } else if (strcmp(sectname, ".rdata") == 0
+ || strncmp(sectname, ".rodata", 7) == 0
+ || strncmp(sectname, ".rdata$", 7) == 0) {
+ data.flags = COFF_STYP_DATA | COFF_STYP_READ;
+ if (objfmt_coff->win32)
+ align = 8;
+ else
+ yasm_warn_set(YASM_WARN_GENERAL,
+ N_("Standard COFF does not support read-only data sections"));
+ } else if (strcmp(sectname, ".drectve") == 0) {
+ data.flags = COFF_STYP_INFO;
+ if (objfmt_coff->win32)
+ data.flags |= COFF_STYP_DISCARD | COFF_STYP_READ;
+ } else if (objfmt_coff->win64 && strcmp(sectname, ".pdata") == 0) {
+ data.flags = COFF_STYP_DATA | COFF_STYP_READ;
+ align = 4;
+ data.flags2 = COFF_FLAG_NOBASE;
+ } else if (objfmt_coff->win64 && strcmp(sectname, ".xdata") == 0) {
+ data.flags = COFF_STYP_DATA | COFF_STYP_READ;
+ align = 8;
+ data.flags2 = COFF_FLAG_NOBASE;
+ } else if (objfmt_coff->win32 && strcmp(sectname, ".sxdata") == 0) {
+ data.flags = COFF_STYP_INFO;
+ } else if (strcmp(sectname, ".comment") == 0) {
+ data.flags = COFF_STYP_INFO | COFF_STYP_DISCARD | COFF_STYP_READ;
+ } else if (yasm__strncasecmp(sectname, ".debug", 6)==0) {
+ data.flags = COFF_STYP_DATA | COFF_STYP_DISCARD | COFF_STYP_READ;
+ align = 1;
+ } else {
+ /* Default to code, but set a flag so if we get gasflags we can
+ * change it (NASM and GAS have different defaults).
+ */
+ data.isdefault = 1;
+ data.flags = COFF_STYP_TEXT | COFF_STYP_EXECUTE | COFF_STYP_READ;
+ }
+
+ flags_override = yasm_dir_helper(object, vp, line, help,
+ objfmt_coff->win32 ? NELEMS(help) : 7,
+ &data, yasm_dir_helper_valparam_warn);
+ if (flags_override < 0)
+ return NULL; /* error occurred */
+
+ if (data.flags & COFF_STYP_EXECUTE)
+ iscode = 1;
+
+ if (!objfmt_coff->win32)
+ data.flags &= ~COFF_STYP_WIN32_MASK;
+
+ if (data.align_intn) {
+ align = yasm_intnum_get_uint(data.align_intn);
+ yasm_intnum_destroy(data.align_intn);
+
+ /* 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;
+ }
+
+ /* Check to see if alignment is supported size */
+ if (align > 8192) {
+ yasm_error_set(YASM_ERROR_VALUE,
+ N_("Win32 does not support alignments > 8192"));
+ return NULL;
+ }
+ }
+
+ realname = yasm__xstrdup(sectname);
+ if (strlen(sectname) > 8 && !objfmt_coff->win32) {
+ /* win32 format supports >8 character section names in object
+ * files via "/nnnn" (where nnnn is decimal offset into string table),
+ * so only warn for regular COFF.
+ */
+ yasm_warn_set(YASM_WARN_GENERAL,
+ N_("COFF section names limited to 8 characters: truncating"));
+ realname[8] = '\0';
+ }
+
+ retval = yasm_object_get_general(object, realname, align, iscode,
+ resonly, &isnew, line);
+ yasm_xfree(realname);
+
+ csd = yasm_section_get_data(retval, &coff_section_data_cb);
+
+ if (isnew || yasm_section_is_default(retval)) {
+ yasm_section_set_default(retval, 0);
+ csd->flags = data.flags;
+ csd->flags2 = data.flags2;
+ yasm_section_set_align(retval, align, line);
+ } else if (flags_override && !data.gasflags)
+ yasm_warn_set(YASM_WARN_GENERAL,
+ N_("section flags ignored on section redeclaration"));
+ return retval;
+}
+
+static /*@observer@*/ /*@null@*/ yasm_symrec *
+coff_objfmt_get_special_sym(yasm_object *object, const char *name,
+ const char *parser)
+{
+ return NULL;
+}
+
+static /*@observer@*/ /*@null@*/ yasm_symrec *
+win64_objfmt_get_special_sym(yasm_object *object, const char *name,
+ const char *parser)
+{
+ if (yasm__strcasecmp(name, "imagebase") == 0) {
+ yasm_objfmt_coff *objfmt_coff = (yasm_objfmt_coff *)object->objfmt;
+ return objfmt_coff->ssym_imagebase;
+ }
+ return NULL;
+}
+
+static void
+coff_section_data_destroy(void *data)
+{
+ yasm_xfree(data);
+}
+
+static void
+coff_section_data_print(void *data, FILE *f, int indent_level)
+{
+ coff_section_data *csd = (coff_section_data *)data;
+
+ fprintf(f, "%*ssym=\n", indent_level, "");
+ yasm_symrec_print(csd->sym, f, indent_level+1);
+ fprintf(f, "%*sscnum=%d\n", indent_level, "", csd->scnum);
+ fprintf(f, "%*sflags=", indent_level, "");
+ switch (csd->flags & COFF_STYP_STD_MASK) {
+ case COFF_STYP_TEXT:
+ fprintf(f, "TEXT");
+ break;
+ case COFF_STYP_DATA:
+ fprintf(f, "DATA");
+ break;
+ case COFF_STYP_BSS:
+ fprintf(f, "BSS");
+ break;
+ default:
+ fprintf(f, "UNKNOWN");
+ break;
+ }
+ fprintf(f, "\n%*saddr=0x%lx\n", indent_level, "", csd->addr);
+ fprintf(f, "%*sscnptr=0x%lx\n", indent_level, "", csd->scnptr);
+ fprintf(f, "%*ssize=%ld\n", indent_level, "", csd->size);
+ fprintf(f, "%*srelptr=0x%lx\n", indent_level, "", csd->relptr);
+ fprintf(f, "%*snreloc=%ld\n", indent_level, "", csd->nreloc);
+ fprintf(f, "%*srelocs:\n", indent_level, "");
+}
+
+static void
+coff_symrec_data_destroy(void *data)
+{
+ yasm_xfree(data);
+}
+
+static void
+coff_symrec_data_print(void *data, FILE *f, int indent_level)
+{
+ coff_symrec_data *csd = (coff_symrec_data *)data;
+
+ fprintf(f, "%*ssymtab index=%lu\n", indent_level, "", csd->index);
+ fprintf(f, "%*ssclass=%d\n", indent_level, "", csd->sclass);
+}
+
+static void
+dir_export(yasm_object *object, yasm_valparamhead *valparams,
+ yasm_valparamhead *objext_valparams, unsigned long line)
+{
+ yasm_valparam *vp;
+ /*@null@*/ const char *symname;
+ int isnew;
+ yasm_section *sect;
+ yasm_datavalhead dvs;
+
+ /* Reference exported symbol (to generate error if not declared) */
+ vp = yasm_vps_first(valparams);
+ symname = yasm_vp_id(vp);
+ if (symname)
+ yasm_symtab_use(object->symtab, symname, line);
+ else {
+ yasm_error_set(YASM_ERROR_SYNTAX,
+ N_("argument to EXPORT must be symbol name"));
+ return;
+ }
+
+ /* Add to end of linker directives */
+ sect = yasm_object_get_general(object, ".drectve", 0, 0, 0, &isnew, line);
+
+ /* Initialize directive section if needed */
+ if (isnew) {
+ coff_section_data *csd;
+ csd = yasm_section_get_data(sect, &coff_section_data_cb);
+ csd->flags = COFF_STYP_INFO | COFF_STYP_DISCARD | COFF_STYP_READ;
+ }
+
+ /* Add text as data bytecode */
+ yasm_dvs_initialize(&dvs);
+ yasm_dvs_append(&dvs, yasm_dv_create_string(yasm__xstrdup("-export:"),
+ strlen("-export:")));
+ yasm_dvs_append(&dvs, yasm_dv_create_string(yasm__xstrdup(symname),
+ strlen(symname)));
+ yasm_dvs_append(&dvs, yasm_dv_create_string(yasm__xstrdup(" "), 1));
+ yasm_section_bcs_append(sect, yasm_bc_create_data(&dvs, 1, 0, NULL, line));
+}
+
+static void
+dir_safeseh(yasm_object *object, yasm_valparamhead *valparams,
+ yasm_valparamhead *objext_valparams, unsigned long line)
+{
+ yasm_valparam *vp;
+ /*@null@*/ const char *symname;
+ yasm_symrec *sym;
+ int isnew;
+ yasm_section *sect;
+
+ /* Reference symbol (to generate error if not declared).
+ * Also, symbol must be externally visible, so force it.
+ */
+ vp = yasm_vps_first(valparams);
+ symname = yasm_vp_id(vp);
+ if (symname) {
+ coff_symrec_data *sym_data;
+ sym = yasm_symtab_use(object->symtab, symname, line);
+ sym_data = yasm_symrec_get_data(sym, &coff_symrec_data_cb);
+ if (!sym_data) {
+ sym_data = coff_objfmt_sym_set_data(sym, COFF_SCL_NULL, 0,
+ COFF_SYMTAB_AUX_NONE);
+ }
+ sym_data->forcevis = 1;
+ sym_data->type = 0x20; /* function */
+ } else {
+ yasm_error_set(YASM_ERROR_SYNTAX,
+ N_("argument to SAFESEH must be symbol name"));
+ return;
+ }
+
+ /*
+ * Add symbol number to end of .sxdata section.
+ */
+
+ sect = yasm_object_get_general(object, ".sxdata", 0, 0, 0, &isnew, line);
+
+ /* Initialize sxdata section if needed */
+ if (isnew) {
+ coff_section_data *csd;
+ csd = yasm_section_get_data(sect, &coff_section_data_cb);
+ csd->flags = COFF_STYP_INFO;
+ }
+
+ /* Add as sxdata bytecode */
+ yasm_section_bcs_append(sect,
+ yasm_bc_create_common(&win32_sxdata_bc_callback,
+ sym, line));
+}
+
+static void
+win32_sxdata_bc_destroy(void *contents)
+{
+ /* Contents is just the symbol pointer, so no need to delete */
+}
+
+static void
+win32_sxdata_bc_print(const void *contents, FILE *f, int indent_level)
+{
+ /* TODO */
+}
+
+static int
+win32_sxdata_bc_calc_len(yasm_bytecode *bc, yasm_bc_add_span_func add_span,
+ void *add_span_data)
+{
+ bc->len += 4;
+ return 0;
+}
+
+static int
+win32_sxdata_bc_tobytes(yasm_bytecode *bc, unsigned char **bufp,
+ unsigned char *bufstart, void *d,
+ yasm_output_value_func output_value,
+ yasm_output_reloc_func output_reloc)
+{
+ yasm_symrec *sym = (yasm_symrec *)bc->contents;
+ unsigned char *buf = *bufp;
+ coff_symrec_data *csymd;
+
+ csymd = yasm_symrec_get_data(sym, &coff_symrec_data_cb);
+ if (!csymd)
+ yasm_internal_error(N_("coff: no symbol data for SAFESEH symbol"));
+
+ YASM_WRITE_32_L(buf, csymd->index);
+
+ *bufp = buf;
+ return 0;
+}
+
+static void
+dir_ident(yasm_object *object, yasm_valparamhead *valparams,
+ yasm_valparamhead *objext_valparams, unsigned long line)
+{
+ yasm_objfmt_coff *objfmt_coff = (yasm_objfmt_coff *)object->objfmt;
+ yasm_valparamhead sect_vps;
+ yasm_datavalhead dvs;
+ yasm_section *comment;
+ const char *sectname;
+ yasm_valparam *vp, *vp2;
+
+ /* Accept, but do nothing with empty ident */
+ if (!valparams)
+ return;
+
+ vp = yasm_vps_first(valparams);
+ if (!vp)
+ return;
+
+ if (objfmt_coff->win32) {
+ /* Put ident data into .comment section for COFF, or .rdata$zzz
+ * to be compatible with the GNU linker, which doesn't ignore
+ * .comment (see binutils/gas/config/obj-coff.c:476-502).
+ */
+ sectname = ".rdata$zzz";
+ } else {
+ sectname = ".comment";
+ }
+ yasm_vps_initialize(&sect_vps);
+ vp2 = yasm_vp_create_id(NULL, yasm__xstrdup(sectname), '\0');
+ yasm_vps_append(&sect_vps, vp2);
+ comment = coff_objfmt_section_switch(object, &sect_vps, NULL, line);
+ yasm_vps_delete(&sect_vps);
+
+ /* To match GAS output, if the comment section is empty, put an
+ * initial 0 byte in the section.
+ */
+ if (yasm_section_bcs_first(comment) == yasm_section_bcs_last(comment)) {
+ yasm_dvs_initialize(&dvs);
+ yasm_dvs_append(&dvs, yasm_dv_create_expr(
+ yasm_expr_create_ident(yasm_expr_int(yasm_intnum_create_uint(0)),
+ line)));
+ yasm_section_bcs_append(comment,
+ yasm_bc_create_data(&dvs, 1, 0, object->arch, line));
+ }
+
+ yasm_dvs_initialize(&dvs);
+ do {
+ const char *s = yasm_vp_string(vp);
+ if (!s) {
+ yasm_error_set(YASM_ERROR_VALUE,
+ N_(".comment requires string parameters"));
+ yasm_dvs_delete(&dvs);
+ return;
+ }
+ yasm_dvs_append(&dvs,
+ yasm_dv_create_string(yasm__xstrdup(s), strlen(s)));
+ } while ((vp = yasm_vps_next(vp)));
+
+ yasm_section_bcs_append(comment,
+ yasm_bc_create_data(&dvs, 1, 1, object->arch, line));
+}
+
+static void
+dir_secrel32(yasm_object *object, yasm_valparamhead *valparams,
+ yasm_valparamhead *objext_valparams, unsigned long line)
+{
+ yasm_datavalhead dvs;
+ yasm_valparam *vp;
+
+ if (!object->cur_section) {
+ yasm_error_set(YASM_ERROR_SYNTAX,
+ N_(".secrel32 can only be used inside of a section"));
+ return;
+ }
+
+ vp = yasm_vps_first(valparams);
+ yasm_dvs_initialize(&dvs);
+ do {
+ yasm_expr *e = yasm_vp_expr(vp, object->symtab, line);
+ yasm_dataval *dv;
+ if (!e) {
+ yasm_error_set(YASM_ERROR_VALUE,
+ N_(".secrel32 requires expressions"));
+ yasm_dvs_delete(&dvs);
+ return;
+ }
+ dv = yasm_dv_create_expr(e);
+ yasm_dv_get_value(dv)->section_rel = 1;
+ yasm_dvs_append(&dvs, dv);
+ } while ((vp = yasm_vps_next(vp)));
+
+ yasm_section_bcs_append(object->cur_section,
+ yasm_bc_create_data(&dvs, 4, 0, object->arch, line));
+}
+
+static void
+dir_def(yasm_object *object, yasm_valparamhead *valparams,
+ yasm_valparamhead *objext_valparams, unsigned long line)
+{
+ yasm_objfmt_coff *objfmt_coff = (yasm_objfmt_coff *)object->objfmt;
+ yasm_valparam *vp;
+ const char *symname;
+ yasm_symrec *sym;
+ coff_symrec_data *sym_data;
+
+ if (objfmt_coff->def_sym) {
+ yasm_warn_set(YASM_WARN_GENERAL,
+ N_(".def pseudo-op used inside of .def/.endef; ignored"));
+ return;
+ }
+
+ vp = yasm_vps_first(valparams);
+ symname = yasm_vp_id(vp);
+ if (!symname) {
+ yasm_error_set(YASM_ERROR_SYNTAX,
+ N_("argument to SAFESEH must be symbol name"));
+ return;
+ }
+
+ sym = yasm_symtab_use(object->symtab, symname, line);
+ sym_data = yasm_symrec_get_data(sym, &coff_symrec_data_cb);
+ if (!sym_data) {
+ sym_data = coff_objfmt_sym_set_data(sym, COFF_SCL_NULL, 0,
+ COFF_SYMTAB_AUX_NONE);
+ }
+ objfmt_coff->def_sym = sym_data;
+}
+
+static void
+dir_scl(yasm_object *object, yasm_valparamhead *valparams,
+ yasm_valparamhead *objext_valparams, unsigned long line)
+{
+ yasm_objfmt_coff *objfmt_coff = (yasm_objfmt_coff *)object->objfmt;
+ yasm_intnum *intn = NULL;
+
+ if (!objfmt_coff->def_sym) {
+ yasm_warn_set(YASM_WARN_GENERAL,
+ N_("%s pseudo-op used outside of .def/.endef; ignored"),
+ ".scl");
+ return;
+ }
+
+ if (yasm_dir_helper_intn(object, yasm_vps_first(valparams), line,
+ &intn, 0) < 0)
+ return;
+ if (!intn)
+ return;
+ objfmt_coff->def_sym->sclass = yasm_intnum_get_uint(intn);
+ yasm_intnum_destroy(intn);
+}
+
+static void
+dir_type(yasm_object *object, yasm_valparamhead *valparams,
+ yasm_valparamhead *objext_valparams, unsigned long line)
+{
+ yasm_objfmt_coff *objfmt_coff = (yasm_objfmt_coff *)object->objfmt;
+ yasm_intnum *intn = NULL;
+
+ if (!objfmt_coff->def_sym) {
+ yasm_warn_set(YASM_WARN_GENERAL,
+ N_("%s pseudo-op used outside of .def/.endef; ignored"),
+ ".type");
+ return;
+ }
+
+ if (yasm_dir_helper_intn(object, yasm_vps_first(valparams), line,
+ &intn, 0) < 0)
+ return;
+ if (!intn)
+ return;
+ objfmt_coff->def_sym->type = yasm_intnum_get_uint(intn);
+ yasm_intnum_destroy(intn);
+}
+
+static void
+dir_endef(yasm_object *object, yasm_valparamhead *valparams,
+ yasm_valparamhead *objext_valparams, unsigned long line)
+{
+ yasm_objfmt_coff *objfmt_coff = (yasm_objfmt_coff *)object->objfmt;
+ if (!objfmt_coff->def_sym) {
+ yasm_warn_set(YASM_WARN_GENERAL,
+ N_(".endef pseudo-op used before .def; ignored"));
+ return;
+ }
+ objfmt_coff->def_sym = NULL;
+}
+
+static void
+dir_proc_frame(yasm_object *object, /*@null@*/ yasm_valparamhead *valparams,
+ yasm_valparamhead *objext_valparams, unsigned long line)
+{
+ yasm_objfmt_coff *objfmt_coff = (yasm_objfmt_coff *)object->objfmt;
+ yasm_valparam *vp = yasm_vps_first(valparams);
+ const char *name = yasm_vp_id(vp);
+
+ if (objfmt_coff->proc_frame) {
+ yasm_error_set_xref(objfmt_coff->proc_frame,
+ N_("previous procedure started here"));
+ yasm_error_set(YASM_ERROR_SYNTAX,
+ N_("nested procedures not supported (didn't use [ENDPROC_FRAME]?)"));
+ return;
+ }
+ objfmt_coff->proc_frame = line;
+ objfmt_coff->done_prolog = 0;
+ objfmt_coff->unwind = yasm_win64__uwinfo_create();
+ objfmt_coff->unwind->proc = yasm_symtab_use(object->symtab, name, line);
+
+ /* Optional error handler */
+ vp = yasm_vps_next(vp);
+ if (!vp || !(name = yasm_vp_id(vp)))
+ return;
+ objfmt_coff->unwind->ehandler =
+ yasm_symtab_use(object->symtab, name, line);
+}
+
+static int
+procframe_checkstate(yasm_objfmt_coff *objfmt_coff, const char *dirname)
+{
+ if (!objfmt_coff->proc_frame) {
+ yasm_error_set(YASM_ERROR_SYNTAX,
+ N_("[%s] without preceding [PROC_FRAME]"), dirname);
+ return 0;
+ }
+ if (objfmt_coff->done_prolog) {
+ yasm_error_set_xref(objfmt_coff->done_prolog,
+ N_("prologue ended here"));
+ yasm_error_set(YASM_ERROR_SYNTAX, N_("[%s] after end of prologue"),
+ dirname);
+ return 0;
+ }
+ if (!objfmt_coff->unwind)
+ yasm_internal_error(N_("unwind info not present"));
+ return 1;
+}
+
+/* Get current assembly position.
+ * XXX: There should be a better way to do this.
+ */
+static yasm_symrec *
+get_curpos(yasm_object *object, const char *dirname, unsigned long line)
+{
+ if (!object->cur_section) {
+ yasm_error_set(YASM_ERROR_SYNTAX,
+ N_("[%s] can only be used inside of a section"),
+ dirname);
+ return NULL;
+ }
+ return yasm_symtab_define_curpos(object->symtab, "$",
+ yasm_section_bcs_last(object->cur_section), line);
+}
+
+static void
+dir_pushreg(yasm_object *object, yasm_valparamhead *valparams,
+ yasm_valparamhead *objext_valparams, unsigned long line)
+{
+ yasm_objfmt_coff *objfmt_coff = (yasm_objfmt_coff *)object->objfmt;
+ yasm_valparam *vp = yasm_vps_first(valparams);
+ coff_unwind_code *code;
+ const uintptr_t *reg;
+
+ if (!procframe_checkstate(objfmt_coff, "PUSHREG"))
+ return;
+
+ if (vp->type != YASM_PARAM_EXPR ||
+ !(reg = yasm_expr_get_reg(&vp->param.e, 0))) {
+ yasm_error_set(YASM_ERROR_SYNTAX,
+ N_("[%s] requires a register as the first parameter"),
+ "PUSHREG");
+ return;
+ }
+
+ /* Generate a PUSH_NONVOL unwind code. */
+ code = yasm_xmalloc(sizeof(coff_unwind_code));
+ code->proc = objfmt_coff->unwind->proc;
+ code->loc = get_curpos(object, "PUSHREG", line);
+ code->opcode = UWOP_PUSH_NONVOL;
+ code->info = (unsigned int)(*reg & 0xF);
+ yasm_value_initialize(&code->off, NULL, 0);
+ SLIST_INSERT_HEAD(&objfmt_coff->unwind->codes, code, link);
+}
+
+static void
+dir_setframe(yasm_object *object, yasm_valparamhead *valparams,
+ yasm_valparamhead *objext_valparams, unsigned long line)
+{
+ yasm_objfmt_coff *objfmt_coff = (yasm_objfmt_coff *)object->objfmt;
+ yasm_valparam *vp = yasm_vps_first(valparams);
+ coff_unwind_code *code;
+ const uintptr_t *reg;
+ yasm_expr *off = NULL;
+
+ if (!procframe_checkstate(objfmt_coff, "SETFRAME"))
+ return;
+
+ if (vp->type != YASM_PARAM_EXPR ||
+ !(reg = yasm_expr_get_reg(&vp->param.e, 0))) {
+ yasm_error_set(YASM_ERROR_SYNTAX,
+ N_("[%s] requires a register as the first parameter"),
+ "SETFRAME");
+ return;
+ }
+
+ vp = yasm_vps_next(vp);
+ if (vp)
+ off = yasm_vp_expr(vp, object->symtab, line);
+
+ /* Set the frame fields in the unwind info */
+ objfmt_coff->unwind->framereg = (unsigned long)(*reg);
+ yasm_value_initialize(&objfmt_coff->unwind->frameoff, off, 8);
+
+ /* Generate a SET_FPREG unwind code */
+ code = yasm_xmalloc(sizeof(coff_unwind_code));
+ code->proc = objfmt_coff->unwind->proc;
+ code->loc = get_curpos(object, "SETFRAME", line);
+ code->opcode = UWOP_SET_FPREG;
+ code->info = (unsigned int)(*reg & 0xF);
+ yasm_value_initialize(&code->off, off ? yasm_expr_copy(off) : NULL, 8);
+ SLIST_INSERT_HEAD(&objfmt_coff->unwind->codes, code, link);
+}
+
+static void
+dir_allocstack(yasm_object *object, yasm_valparamhead *valparams,
+ yasm_valparamhead *objext_valparams, unsigned long line)
+{
+ yasm_objfmt_coff *objfmt_coff = (yasm_objfmt_coff *)object->objfmt;
+ yasm_valparam *vp = yasm_vps_first(valparams);
+ /*@null@*/ /*@only@*/ yasm_expr *size;
+ coff_unwind_code *code;
+
+ if (!procframe_checkstate(objfmt_coff, "ALLOCSTACK"))
+ return;
+
+ size = yasm_vp_expr(vp, object->symtab, line);
+ if (!size) {
+ yasm_error_set(YASM_ERROR_SYNTAX, N_("[%s] requires a size"),
+ "ALLOCSTACK");
+ return;
+ }
+
+ /* Generate an ALLOC_SMALL unwind code; this will get enlarged to an
+ * ALLOC_LARGE if necessary.
+ */
+ code = yasm_xmalloc(sizeof(coff_unwind_code));
+ code->proc = objfmt_coff->unwind->proc;
+ code->loc = get_curpos(object, "ALLOCSTACK", line);
+ code->opcode = UWOP_ALLOC_SMALL;
+ code->info = 0;
+ yasm_value_initialize(&code->off, size, 7);
+ SLIST_INSERT_HEAD(&objfmt_coff->unwind->codes, code, link);
+}
+
+static void
+dir_save_common(yasm_object *object, yasm_valparamhead *valparams,
+ unsigned long line, const char *name, int op)
+{
+ yasm_objfmt_coff *objfmt_coff = (yasm_objfmt_coff *)object->objfmt;
+ yasm_valparam *vp = yasm_vps_first(valparams);
+ coff_unwind_code *code;
+ const uintptr_t *reg;
+ /*@only@*/ /*@null@*/ yasm_expr *offset;
+
+ if (!procframe_checkstate(objfmt_coff, name))
+ return;
+
+ if (vp->type != YASM_PARAM_EXPR ||
+ !(reg = yasm_expr_get_reg(&vp->param.e, 0))) {
+ yasm_error_set(YASM_ERROR_SYNTAX,
+ N_("[%s] requires a register as the first parameter"),
+ name);
+ return;
+ }
+
+ vp = yasm_vps_next(vp);
+ offset = yasm_vp_expr(vp, object->symtab, line);
+ if (!offset) {
+ yasm_error_set(YASM_ERROR_SYNTAX,
+ N_("[%s] requires an offset as the second parameter"),
+ name);
+ return;
+ }
+
+ /* Generate a SAVE_XXX unwind code; this will get enlarged to a
+ * SAVE_XXX_FAR if necessary.
+ */
+ code = yasm_xmalloc(sizeof(coff_unwind_code));
+ code->proc = objfmt_coff->unwind->proc;
+ code->loc = get_curpos(object, name, line);
+ code->opcode = op;
+ code->info = (unsigned int)(*reg & 0xF);
+ yasm_value_initialize(&code->off, offset, 16);
+ SLIST_INSERT_HEAD(&objfmt_coff->unwind->codes, code, link);
+}
+
+static void
+dir_savereg(yasm_object *object, yasm_valparamhead *valparams,
+ yasm_valparamhead *objext_valparams, unsigned long line)
+{
+ dir_save_common(object, valparams, line, "SAVEREG", UWOP_SAVE_NONVOL);
+}
+
+static void
+dir_savexmm128(yasm_object *object, yasm_valparamhead *valparams,
+ yasm_valparamhead *objext_valparams, unsigned long line)
+{
+ dir_save_common(object, valparams, line, "SAVEXMM128", UWOP_SAVE_XMM128);
+}
+
+static void
+dir_pushframe(yasm_object *object, /*@null@*/ yasm_valparamhead *valparams,
+ yasm_valparamhead *objext_valparams, unsigned long line)
+{
+ yasm_objfmt_coff *objfmt_coff = (yasm_objfmt_coff *)object->objfmt;
+ yasm_valparam *vp = yasm_vps_first(valparams);
+ coff_unwind_code *code;
+
+ if (!procframe_checkstate(objfmt_coff, "PUSHFRAME"))
+ return;
+
+ /* Generate a PUSH_MACHFRAME unwind code. If there's any parameter,
+ * we set info to 1. Otherwise we set info to 0.
+ */
+ code = yasm_xmalloc(sizeof(coff_unwind_code));
+ code->proc = objfmt_coff->unwind->proc;
+ code->loc = get_curpos(object, "PUSHFRAME", line);
+ code->opcode = UWOP_PUSH_MACHFRAME;
+ code->info = vp != NULL;
+ yasm_value_initialize(&code->off, NULL, 0);
+ SLIST_INSERT_HEAD(&objfmt_coff->unwind->codes, code, link);
+}
+
+static void
+dir_endprolog(yasm_object *object, /*@null@*/ yasm_valparamhead *valparams,
+ yasm_valparamhead *objext_valparams, unsigned long line)
+{
+ yasm_objfmt_coff *objfmt_coff = (yasm_objfmt_coff *)object->objfmt;
+ if (!procframe_checkstate(objfmt_coff, "ENDPROLOG"))
+ return;
+ objfmt_coff->done_prolog = line;
+
+ objfmt_coff->unwind->prolog = get_curpos(object, "ENDPROLOG", line);
+}
+
+static void
+dir_endproc_frame(yasm_object *object, /*@null@*/ yasm_valparamhead *valparams,
+ yasm_valparamhead *objext_valparams, unsigned long line)
+{
+ yasm_objfmt_coff *objfmt_coff = (yasm_objfmt_coff *)object->objfmt;
+ yasm_section *sect;
+ coff_section_data *csd;
+ yasm_datavalhead dvs;
+ int isnew;
+ /*@dependent@*/ yasm_symrec *curpos, *unwindpos, *proc_sym, *xdata_sym;
+
+ if (!objfmt_coff->proc_frame) {
+ yasm_error_set(YASM_ERROR_SYNTAX,
+ N_("[%s] without preceding [PROC_FRAME]"),
+ "ENDPROC_FRAME");
+ return;
+ }
+ if (!objfmt_coff->done_prolog) {
+ yasm_error_set_xref(objfmt_coff->proc_frame,
+ N_("procedure started here"));
+ yasm_error_set(YASM_ERROR_SYNTAX,
+ N_("ended procedure without ending prologue"),
+ "ENDPROC_FRAME");
+ objfmt_coff->proc_frame = 0;
+ yasm_win64__uwinfo_destroy(objfmt_coff->unwind);
+ objfmt_coff->unwind = NULL;
+ return;
+ }
+ if (!objfmt_coff->unwind)
+ yasm_internal_error(N_("unwind info not present"));
+
+ proc_sym = objfmt_coff->unwind->proc;
+
+ curpos = get_curpos(object, "ENDPROC_FRAME", line);
+
+ /*
+ * Add unwind info to end of .xdata section.
+ */
+
+ sect = yasm_object_get_general(object, ".xdata", 0, 0, 0, &isnew, line);
+
+ /* Initialize xdata section if needed */
+ if (isnew) {
+ csd = yasm_section_get_data(sect, &coff_section_data_cb);
+ csd->flags = COFF_STYP_DATA | COFF_STYP_READ;
+ yasm_section_set_align(sect, 8, line);
+ }
+
+ /* Get current position in .xdata section */
+ unwindpos = yasm_symtab_define_curpos(object->symtab, "$",
+ yasm_section_bcs_last(sect), line);
+ /* Get symbol for .xdata as we'll want to reference it with WRT */
+ csd = yasm_section_get_data(sect, &coff_section_data_cb);
+ xdata_sym = csd->sym;
+
+ /* Add unwind info. Use line number of start of procedure. */
+ yasm_win64__unwind_generate(sect, objfmt_coff->unwind,
+ objfmt_coff->proc_frame);
+ objfmt_coff->unwind = NULL; /* generate keeps the unwind pointer */
+
+ /*
+ * Add function lookup to end of .pdata section.
+ */
+
+ sect = yasm_object_get_general(object, ".pdata", 0, 0, 0, &isnew, line);
+
+ /* Initialize pdata section if needed */
+ if (isnew) {
+ csd = yasm_section_get_data(sect, &coff_section_data_cb);
+ csd->flags = COFF_STYP_DATA | COFF_STYP_READ;
+ csd->flags2 = COFF_FLAG_NOBASE;
+ yasm_section_set_align(sect, 4, line);
+ }
+
+ /* Add function structure as data bytecode */
+ yasm_dvs_initialize(&dvs);
+ yasm_dvs_append(&dvs, yasm_dv_create_expr(
+ yasm_expr_create_ident(yasm_expr_sym(proc_sym), line)));
+ yasm_dvs_append(&dvs, yasm_dv_create_expr(
+ yasm_expr_create(YASM_EXPR_WRT, yasm_expr_sym(curpos),
+ yasm_expr_sym(proc_sym), line)));
+ yasm_dvs_append(&dvs, yasm_dv_create_expr(
+ yasm_expr_create(YASM_EXPR_WRT, yasm_expr_sym(unwindpos),
+ yasm_expr_sym(xdata_sym), line)));
+ yasm_section_bcs_append(sect, yasm_bc_create_data(&dvs, 4, 0, NULL, line));
+
+ objfmt_coff->proc_frame = 0;
+ objfmt_coff->done_prolog = 0;
+}
+
+/* Define valid debug formats to use with this object format */
+static const char *coff_objfmt_dbgfmt_keywords[] = {
+ "null",
+ "dwarf2",
+ NULL
+};
+
+static const yasm_directive coff_objfmt_directives[] = {
+ { ".ident", "gas", dir_ident, YASM_DIR_ANY },
+ { "ident", "nasm", dir_ident, YASM_DIR_ANY },
+ { ".def", "gas", dir_def, YASM_DIR_ID_REQUIRED },
+ { ".endef", "gas", dir_endef, YASM_DIR_ANY },
+ { ".scl", "gas", dir_scl, YASM_DIR_ARG_REQUIRED },
+ { ".type", "gas", dir_type, YASM_DIR_ARG_REQUIRED },
+ { ".secrel32", "gas", dir_secrel32, YASM_DIR_ARG_REQUIRED },
+ { NULL, NULL, NULL, 0 }
+};
+
+/* Define objfmt structure -- see objfmt.h for details */
+yasm_objfmt_module yasm_coff_LTX_objfmt = {
+ "COFF (DJGPP)",
+ "coff",
+ "o",
+ 32,
+ 0,
+ coff_objfmt_dbgfmt_keywords,
+ "null",
+ coff_objfmt_directives,
+ NULL, /* no standard macros */
+ coff_objfmt_create,
+ coff_objfmt_output,
+ coff_objfmt_destroy,
+ coff_objfmt_add_default_section,
+ coff_objfmt_init_new_section,
+ coff_objfmt_section_switch,
+ coff_objfmt_get_special_sym
+};
+
+/* Define valid debug formats to use with this object format */
+static const char *winXX_objfmt_dbgfmt_keywords[] = {
+ "null",
+ "dwarf2",
+ "cv8",
+ NULL
+};
+
+static const yasm_directive win32_objfmt_directives[] = {
+ { ".ident", "gas", dir_ident, YASM_DIR_ANY },
+ { "ident", "nasm", dir_ident, YASM_DIR_ANY },
+ { ".def", "gas", dir_def, YASM_DIR_ID_REQUIRED },
+ { ".endef", "gas", dir_endef, YASM_DIR_ANY },
+ { ".scl", "gas", dir_scl, YASM_DIR_ARG_REQUIRED },
+ { ".type", "gas", dir_type, YASM_DIR_ARG_REQUIRED },
+ { ".secrel32", "gas", dir_secrel32, YASM_DIR_ARG_REQUIRED },
+ { ".export", "gas", dir_export, YASM_DIR_ID_REQUIRED },
+ { "export", "nasm", dir_export, YASM_DIR_ID_REQUIRED },
+ { ".safeseh", "gas", dir_safeseh, YASM_DIR_ID_REQUIRED },
+ { "safeseh", "nasm", dir_safeseh, YASM_DIR_ID_REQUIRED },
+ { NULL, NULL, NULL, 0 }
+};
+
+static const char *win32_nasm_stdmac[] = {
+ "%imacro export 1+.nolist",
+ "[export %1]",
+ "%endmacro",
+ "%imacro safeseh 1+.nolist",
+ "[safeseh %1]",
+ "%endmacro",
+ NULL
+};
+
+static const yasm_stdmac win32_objfmt_stdmacs[] = {
+ { "nasm", "nasm", win32_nasm_stdmac },
+ { NULL, NULL, NULL }
+};
+
+/* Define objfmt structure -- see objfmt.h for details */
+yasm_objfmt_module yasm_win32_LTX_objfmt = {
+ "Win32",
+ "win32",
+ "obj",
+ 32,
+ 1,
+ winXX_objfmt_dbgfmt_keywords,
+ "null",
+ win32_objfmt_directives,
+ win32_objfmt_stdmacs,
+ win32_objfmt_create,
+ coff_objfmt_output,
+ coff_objfmt_destroy,
+ coff_objfmt_add_default_section,
+ coff_objfmt_init_new_section,
+ coff_objfmt_section_switch,
+ coff_objfmt_get_special_sym
+};
+
+static const yasm_directive win64_objfmt_directives[] = {
+ { ".ident", "gas", dir_ident, YASM_DIR_ANY },
+ { "ident", "nasm", dir_ident, YASM_DIR_ANY },
+ { ".def", "gas", dir_def, YASM_DIR_ID_REQUIRED },
+ { ".endef", "gas", dir_endef, YASM_DIR_ANY },
+ { ".scl", "gas", dir_scl, YASM_DIR_ARG_REQUIRED },
+ { ".type", "gas", dir_type, YASM_DIR_ARG_REQUIRED },
+ { ".secrel32", "gas", dir_secrel32, YASM_DIR_ARG_REQUIRED },
+ { ".export", "gas", dir_export, YASM_DIR_ID_REQUIRED },
+ { "export", "nasm", dir_export, YASM_DIR_ID_REQUIRED },
+ { ".proc_frame", "gas", dir_proc_frame, YASM_DIR_ID_REQUIRED },
+ { "proc_frame", "nasm", dir_proc_frame, YASM_DIR_ID_REQUIRED },
+ { ".pushreg", "gas", dir_pushreg, YASM_DIR_ARG_REQUIRED },
+ { "pushreg", "nasm", dir_pushreg, YASM_DIR_ARG_REQUIRED },
+ { ".setframe", "gas", dir_setframe, YASM_DIR_ARG_REQUIRED },
+ { "setframe", "nasm", dir_setframe, YASM_DIR_ARG_REQUIRED },
+ { ".allocstack", "gas", dir_allocstack, YASM_DIR_ARG_REQUIRED },
+ { "allocstack", "nasm", dir_allocstack, YASM_DIR_ARG_REQUIRED },
+ { ".savereg", "gas", dir_savereg, YASM_DIR_ARG_REQUIRED },
+ { "savereg", "nasm", dir_savereg, YASM_DIR_ARG_REQUIRED },
+ { ".savexmm128", "gas", dir_savexmm128, YASM_DIR_ARG_REQUIRED },
+ { "savexmm128", "nasm", dir_savexmm128, YASM_DIR_ARG_REQUIRED },
+ { ".pushframe", "gas", dir_pushframe, YASM_DIR_ANY },
+ { "pushframe", "nasm", dir_pushframe, YASM_DIR_ANY },
+ { ".endprolog", "gas", dir_endprolog, YASM_DIR_ANY },
+ { "endprolog", "nasm", dir_endprolog, YASM_DIR_ANY },
+ { ".endproc_frame", "gas", dir_endproc_frame, YASM_DIR_ANY },
+ { "endproc_frame", "nasm", dir_endproc_frame, YASM_DIR_ANY },
+ { NULL, NULL, NULL, 0 }
+};
+
+#include "win64-nasm.c"
+#include "win64-gas.c"
+
+static const yasm_stdmac win64_objfmt_stdmacs[] = {
+ { "nasm", "nasm", win64_nasm_stdmac },
+ { "gas", "nasm", win64_gas_stdmac },
+ { NULL, NULL, NULL }
+};
+
+/* Define objfmt structure -- see objfmt.h for details */
+yasm_objfmt_module yasm_win64_LTX_objfmt = {
+ "Win64",
+ "win64",
+ "obj",
+ 64,
+ 1,
+ winXX_objfmt_dbgfmt_keywords,
+ "null",
+ win64_objfmt_directives,
+ win64_objfmt_stdmacs,
+ win64_objfmt_create,
+ coff_objfmt_output,
+ coff_objfmt_destroy,
+ coff_objfmt_add_default_section,
+ coff_objfmt_init_new_section,
+ coff_objfmt_section_switch,
+ win64_objfmt_get_special_sym
+};
+yasm_objfmt_module yasm_x64_LTX_objfmt = {
+ "Win64",
+ "x64",
+ "obj",
+ 64,
+ 1,
+ winXX_objfmt_dbgfmt_keywords,
+ "null",
+ win64_objfmt_directives,
+ win64_objfmt_stdmacs,
+ win64_objfmt_create,
+ coff_objfmt_output,
+ coff_objfmt_destroy,
+ coff_objfmt_add_default_section,
+ coff_objfmt_init_new_section,
+ coff_objfmt_section_switch,
+ win64_objfmt_get_special_sym
+};
diff --git a/contrib/tools/yasm/modules/objfmts/coff/coff-objfmt.h b/contrib/tools/yasm/modules/objfmts/coff/coff-objfmt.h
index 10d88a0982..cdd581acb2 100644
--- a/contrib/tools/yasm/modules/objfmts/coff/coff-objfmt.h
+++ b/contrib/tools/yasm/modules/objfmts/coff/coff-objfmt.h
@@ -1,77 +1,77 @@
-/*
- * COFF (DJGPP) object format
- *
- * Copyright (C) 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.
- */
-#ifndef COFF_OBJFMT_H
-#define COFF_OBJFMT_H
-
-typedef struct coff_unwind_code {
- SLIST_ENTRY(coff_unwind_code) link;
-
- /*@dependent@*/ yasm_symrec *proc; /* Start of procedure */
- /*@dependent@*/ yasm_symrec *loc; /* Location of operation */
- /* Unwind operation code */
- enum {
- UWOP_PUSH_NONVOL = 0,
- UWOP_ALLOC_LARGE = 1,
- UWOP_ALLOC_SMALL = 2,
- UWOP_SET_FPREG = 3,
- UWOP_SAVE_NONVOL = 4,
- UWOP_SAVE_NONVOL_FAR = 5,
- UWOP_SAVE_XMM128 = 8,
- UWOP_SAVE_XMM128_FAR = 9,
- UWOP_PUSH_MACHFRAME = 10
- } opcode;
- unsigned int info; /* Operation info */
- yasm_value off; /* Offset expression (used for some codes) */
-} coff_unwind_code;
-
-typedef struct coff_unwind_info {
- /*@dependent@*/ yasm_symrec *proc; /* Start of procedure */
- /*@dependent@*/ yasm_symrec *prolog; /* End of prologue */
-
- /*@null@*/ /*@dependent@*/ yasm_symrec *ehandler; /* Error handler */
-
- unsigned long framereg; /* Frame register */
- yasm_value frameoff; /* Frame offset */
-
- /* Linked list of codes, in decreasing location offset order.
- * Inserting at the head of this list during assembly naturally results
- * in this sorting.
- */
- SLIST_HEAD(coff_unwind_code_head, coff_unwind_code) codes;
-
- /* These aren't used until inside of generate. */
- yasm_value prolog_size;
- yasm_value codes_count;
-} coff_unwind_info;
-
-coff_unwind_info *yasm_win64__uwinfo_create(void);
-void yasm_win64__uwinfo_destroy(coff_unwind_info *info);
-void yasm_win64__unwind_generate(yasm_section *xdata,
- /*@only@*/ coff_unwind_info *info,
- unsigned long line);
-
-#endif
+/*
+ * COFF (DJGPP) object format
+ *
+ * Copyright (C) 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.
+ */
+#ifndef COFF_OBJFMT_H
+#define COFF_OBJFMT_H
+
+typedef struct coff_unwind_code {
+ SLIST_ENTRY(coff_unwind_code) link;
+
+ /*@dependent@*/ yasm_symrec *proc; /* Start of procedure */
+ /*@dependent@*/ yasm_symrec *loc; /* Location of operation */
+ /* Unwind operation code */
+ enum {
+ UWOP_PUSH_NONVOL = 0,
+ UWOP_ALLOC_LARGE = 1,
+ UWOP_ALLOC_SMALL = 2,
+ UWOP_SET_FPREG = 3,
+ UWOP_SAVE_NONVOL = 4,
+ UWOP_SAVE_NONVOL_FAR = 5,
+ UWOP_SAVE_XMM128 = 8,
+ UWOP_SAVE_XMM128_FAR = 9,
+ UWOP_PUSH_MACHFRAME = 10
+ } opcode;
+ unsigned int info; /* Operation info */
+ yasm_value off; /* Offset expression (used for some codes) */
+} coff_unwind_code;
+
+typedef struct coff_unwind_info {
+ /*@dependent@*/ yasm_symrec *proc; /* Start of procedure */
+ /*@dependent@*/ yasm_symrec *prolog; /* End of prologue */
+
+ /*@null@*/ /*@dependent@*/ yasm_symrec *ehandler; /* Error handler */
+
+ unsigned long framereg; /* Frame register */
+ yasm_value frameoff; /* Frame offset */
+
+ /* Linked list of codes, in decreasing location offset order.
+ * Inserting at the head of this list during assembly naturally results
+ * in this sorting.
+ */
+ SLIST_HEAD(coff_unwind_code_head, coff_unwind_code) codes;
+
+ /* These aren't used until inside of generate. */
+ yasm_value prolog_size;
+ yasm_value codes_count;
+} coff_unwind_info;
+
+coff_unwind_info *yasm_win64__uwinfo_create(void);
+void yasm_win64__uwinfo_destroy(coff_unwind_info *info);
+void yasm_win64__unwind_generate(yasm_section *xdata,
+ /*@only@*/ coff_unwind_info *info,
+ unsigned long line);
+
+#endif
diff --git a/contrib/tools/yasm/modules/objfmts/coff/win64-except.c b/contrib/tools/yasm/modules/objfmts/coff/win64-except.c
index 8c8ecbbc49..8fe585df8c 100644
--- a/contrib/tools/yasm/modules/objfmts/coff/win64-except.c
+++ b/contrib/tools/yasm/modules/objfmts/coff/win64-except.c
@@ -1,559 +1,559 @@
-/*
- * Win64 structured exception handling support
- *
- * Copyright (C) 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>
-
-#include <libyasm.h>
-
-#include "coff-objfmt.h"
-
-
-#define UNW_FLAG_EHANDLER 0x01
-#define UNW_FLAG_UHANDLER 0x02
-#define UNW_FLAG_CHAININFO 0x04
-
-/* Bytecode callback function prototypes */
-static void win64_uwinfo_bc_destroy(void *contents);
-static void win64_uwinfo_bc_print(const void *contents, FILE *f,
- int indent_level);
-static void win64_uwinfo_bc_finalize(yasm_bytecode *bc,
- yasm_bytecode *prev_bc);
-static int win64_uwinfo_bc_calc_len
- (yasm_bytecode *bc, yasm_bc_add_span_func add_span, void *add_span_data);
-static int win64_uwinfo_bc_expand(yasm_bytecode *bc, int span, long old_val,
- long new_val, /*@out@*/ long *neg_thres,
- /*@out@*/ long *pos_thres);
-static int win64_uwinfo_bc_tobytes
- (yasm_bytecode *bc, unsigned char **bufp, unsigned char *bufstart, void *d,
- yasm_output_value_func output_value,
- /*@null@*/ yasm_output_reloc_func output_reloc);
-
-static void win64_uwcode_bc_destroy(void *contents);
-static void win64_uwcode_bc_print(const void *contents, FILE *f,
- int indent_level);
-static void win64_uwcode_bc_finalize(yasm_bytecode *bc,
- yasm_bytecode *prev_bc);
-static int win64_uwcode_bc_calc_len
- (yasm_bytecode *bc, yasm_bc_add_span_func add_span, void *add_span_data);
-static int win64_uwcode_bc_expand(yasm_bytecode *bc, int span, long old_val,
- long new_val, /*@out@*/ long *neg_thres,
- /*@out@*/ long *pos_thres);
-static int win64_uwcode_bc_tobytes
- (yasm_bytecode *bc, unsigned char **bufp, unsigned char *bufstart, void *d,
- yasm_output_value_func output_value,
- /*@null@*/ yasm_output_reloc_func output_reloc);
-
-/* Bytecode callback structures */
-static const yasm_bytecode_callback win64_uwinfo_bc_callback = {
- win64_uwinfo_bc_destroy,
- win64_uwinfo_bc_print,
- win64_uwinfo_bc_finalize,
- NULL,
- win64_uwinfo_bc_calc_len,
- win64_uwinfo_bc_expand,
- win64_uwinfo_bc_tobytes,
- 0
-};
-
-static const yasm_bytecode_callback win64_uwcode_bc_callback = {
- win64_uwcode_bc_destroy,
- win64_uwcode_bc_print,
- win64_uwcode_bc_finalize,
- NULL,
- win64_uwcode_bc_calc_len,
- win64_uwcode_bc_expand,
- win64_uwcode_bc_tobytes,
- 0
-};
-
-
-coff_unwind_info *
-yasm_win64__uwinfo_create(void)
-{
- coff_unwind_info *info = yasm_xmalloc(sizeof(coff_unwind_info));
- info->proc = NULL;
- info->prolog = NULL;
- info->ehandler = NULL;
- info->framereg = 0;
- /* Frameoff is really a 4-bit value, scaled by 16 */
- yasm_value_initialize(&info->frameoff, NULL, 8);
- SLIST_INIT(&info->codes);
- yasm_value_initialize(&info->prolog_size, NULL, 8);
- yasm_value_initialize(&info->codes_count, NULL, 8);
- return info;
-}
-
-void
-yasm_win64__uwinfo_destroy(coff_unwind_info *info)
-{
- coff_unwind_code *code;
-
- yasm_value_delete(&info->frameoff);
- yasm_value_delete(&info->prolog_size);
- yasm_value_delete(&info->codes_count);
-
- while (!SLIST_EMPTY(&info->codes)) {
- code = SLIST_FIRST(&info->codes);
- SLIST_REMOVE_HEAD(&info->codes, link);
- yasm_value_delete(&code->off);
- yasm_xfree(code);
- }
- yasm_xfree(info);
-}
-
-void
-yasm_win64__unwind_generate(yasm_section *xdata, coff_unwind_info *info,
- unsigned long line)
-{
- yasm_bytecode *infobc, *codebc = NULL;
- coff_unwind_code *code;
-
- /* 4-byte align the start of unwind info */
- yasm_section_bcs_append(xdata, yasm_bc_create_align(
- yasm_expr_create_ident(yasm_expr_int(yasm_intnum_create_uint(4)),
- line),
- NULL, NULL, NULL, line));
-
- /* Prolog size = end of prolog - start of procedure */
- yasm_value_initialize(&info->prolog_size,
- yasm_expr_create(YASM_EXPR_SUB, yasm_expr_sym(info->prolog),
- yasm_expr_sym(info->proc), line),
- 8);
-
- /* Unwind info */
- infobc = yasm_bc_create_common(&win64_uwinfo_bc_callback, info, line);
- yasm_section_bcs_append(xdata, infobc);
-
- /* Code array */
- SLIST_FOREACH(code, &info->codes, link) {
- codebc = yasm_bc_create_common(&win64_uwcode_bc_callback, code,
- yasm_symrec_get_def_line(code->loc));
- yasm_section_bcs_append(xdata, codebc);
- }
-
- /* Avoid double-free (by code destroy and uwinfo destroy). */
- SLIST_INIT(&info->codes);
-
- /* Number of codes = (Last code - end of info) >> 1 */
- if (!codebc) {
- yasm_value_initialize(&info->codes_count,
- yasm_expr_create_ident(yasm_expr_int(yasm_intnum_create_uint(0)),
- line),
- 8);
- } else {
- yasm_value_initialize(&info->codes_count,
- yasm_expr_create(YASM_EXPR_SHR, yasm_expr_expr(
- yasm_expr_create(YASM_EXPR_SUB, yasm_expr_precbc(codebc),
- yasm_expr_precbc(infobc), line)),
- yasm_expr_int(yasm_intnum_create_uint(1)), line),
- 8);
- }
-
- /* 4-byte align */
- yasm_section_bcs_append(xdata, yasm_bc_create_align(
- yasm_expr_create_ident(yasm_expr_int(yasm_intnum_create_uint(4)),
- line),
- NULL, NULL, NULL, line));
-
- /* Exception handler, if present. Use data bytecode. */
- if (info->ehandler) {
- yasm_datavalhead dvs;
-
- yasm_dvs_initialize(&dvs);
- yasm_dvs_append(&dvs, yasm_dv_create_expr(
- yasm_expr_create_ident(yasm_expr_sym(info->ehandler), line)));
- yasm_section_bcs_append(xdata,
- yasm_bc_create_data(&dvs, 4, 0, NULL, line));
- }
-}
-
-static void
-win64_uwinfo_bc_destroy(void *contents)
-{
- yasm_win64__uwinfo_destroy((coff_unwind_info *)contents);
-}
-
-static void
-win64_uwinfo_bc_print(const void *contents, FILE *f, int indent_level)
-{
- /* TODO */
-}
-
-static void
-win64_uwinfo_bc_finalize(yasm_bytecode *bc, yasm_bytecode *prev_bc)
-{
- coff_unwind_info *info = (coff_unwind_info *)bc->contents;
-
- if (yasm_value_finalize(&info->prolog_size, prev_bc))
- yasm_internal_error(N_("prolog size expression too complex"));
-
- if (yasm_value_finalize(&info->codes_count, prev_bc))
- yasm_internal_error(N_("codes count expression too complex"));
-
- if (yasm_value_finalize(&info->frameoff, prev_bc))
- yasm_error_set(YASM_ERROR_VALUE,
- N_("frame offset expression too complex"));
-}
-
-static int
-win64_uwinfo_bc_calc_len(yasm_bytecode *bc, yasm_bc_add_span_func add_span,
- void *add_span_data)
-{
- coff_unwind_info *info = (coff_unwind_info *)bc->contents;
- /*@only@*/ /*@null@*/ yasm_intnum *intn;
- long intv;
-
- /* Want to make sure prolog size and codes count doesn't exceed
- * byte-size, and scaled frame offset doesn't exceed 4 bits.
- */
- add_span(add_span_data, bc, 1, &info->prolog_size, 0, 255);
- add_span(add_span_data, bc, 2, &info->codes_count, 0, 255);
-
- intn = yasm_value_get_intnum(&info->frameoff, bc, 0);
- if (intn) {
- intv = yasm_intnum_get_int(intn);
- if (intv < 0 || intv > 240)
- yasm_error_set(YASM_ERROR_VALUE,
- N_("frame offset of %ld bytes, must be between 0 and 240"),
- intv);
- else if ((intv & 0xF) != 0)
- yasm_error_set(YASM_ERROR_VALUE,
- N_("frame offset of %ld is not a multiple of 16"), intv);
- yasm_intnum_destroy(intn);
- } else
- add_span(add_span_data, bc, 3, &info->frameoff, 0, 240);
-
- bc->len += 4;
- return 0;
-}
-
-static int
-win64_uwinfo_bc_expand(yasm_bytecode *bc, int span, long old_val, long new_val,
- /*@out@*/ long *neg_thres, /*@out@*/ long *pos_thres)
-{
- coff_unwind_info *info = (coff_unwind_info *)bc->contents;
- switch (span) {
- case 1:
- yasm_error_set_xref(yasm_symrec_get_def_line(info->prolog),
- N_("prologue ended here"));
- yasm_error_set(YASM_ERROR_VALUE,
- N_("prologue %ld bytes, must be <256"), new_val);
- return -1;
- case 2:
- yasm_error_set(YASM_ERROR_VALUE,
- N_("%ld unwind codes, maximum of 255"), new_val);
- return -1;
- case 3:
- yasm_error_set(YASM_ERROR_VALUE,
- N_("frame offset of %ld bytes, must be between 0 and 240"),
- new_val);
- return -1;
- default:
- yasm_internal_error(N_("unrecognized span id"));
- }
- return 0;
-}
-
-static int
-win64_uwinfo_bc_tobytes(yasm_bytecode *bc, unsigned char **bufp,
- unsigned char *bufstart, void *d,
- yasm_output_value_func output_value,
- yasm_output_reloc_func output_reloc)
-{
- coff_unwind_info *info = (coff_unwind_info *)bc->contents;
- unsigned char *buf = *bufp;
- /*@only@*/ /*@null@*/ yasm_intnum *frameoff;
- long intv;
-
- /* Version and flags */
- if (info->ehandler)
- YASM_WRITE_8(buf, 1 | (UNW_FLAG_EHANDLER << 3));
- else
- YASM_WRITE_8(buf, 1);
-
- /* Size of prolog */
- output_value(&info->prolog_size, buf, 1, (unsigned long)(buf-bufstart),
- bc, 1, d);
- buf += 1;
-
- /* Count of codes */
- output_value(&info->codes_count, buf, 1, (unsigned long)(buf-bufstart),
- bc, 1, d);
- buf += 1;
-
- /* Frame register and offset */
- frameoff = yasm_value_get_intnum(&info->frameoff, bc, 1);
- if (!frameoff) {
- yasm_error_set(YASM_ERROR_VALUE,
- N_("frame offset expression too complex"));
- return 1;
- }
- intv = yasm_intnum_get_int(frameoff);
- if (intv < 0 || intv > 240)
- yasm_error_set(YASM_ERROR_VALUE,
- N_("frame offset of %ld bytes, must be between 0 and 240"), intv);
- else if ((intv & 0xF) != 0)
- yasm_error_set(YASM_ERROR_VALUE,
- N_("frame offset of %ld is not a multiple of 16"), intv);
-
- YASM_WRITE_8(buf, ((unsigned long)intv & 0xF0) | (info->framereg & 0x0F));
- yasm_intnum_destroy(frameoff);
-
- *bufp = buf;
- return 0;
-}
-
-static void
-win64_uwcode_bc_destroy(void *contents)
-{
- coff_unwind_code *code = (coff_unwind_code *)contents;
- yasm_value_delete(&code->off);
- yasm_xfree(contents);
-}
-
-static void
-win64_uwcode_bc_print(const void *contents, FILE *f, int indent_level)
-{
- /* TODO */
-}
-
-static void
-win64_uwcode_bc_finalize(yasm_bytecode *bc, yasm_bytecode *prev_bc)
-{
- coff_unwind_code *code = (coff_unwind_code *)bc->contents;
- if (yasm_value_finalize(&code->off, prev_bc))
- yasm_error_set(YASM_ERROR_VALUE, N_("offset expression too complex"));
-}
-
-static int
-win64_uwcode_bc_calc_len(yasm_bytecode *bc, yasm_bc_add_span_func add_span,
- void *add_span_data)
-{
- coff_unwind_code *code = (coff_unwind_code *)bc->contents;
- int span = 0;
- /*@only@*/ /*@null@*/ yasm_intnum *intn;
- long intv;
- long low, high, mask;
-
- bc->len += 2; /* Prolog offset, code, and info */
-
- switch (code->opcode) {
- case UWOP_PUSH_NONVOL:
- case UWOP_SET_FPREG:
- case UWOP_PUSH_MACHFRAME:
- /* always 1 node */
- return 0;
- case UWOP_ALLOC_SMALL:
- case UWOP_ALLOC_LARGE:
- /* Start with smallest, then work our way up as necessary */
- code->opcode = UWOP_ALLOC_SMALL;
- code->info = 0;
- span = 1; low = 8; high = 128; mask = 0x7;
- break;
- case UWOP_SAVE_NONVOL:
- case UWOP_SAVE_NONVOL_FAR:
- /* Start with smallest, then work our way up as necessary */
- code->opcode = UWOP_SAVE_NONVOL;
- bc->len += 2; /* Scaled offset */
- span = 2;
- low = 0;
- high = 8*64*1024-8; /* 16-bit field, *8 scaling */
- mask = 0x7;
- break;
- case UWOP_SAVE_XMM128:
- case UWOP_SAVE_XMM128_FAR:
- /* Start with smallest, then work our way up as necessary */
- code->opcode = UWOP_SAVE_XMM128;
- bc->len += 2; /* Scaled offset */
- span = 3;
- low = 0;
- high = 16*64*1024-16; /* 16-bit field, *16 scaling */
- mask = 0xF;
- break;
- default:
- yasm_internal_error(N_("unrecognied unwind opcode"));
- /*@unreached@*/
- return 0;
- }
-
- intn = yasm_value_get_intnum(&code->off, bc, 0);
- if (intn) {
- intv = yasm_intnum_get_int(intn);
- if (intv > high) {
- /* Expand it ourselves here if we can and we're already larger */
- if (win64_uwcode_bc_expand(bc, span, intv, intv, &low, &high) > 0)
- add_span(add_span_data, bc, span, &code->off, low, high);
- }
- if (intv < low)
- yasm_error_set(YASM_ERROR_VALUE,
- N_("negative offset not allowed"));
- if ((intv & mask) != 0)
- yasm_error_set(YASM_ERROR_VALUE,
- N_("offset of %ld is not a multiple of %ld"), intv, mask+1);
- yasm_intnum_destroy(intn);
- } else
- add_span(add_span_data, bc, span, &code->off, low, high);
- return 0;
-}
-
-static int
-win64_uwcode_bc_expand(yasm_bytecode *bc, int span, long old_val, long new_val,
- /*@out@*/ long *neg_thres, /*@out@*/ long *pos_thres)
-{
- coff_unwind_code *code = (coff_unwind_code *)bc->contents;
-
- if (new_val < 0) {
- yasm_error_set(YASM_ERROR_VALUE, N_("negative offset not allowed"));
- return -1;
- }
-
- if (span == 1) {
- /* 3 stages: SMALL, LARGE and info=0, LARGE and info=1 */
- if (code->opcode == UWOP_ALLOC_LARGE && code->info == 1)
- yasm_internal_error(N_("expansion on already largest alloc"));
-
- if (code->opcode == UWOP_ALLOC_SMALL && new_val > 128) {
- /* Overflowed small size */
- code->opcode = UWOP_ALLOC_LARGE;
- bc->len += 2;
- }
- if (new_val <= 8*64*1024-8) {
- /* Still can grow one more size */
- *pos_thres = 8*64*1024-8;
- return 1;
- }
- /* We're into the largest size */
- code->info = 1;
- bc->len += 2;
- } else if (code->opcode == UWOP_SAVE_NONVOL && span == 2) {
- code->opcode = UWOP_SAVE_NONVOL_FAR;
- bc->len += 2;
- } else if (code->opcode == UWOP_SAVE_XMM128 && span == 3) {
- code->opcode = UWOP_SAVE_XMM128_FAR;
- bc->len += 2;
- }
- return 0;
-}
-
-static int
-win64_uwcode_bc_tobytes(yasm_bytecode *bc, unsigned char **bufp,
- unsigned char *bufstart, void *d,
- yasm_output_value_func output_value,
- yasm_output_reloc_func output_reloc)
-{
- coff_unwind_code *code = (coff_unwind_code *)bc->contents;
- unsigned char *buf = *bufp;
- yasm_value val;
- unsigned int size;
- int shift;
- long intv, low, high, mask;
- yasm_intnum *intn;
-
- /* Offset in prolog */
- yasm_value_initialize(&val,
- yasm_expr_create(YASM_EXPR_SUB, yasm_expr_sym(code->loc),
- yasm_expr_sym(code->proc), bc->line),
- 8);
- output_value(&val, buf, 1, (unsigned long)(buf-bufstart), bc, 1, d);
- buf += 1;
- yasm_value_delete(&val);
-
- /* Offset value */
- switch (code->opcode) {
- case UWOP_PUSH_NONVOL:
- case UWOP_SET_FPREG:
- case UWOP_PUSH_MACHFRAME:
- /* just 1 node, no offset; write opcode and info and we're done */
- YASM_WRITE_8(buf, (code->info << 4) | (code->opcode & 0xF));
- *bufp = buf;
- return 0;
- case UWOP_ALLOC_SMALL:
- /* 1 node, but offset stored in info */
- size = 0; low = 8; high = 128; shift = 3; mask = 0x7;
- break;
- case UWOP_ALLOC_LARGE:
- if (code->info == 0) {
- size = 2; low = 136; high = 8*64*1024-8; shift = 3;
- } else {
- size = 4; low = high = 0; shift = 0;
- }
- mask = 0x7;
- break;
- case UWOP_SAVE_NONVOL:
- size = 2; low = 0; high = 8*64*1024-8; shift = 3; mask = 0x7;
- break;
- case UWOP_SAVE_XMM128:
- size = 2; low = 0; high = 16*64*1024-16; shift = 4; mask = 0xF;
- break;
- case UWOP_SAVE_NONVOL_FAR:
- size = 4; low = high = 0; shift = 0; mask = 0x7;
- break;
- case UWOP_SAVE_XMM128_FAR:
- size = 4; low = high = 0; shift = 0; mask = 0xF;
- break;
- default:
- yasm_internal_error(N_("unrecognied unwind opcode"));
- /*@unreached@*/
- return 1;
- }
-
- /* Check for overflow */
- intn = yasm_value_get_intnum(&code->off, bc, 1);
- if (!intn) {
- yasm_error_set(YASM_ERROR_VALUE, N_("offset expression too complex"));
- return 1;
- }
- intv = yasm_intnum_get_int(intn);
- if (size != 4 && (intv < low || intv > high)) {
- yasm_error_set(YASM_ERROR_VALUE,
- N_("offset of %ld bytes, must be between %ld and %ld"),
- intv, low, high);
- return 1;
- }
- if ((intv & mask) != 0) {
- yasm_error_set(YASM_ERROR_VALUE,
- N_("offset of %ld is not a multiple of %ld"),
- intv, mask+1);
- return 1;
- }
-
- /* Stored value in info instead of extra code space */
- if (size == 0)
- code->info = (yasm_intnum_get_uint(intn) >> shift)-1;
-
- /* Opcode and info */
- YASM_WRITE_8(buf, (code->info << 4) | (code->opcode & 0xF));
-
- if (size != 0) {
- yasm_intnum_get_sized(intn, buf, size, size*8, -shift, 0, 1);
- buf += size;
- }
-
- yasm_intnum_destroy(intn);
-
- *bufp = buf;
- return 0;
-}
+/*
+ * Win64 structured exception handling support
+ *
+ * Copyright (C) 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>
+
+#include <libyasm.h>
+
+#include "coff-objfmt.h"
+
+
+#define UNW_FLAG_EHANDLER 0x01
+#define UNW_FLAG_UHANDLER 0x02
+#define UNW_FLAG_CHAININFO 0x04
+
+/* Bytecode callback function prototypes */
+static void win64_uwinfo_bc_destroy(void *contents);
+static void win64_uwinfo_bc_print(const void *contents, FILE *f,
+ int indent_level);
+static void win64_uwinfo_bc_finalize(yasm_bytecode *bc,
+ yasm_bytecode *prev_bc);
+static int win64_uwinfo_bc_calc_len
+ (yasm_bytecode *bc, yasm_bc_add_span_func add_span, void *add_span_data);
+static int win64_uwinfo_bc_expand(yasm_bytecode *bc, int span, long old_val,
+ long new_val, /*@out@*/ long *neg_thres,
+ /*@out@*/ long *pos_thres);
+static int win64_uwinfo_bc_tobytes
+ (yasm_bytecode *bc, unsigned char **bufp, unsigned char *bufstart, void *d,
+ yasm_output_value_func output_value,
+ /*@null@*/ yasm_output_reloc_func output_reloc);
+
+static void win64_uwcode_bc_destroy(void *contents);
+static void win64_uwcode_bc_print(const void *contents, FILE *f,
+ int indent_level);
+static void win64_uwcode_bc_finalize(yasm_bytecode *bc,
+ yasm_bytecode *prev_bc);
+static int win64_uwcode_bc_calc_len
+ (yasm_bytecode *bc, yasm_bc_add_span_func add_span, void *add_span_data);
+static int win64_uwcode_bc_expand(yasm_bytecode *bc, int span, long old_val,
+ long new_val, /*@out@*/ long *neg_thres,
+ /*@out@*/ long *pos_thres);
+static int win64_uwcode_bc_tobytes
+ (yasm_bytecode *bc, unsigned char **bufp, unsigned char *bufstart, void *d,
+ yasm_output_value_func output_value,
+ /*@null@*/ yasm_output_reloc_func output_reloc);
+
+/* Bytecode callback structures */
+static const yasm_bytecode_callback win64_uwinfo_bc_callback = {
+ win64_uwinfo_bc_destroy,
+ win64_uwinfo_bc_print,
+ win64_uwinfo_bc_finalize,
+ NULL,
+ win64_uwinfo_bc_calc_len,
+ win64_uwinfo_bc_expand,
+ win64_uwinfo_bc_tobytes,
+ 0
+};
+
+static const yasm_bytecode_callback win64_uwcode_bc_callback = {
+ win64_uwcode_bc_destroy,
+ win64_uwcode_bc_print,
+ win64_uwcode_bc_finalize,
+ NULL,
+ win64_uwcode_bc_calc_len,
+ win64_uwcode_bc_expand,
+ win64_uwcode_bc_tobytes,
+ 0
+};
+
+
+coff_unwind_info *
+yasm_win64__uwinfo_create(void)
+{
+ coff_unwind_info *info = yasm_xmalloc(sizeof(coff_unwind_info));
+ info->proc = NULL;
+ info->prolog = NULL;
+ info->ehandler = NULL;
+ info->framereg = 0;
+ /* Frameoff is really a 4-bit value, scaled by 16 */
+ yasm_value_initialize(&info->frameoff, NULL, 8);
+ SLIST_INIT(&info->codes);
+ yasm_value_initialize(&info->prolog_size, NULL, 8);
+ yasm_value_initialize(&info->codes_count, NULL, 8);
+ return info;
+}
+
+void
+yasm_win64__uwinfo_destroy(coff_unwind_info *info)
+{
+ coff_unwind_code *code;
+
+ yasm_value_delete(&info->frameoff);
+ yasm_value_delete(&info->prolog_size);
+ yasm_value_delete(&info->codes_count);
+
+ while (!SLIST_EMPTY(&info->codes)) {
+ code = SLIST_FIRST(&info->codes);
+ SLIST_REMOVE_HEAD(&info->codes, link);
+ yasm_value_delete(&code->off);
+ yasm_xfree(code);
+ }
+ yasm_xfree(info);
+}
+
+void
+yasm_win64__unwind_generate(yasm_section *xdata, coff_unwind_info *info,
+ unsigned long line)
+{
+ yasm_bytecode *infobc, *codebc = NULL;
+ coff_unwind_code *code;
+
+ /* 4-byte align the start of unwind info */
+ yasm_section_bcs_append(xdata, yasm_bc_create_align(
+ yasm_expr_create_ident(yasm_expr_int(yasm_intnum_create_uint(4)),
+ line),
+ NULL, NULL, NULL, line));
+
+ /* Prolog size = end of prolog - start of procedure */
+ yasm_value_initialize(&info->prolog_size,
+ yasm_expr_create(YASM_EXPR_SUB, yasm_expr_sym(info->prolog),
+ yasm_expr_sym(info->proc), line),
+ 8);
+
+ /* Unwind info */
+ infobc = yasm_bc_create_common(&win64_uwinfo_bc_callback, info, line);
+ yasm_section_bcs_append(xdata, infobc);
+
+ /* Code array */
+ SLIST_FOREACH(code, &info->codes, link) {
+ codebc = yasm_bc_create_common(&win64_uwcode_bc_callback, code,
+ yasm_symrec_get_def_line(code->loc));
+ yasm_section_bcs_append(xdata, codebc);
+ }
+
+ /* Avoid double-free (by code destroy and uwinfo destroy). */
+ SLIST_INIT(&info->codes);
+
+ /* Number of codes = (Last code - end of info) >> 1 */
+ if (!codebc) {
+ yasm_value_initialize(&info->codes_count,
+ yasm_expr_create_ident(yasm_expr_int(yasm_intnum_create_uint(0)),
+ line),
+ 8);
+ } else {
+ yasm_value_initialize(&info->codes_count,
+ yasm_expr_create(YASM_EXPR_SHR, yasm_expr_expr(
+ yasm_expr_create(YASM_EXPR_SUB, yasm_expr_precbc(codebc),
+ yasm_expr_precbc(infobc), line)),
+ yasm_expr_int(yasm_intnum_create_uint(1)), line),
+ 8);
+ }
+
+ /* 4-byte align */
+ yasm_section_bcs_append(xdata, yasm_bc_create_align(
+ yasm_expr_create_ident(yasm_expr_int(yasm_intnum_create_uint(4)),
+ line),
+ NULL, NULL, NULL, line));
+
+ /* Exception handler, if present. Use data bytecode. */
+ if (info->ehandler) {
+ yasm_datavalhead dvs;
+
+ yasm_dvs_initialize(&dvs);
+ yasm_dvs_append(&dvs, yasm_dv_create_expr(
+ yasm_expr_create_ident(yasm_expr_sym(info->ehandler), line)));
+ yasm_section_bcs_append(xdata,
+ yasm_bc_create_data(&dvs, 4, 0, NULL, line));
+ }
+}
+
+static void
+win64_uwinfo_bc_destroy(void *contents)
+{
+ yasm_win64__uwinfo_destroy((coff_unwind_info *)contents);
+}
+
+static void
+win64_uwinfo_bc_print(const void *contents, FILE *f, int indent_level)
+{
+ /* TODO */
+}
+
+static void
+win64_uwinfo_bc_finalize(yasm_bytecode *bc, yasm_bytecode *prev_bc)
+{
+ coff_unwind_info *info = (coff_unwind_info *)bc->contents;
+
+ if (yasm_value_finalize(&info->prolog_size, prev_bc))
+ yasm_internal_error(N_("prolog size expression too complex"));
+
+ if (yasm_value_finalize(&info->codes_count, prev_bc))
+ yasm_internal_error(N_("codes count expression too complex"));
+
+ if (yasm_value_finalize(&info->frameoff, prev_bc))
+ yasm_error_set(YASM_ERROR_VALUE,
+ N_("frame offset expression too complex"));
+}
+
+static int
+win64_uwinfo_bc_calc_len(yasm_bytecode *bc, yasm_bc_add_span_func add_span,
+ void *add_span_data)
+{
+ coff_unwind_info *info = (coff_unwind_info *)bc->contents;
+ /*@only@*/ /*@null@*/ yasm_intnum *intn;
+ long intv;
+
+ /* Want to make sure prolog size and codes count doesn't exceed
+ * byte-size, and scaled frame offset doesn't exceed 4 bits.
+ */
+ add_span(add_span_data, bc, 1, &info->prolog_size, 0, 255);
+ add_span(add_span_data, bc, 2, &info->codes_count, 0, 255);
+
+ intn = yasm_value_get_intnum(&info->frameoff, bc, 0);
+ if (intn) {
+ intv = yasm_intnum_get_int(intn);
+ if (intv < 0 || intv > 240)
+ yasm_error_set(YASM_ERROR_VALUE,
+ N_("frame offset of %ld bytes, must be between 0 and 240"),
+ intv);
+ else if ((intv & 0xF) != 0)
+ yasm_error_set(YASM_ERROR_VALUE,
+ N_("frame offset of %ld is not a multiple of 16"), intv);
+ yasm_intnum_destroy(intn);
+ } else
+ add_span(add_span_data, bc, 3, &info->frameoff, 0, 240);
+
+ bc->len += 4;
+ return 0;
+}
+
+static int
+win64_uwinfo_bc_expand(yasm_bytecode *bc, int span, long old_val, long new_val,
+ /*@out@*/ long *neg_thres, /*@out@*/ long *pos_thres)
+{
+ coff_unwind_info *info = (coff_unwind_info *)bc->contents;
+ switch (span) {
+ case 1:
+ yasm_error_set_xref(yasm_symrec_get_def_line(info->prolog),
+ N_("prologue ended here"));
+ yasm_error_set(YASM_ERROR_VALUE,
+ N_("prologue %ld bytes, must be <256"), new_val);
+ return -1;
+ case 2:
+ yasm_error_set(YASM_ERROR_VALUE,
+ N_("%ld unwind codes, maximum of 255"), new_val);
+ return -1;
+ case 3:
+ yasm_error_set(YASM_ERROR_VALUE,
+ N_("frame offset of %ld bytes, must be between 0 and 240"),
+ new_val);
+ return -1;
+ default:
+ yasm_internal_error(N_("unrecognized span id"));
+ }
+ return 0;
+}
+
+static int
+win64_uwinfo_bc_tobytes(yasm_bytecode *bc, unsigned char **bufp,
+ unsigned char *bufstart, void *d,
+ yasm_output_value_func output_value,
+ yasm_output_reloc_func output_reloc)
+{
+ coff_unwind_info *info = (coff_unwind_info *)bc->contents;
+ unsigned char *buf = *bufp;
+ /*@only@*/ /*@null@*/ yasm_intnum *frameoff;
+ long intv;
+
+ /* Version and flags */
+ if (info->ehandler)
+ YASM_WRITE_8(buf, 1 | (UNW_FLAG_EHANDLER << 3));
+ else
+ YASM_WRITE_8(buf, 1);
+
+ /* Size of prolog */
+ output_value(&info->prolog_size, buf, 1, (unsigned long)(buf-bufstart),
+ bc, 1, d);
+ buf += 1;
+
+ /* Count of codes */
+ output_value(&info->codes_count, buf, 1, (unsigned long)(buf-bufstart),
+ bc, 1, d);
+ buf += 1;
+
+ /* Frame register and offset */
+ frameoff = yasm_value_get_intnum(&info->frameoff, bc, 1);
+ if (!frameoff) {
+ yasm_error_set(YASM_ERROR_VALUE,
+ N_("frame offset expression too complex"));
+ return 1;
+ }
+ intv = yasm_intnum_get_int(frameoff);
+ if (intv < 0 || intv > 240)
+ yasm_error_set(YASM_ERROR_VALUE,
+ N_("frame offset of %ld bytes, must be between 0 and 240"), intv);
+ else if ((intv & 0xF) != 0)
+ yasm_error_set(YASM_ERROR_VALUE,
+ N_("frame offset of %ld is not a multiple of 16"), intv);
+
+ YASM_WRITE_8(buf, ((unsigned long)intv & 0xF0) | (info->framereg & 0x0F));
+ yasm_intnum_destroy(frameoff);
+
+ *bufp = buf;
+ return 0;
+}
+
+static void
+win64_uwcode_bc_destroy(void *contents)
+{
+ coff_unwind_code *code = (coff_unwind_code *)contents;
+ yasm_value_delete(&code->off);
+ yasm_xfree(contents);
+}
+
+static void
+win64_uwcode_bc_print(const void *contents, FILE *f, int indent_level)
+{
+ /* TODO */
+}
+
+static void
+win64_uwcode_bc_finalize(yasm_bytecode *bc, yasm_bytecode *prev_bc)
+{
+ coff_unwind_code *code = (coff_unwind_code *)bc->contents;
+ if (yasm_value_finalize(&code->off, prev_bc))
+ yasm_error_set(YASM_ERROR_VALUE, N_("offset expression too complex"));
+}
+
+static int
+win64_uwcode_bc_calc_len(yasm_bytecode *bc, yasm_bc_add_span_func add_span,
+ void *add_span_data)
+{
+ coff_unwind_code *code = (coff_unwind_code *)bc->contents;
+ int span = 0;
+ /*@only@*/ /*@null@*/ yasm_intnum *intn;
+ long intv;
+ long low, high, mask;
+
+ bc->len += 2; /* Prolog offset, code, and info */
+
+ switch (code->opcode) {
+ case UWOP_PUSH_NONVOL:
+ case UWOP_SET_FPREG:
+ case UWOP_PUSH_MACHFRAME:
+ /* always 1 node */
+ return 0;
+ case UWOP_ALLOC_SMALL:
+ case UWOP_ALLOC_LARGE:
+ /* Start with smallest, then work our way up as necessary */
+ code->opcode = UWOP_ALLOC_SMALL;
+ code->info = 0;
+ span = 1; low = 8; high = 128; mask = 0x7;
+ break;
+ case UWOP_SAVE_NONVOL:
+ case UWOP_SAVE_NONVOL_FAR:
+ /* Start with smallest, then work our way up as necessary */
+ code->opcode = UWOP_SAVE_NONVOL;
+ bc->len += 2; /* Scaled offset */
+ span = 2;
+ low = 0;
+ high = 8*64*1024-8; /* 16-bit field, *8 scaling */
+ mask = 0x7;
+ break;
+ case UWOP_SAVE_XMM128:
+ case UWOP_SAVE_XMM128_FAR:
+ /* Start with smallest, then work our way up as necessary */
+ code->opcode = UWOP_SAVE_XMM128;
+ bc->len += 2; /* Scaled offset */
+ span = 3;
+ low = 0;
+ high = 16*64*1024-16; /* 16-bit field, *16 scaling */
+ mask = 0xF;
+ break;
+ default:
+ yasm_internal_error(N_("unrecognied unwind opcode"));
+ /*@unreached@*/
+ return 0;
+ }
+
+ intn = yasm_value_get_intnum(&code->off, bc, 0);
+ if (intn) {
+ intv = yasm_intnum_get_int(intn);
+ if (intv > high) {
+ /* Expand it ourselves here if we can and we're already larger */
+ if (win64_uwcode_bc_expand(bc, span, intv, intv, &low, &high) > 0)
+ add_span(add_span_data, bc, span, &code->off, low, high);
+ }
+ if (intv < low)
+ yasm_error_set(YASM_ERROR_VALUE,
+ N_("negative offset not allowed"));
+ if ((intv & mask) != 0)
+ yasm_error_set(YASM_ERROR_VALUE,
+ N_("offset of %ld is not a multiple of %ld"), intv, mask+1);
+ yasm_intnum_destroy(intn);
+ } else
+ add_span(add_span_data, bc, span, &code->off, low, high);
+ return 0;
+}
+
+static int
+win64_uwcode_bc_expand(yasm_bytecode *bc, int span, long old_val, long new_val,
+ /*@out@*/ long *neg_thres, /*@out@*/ long *pos_thres)
+{
+ coff_unwind_code *code = (coff_unwind_code *)bc->contents;
+
+ if (new_val < 0) {
+ yasm_error_set(YASM_ERROR_VALUE, N_("negative offset not allowed"));
+ return -1;
+ }
+
+ if (span == 1) {
+ /* 3 stages: SMALL, LARGE and info=0, LARGE and info=1 */
+ if (code->opcode == UWOP_ALLOC_LARGE && code->info == 1)
+ yasm_internal_error(N_("expansion on already largest alloc"));
+
+ if (code->opcode == UWOP_ALLOC_SMALL && new_val > 128) {
+ /* Overflowed small size */
+ code->opcode = UWOP_ALLOC_LARGE;
+ bc->len += 2;
+ }
+ if (new_val <= 8*64*1024-8) {
+ /* Still can grow one more size */
+ *pos_thres = 8*64*1024-8;
+ return 1;
+ }
+ /* We're into the largest size */
+ code->info = 1;
+ bc->len += 2;
+ } else if (code->opcode == UWOP_SAVE_NONVOL && span == 2) {
+ code->opcode = UWOP_SAVE_NONVOL_FAR;
+ bc->len += 2;
+ } else if (code->opcode == UWOP_SAVE_XMM128 && span == 3) {
+ code->opcode = UWOP_SAVE_XMM128_FAR;
+ bc->len += 2;
+ }
+ return 0;
+}
+
+static int
+win64_uwcode_bc_tobytes(yasm_bytecode *bc, unsigned char **bufp,
+ unsigned char *bufstart, void *d,
+ yasm_output_value_func output_value,
+ yasm_output_reloc_func output_reloc)
+{
+ coff_unwind_code *code = (coff_unwind_code *)bc->contents;
+ unsigned char *buf = *bufp;
+ yasm_value val;
+ unsigned int size;
+ int shift;
+ long intv, low, high, mask;
+ yasm_intnum *intn;
+
+ /* Offset in prolog */
+ yasm_value_initialize(&val,
+ yasm_expr_create(YASM_EXPR_SUB, yasm_expr_sym(code->loc),
+ yasm_expr_sym(code->proc), bc->line),
+ 8);
+ output_value(&val, buf, 1, (unsigned long)(buf-bufstart), bc, 1, d);
+ buf += 1;
+ yasm_value_delete(&val);
+
+ /* Offset value */
+ switch (code->opcode) {
+ case UWOP_PUSH_NONVOL:
+ case UWOP_SET_FPREG:
+ case UWOP_PUSH_MACHFRAME:
+ /* just 1 node, no offset; write opcode and info and we're done */
+ YASM_WRITE_8(buf, (code->info << 4) | (code->opcode & 0xF));
+ *bufp = buf;
+ return 0;
+ case UWOP_ALLOC_SMALL:
+ /* 1 node, but offset stored in info */
+ size = 0; low = 8; high = 128; shift = 3; mask = 0x7;
+ break;
+ case UWOP_ALLOC_LARGE:
+ if (code->info == 0) {
+ size = 2; low = 136; high = 8*64*1024-8; shift = 3;
+ } else {
+ size = 4; low = high = 0; shift = 0;
+ }
+ mask = 0x7;
+ break;
+ case UWOP_SAVE_NONVOL:
+ size = 2; low = 0; high = 8*64*1024-8; shift = 3; mask = 0x7;
+ break;
+ case UWOP_SAVE_XMM128:
+ size = 2; low = 0; high = 16*64*1024-16; shift = 4; mask = 0xF;
+ break;
+ case UWOP_SAVE_NONVOL_FAR:
+ size = 4; low = high = 0; shift = 0; mask = 0x7;
+ break;
+ case UWOP_SAVE_XMM128_FAR:
+ size = 4; low = high = 0; shift = 0; mask = 0xF;
+ break;
+ default:
+ yasm_internal_error(N_("unrecognied unwind opcode"));
+ /*@unreached@*/
+ return 1;
+ }
+
+ /* Check for overflow */
+ intn = yasm_value_get_intnum(&code->off, bc, 1);
+ if (!intn) {
+ yasm_error_set(YASM_ERROR_VALUE, N_("offset expression too complex"));
+ return 1;
+ }
+ intv = yasm_intnum_get_int(intn);
+ if (size != 4 && (intv < low || intv > high)) {
+ yasm_error_set(YASM_ERROR_VALUE,
+ N_("offset of %ld bytes, must be between %ld and %ld"),
+ intv, low, high);
+ return 1;
+ }
+ if ((intv & mask) != 0) {
+ yasm_error_set(YASM_ERROR_VALUE,
+ N_("offset of %ld is not a multiple of %ld"),
+ intv, mask+1);
+ return 1;
+ }
+
+ /* Stored value in info instead of extra code space */
+ if (size == 0)
+ code->info = (yasm_intnum_get_uint(intn) >> shift)-1;
+
+ /* Opcode and info */
+ YASM_WRITE_8(buf, (code->info << 4) | (code->opcode & 0xF));
+
+ if (size != 0) {
+ yasm_intnum_get_sized(intn, buf, size, size*8, -shift, 0, 1);
+ buf += size;
+ }
+
+ yasm_intnum_destroy(intn);
+
+ *bufp = buf;
+ return 0;
+}
diff --git a/contrib/tools/yasm/modules/objfmts/dbg/dbg-objfmt.c b/contrib/tools/yasm/modules/objfmts/dbg/dbg-objfmt.c
index bdf403c762..135edef012 100644
--- a/contrib/tools/yasm/modules/objfmts/dbg/dbg-objfmt.c
+++ b/contrib/tools/yasm/modules/objfmts/dbg/dbg-objfmt.c
@@ -1,183 +1,183 @@
-/*
- * Debugging object format (used to debug object format module interface)
- *
- * Copyright (C) 2001-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>
-
-#include <libyasm.h>
-
-
-typedef struct yasm_objfmt_dbg {
- yasm_objfmt_base objfmt; /* base structure */
-
- FILE *dbgfile;
-} yasm_objfmt_dbg;
-
-yasm_objfmt_module yasm_dbg_LTX_objfmt;
-
-
-static yasm_objfmt *
-dbg_objfmt_create(yasm_object *object)
-{
- yasm_objfmt_dbg *objfmt_dbg = yasm_xmalloc(sizeof(yasm_objfmt_dbg));
-
- objfmt_dbg->objfmt.module = &yasm_dbg_LTX_objfmt;
-
- objfmt_dbg->dbgfile = tmpfile();
- if (!objfmt_dbg->dbgfile) {
- fprintf(stderr, N_("could not open temporary file"));
- return 0;
- }
- fprintf(objfmt_dbg->dbgfile, "create()\n");
- return (yasm_objfmt *)objfmt_dbg;
-}
-
-static void
-dbg_objfmt_output(yasm_object *object, FILE *f, int all_syms,
- yasm_errwarns *errwarns)
-{
- yasm_objfmt_dbg *objfmt_dbg = (yasm_objfmt_dbg *)object->objfmt;
- char buf[1024];
- size_t i;
-
- /* Copy temp file to real output file */
- rewind(objfmt_dbg->dbgfile);
- while ((i = fread(buf, 1, 1024, objfmt_dbg->dbgfile))) {
- if (fwrite(buf, 1, i, f) != i)
- break;
- }
-
- /* Reassign objfmt debug file to output file */
- fclose(objfmt_dbg->dbgfile);
- objfmt_dbg->dbgfile = f;
-
- fprintf(objfmt_dbg->dbgfile, "output(f, object->\n");
- yasm_object_print(object, objfmt_dbg->dbgfile, 1);
- fprintf(objfmt_dbg->dbgfile, "%d)\n", all_syms);
- fprintf(objfmt_dbg->dbgfile, " Symbol Table:\n");
- yasm_symtab_print(object->symtab, objfmt_dbg->dbgfile, 1);
-}
-
-static void
-dbg_objfmt_destroy(yasm_objfmt *objfmt)
-{
- yasm_objfmt_dbg *objfmt_dbg = (yasm_objfmt_dbg *)objfmt;
- fprintf(objfmt_dbg->dbgfile, "destroy()\n");
- yasm_xfree(objfmt);
-}
-
-static void
-dbg_objfmt_init_new_section(yasm_section *sect, unsigned long line)
-{
- yasm_object *object = yasm_section_get_object(sect);
- yasm_objfmt_dbg *objfmt_dbg = (yasm_objfmt_dbg *)object->objfmt;
- fprintf(objfmt_dbg->dbgfile, "init_new_section(\"%s\", %lu)\n",
- yasm_section_get_name(sect), line);
- yasm_symtab_define_label(object->symtab, ".text",
- yasm_section_bcs_first(sect), 1, 0);
-}
-
-static yasm_section *
-dbg_objfmt_add_default_section(yasm_object *object)
-{
- yasm_objfmt_dbg *objfmt_dbg = (yasm_objfmt_dbg *)object->objfmt;
- yasm_section *retval;
- int isnew;
-
- fprintf(objfmt_dbg->dbgfile, "add_default_section()\n");
- retval = yasm_object_get_general(object, ".text", 0, 0, 0, &isnew, 0);
- if (isnew) {
- yasm_section_set_default(retval, 1);
- }
- return retval;
-}
-
-static /*@observer@*/ /*@null@*/ yasm_section *
-dbg_objfmt_section_switch(yasm_object *object, yasm_valparamhead *valparams,
- /*@unused@*/ /*@null@*/
- yasm_valparamhead *objext_valparams,
- unsigned long line)
-{
- yasm_objfmt_dbg *objfmt_dbg = (yasm_objfmt_dbg *)object->objfmt;
- yasm_valparam *vp;
- yasm_section *retval;
- int isnew;
-
- fprintf(objfmt_dbg->dbgfile, "section_switch(headp, ");
- yasm_vps_print(valparams, objfmt_dbg->dbgfile);
- fprintf(objfmt_dbg->dbgfile, ", ");
- yasm_vps_print(objext_valparams, objfmt_dbg->dbgfile);
- fprintf(objfmt_dbg->dbgfile, ", %lu), returning ", line);
-
- vp = yasm_vps_first(valparams);
- if (!yasm_vp_string(vp)) {
- fprintf(objfmt_dbg->dbgfile, "NULL\n");
- return NULL;
- }
- retval = yasm_object_get_general(object, yasm_vp_string(vp), 0, 0, 0,
- &isnew, line);
- if (isnew) {
- fprintf(objfmt_dbg->dbgfile, "(new) ");
- }
- yasm_section_set_default(retval, 0);
- fprintf(objfmt_dbg->dbgfile, "\"%s\" section\n", vp->val);
- return retval;
-}
-
-static /*@observer@*/ /*@null@*/ yasm_symrec *
-dbg_objfmt_get_special_sym(yasm_object *object, const char *name,
- const char *parser)
-{
- yasm_objfmt_dbg *objfmt_dbg = (yasm_objfmt_dbg *)object->objfmt;
- fprintf(objfmt_dbg->dbgfile, "get_special_sym(object, \"%s\", \"%s\")\n",
- name, parser);
- return NULL;
-}
-
-/* Define valid debug formats to use with this object format */
-static const char *dbg_objfmt_dbgfmt_keywords[] = {
- "null",
- NULL
-};
-
-/* Define objfmt structure -- see objfmt.h for details */
-yasm_objfmt_module yasm_dbg_LTX_objfmt = {
- "Trace of all info passed to object format module",
- "dbg",
- "dbg",
- 32,
- 0,
- dbg_objfmt_dbgfmt_keywords,
- "null",
- NULL, /* no directives */
- NULL, /* no standard macros */
- dbg_objfmt_create,
- dbg_objfmt_output,
- dbg_objfmt_destroy,
- dbg_objfmt_add_default_section,
- dbg_objfmt_init_new_section,
- dbg_objfmt_section_switch,
- dbg_objfmt_get_special_sym
-};
+/*
+ * Debugging object format (used to debug object format module interface)
+ *
+ * Copyright (C) 2001-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>
+
+#include <libyasm.h>
+
+
+typedef struct yasm_objfmt_dbg {
+ yasm_objfmt_base objfmt; /* base structure */
+
+ FILE *dbgfile;
+} yasm_objfmt_dbg;
+
+yasm_objfmt_module yasm_dbg_LTX_objfmt;
+
+
+static yasm_objfmt *
+dbg_objfmt_create(yasm_object *object)
+{
+ yasm_objfmt_dbg *objfmt_dbg = yasm_xmalloc(sizeof(yasm_objfmt_dbg));
+
+ objfmt_dbg->objfmt.module = &yasm_dbg_LTX_objfmt;
+
+ objfmt_dbg->dbgfile = tmpfile();
+ if (!objfmt_dbg->dbgfile) {
+ fprintf(stderr, N_("could not open temporary file"));
+ return 0;
+ }
+ fprintf(objfmt_dbg->dbgfile, "create()\n");
+ return (yasm_objfmt *)objfmt_dbg;
+}
+
+static void
+dbg_objfmt_output(yasm_object *object, FILE *f, int all_syms,
+ yasm_errwarns *errwarns)
+{
+ yasm_objfmt_dbg *objfmt_dbg = (yasm_objfmt_dbg *)object->objfmt;
+ char buf[1024];
+ size_t i;
+
+ /* Copy temp file to real output file */
+ rewind(objfmt_dbg->dbgfile);
+ while ((i = fread(buf, 1, 1024, objfmt_dbg->dbgfile))) {
+ if (fwrite(buf, 1, i, f) != i)
+ break;
+ }
+
+ /* Reassign objfmt debug file to output file */
+ fclose(objfmt_dbg->dbgfile);
+ objfmt_dbg->dbgfile = f;
+
+ fprintf(objfmt_dbg->dbgfile, "output(f, object->\n");
+ yasm_object_print(object, objfmt_dbg->dbgfile, 1);
+ fprintf(objfmt_dbg->dbgfile, "%d)\n", all_syms);
+ fprintf(objfmt_dbg->dbgfile, " Symbol Table:\n");
+ yasm_symtab_print(object->symtab, objfmt_dbg->dbgfile, 1);
+}
+
+static void
+dbg_objfmt_destroy(yasm_objfmt *objfmt)
+{
+ yasm_objfmt_dbg *objfmt_dbg = (yasm_objfmt_dbg *)objfmt;
+ fprintf(objfmt_dbg->dbgfile, "destroy()\n");
+ yasm_xfree(objfmt);
+}
+
+static void
+dbg_objfmt_init_new_section(yasm_section *sect, unsigned long line)
+{
+ yasm_object *object = yasm_section_get_object(sect);
+ yasm_objfmt_dbg *objfmt_dbg = (yasm_objfmt_dbg *)object->objfmt;
+ fprintf(objfmt_dbg->dbgfile, "init_new_section(\"%s\", %lu)\n",
+ yasm_section_get_name(sect), line);
+ yasm_symtab_define_label(object->symtab, ".text",
+ yasm_section_bcs_first(sect), 1, 0);
+}
+
+static yasm_section *
+dbg_objfmt_add_default_section(yasm_object *object)
+{
+ yasm_objfmt_dbg *objfmt_dbg = (yasm_objfmt_dbg *)object->objfmt;
+ yasm_section *retval;
+ int isnew;
+
+ fprintf(objfmt_dbg->dbgfile, "add_default_section()\n");
+ retval = yasm_object_get_general(object, ".text", 0, 0, 0, &isnew, 0);
+ if (isnew) {
+ yasm_section_set_default(retval, 1);
+ }
+ return retval;
+}
+
+static /*@observer@*/ /*@null@*/ yasm_section *
+dbg_objfmt_section_switch(yasm_object *object, yasm_valparamhead *valparams,
+ /*@unused@*/ /*@null@*/
+ yasm_valparamhead *objext_valparams,
+ unsigned long line)
+{
+ yasm_objfmt_dbg *objfmt_dbg = (yasm_objfmt_dbg *)object->objfmt;
+ yasm_valparam *vp;
+ yasm_section *retval;
+ int isnew;
+
+ fprintf(objfmt_dbg->dbgfile, "section_switch(headp, ");
+ yasm_vps_print(valparams, objfmt_dbg->dbgfile);
+ fprintf(objfmt_dbg->dbgfile, ", ");
+ yasm_vps_print(objext_valparams, objfmt_dbg->dbgfile);
+ fprintf(objfmt_dbg->dbgfile, ", %lu), returning ", line);
+
+ vp = yasm_vps_first(valparams);
+ if (!yasm_vp_string(vp)) {
+ fprintf(objfmt_dbg->dbgfile, "NULL\n");
+ return NULL;
+ }
+ retval = yasm_object_get_general(object, yasm_vp_string(vp), 0, 0, 0,
+ &isnew, line);
+ if (isnew) {
+ fprintf(objfmt_dbg->dbgfile, "(new) ");
+ }
+ yasm_section_set_default(retval, 0);
+ fprintf(objfmt_dbg->dbgfile, "\"%s\" section\n", vp->val);
+ return retval;
+}
+
+static /*@observer@*/ /*@null@*/ yasm_symrec *
+dbg_objfmt_get_special_sym(yasm_object *object, const char *name,
+ const char *parser)
+{
+ yasm_objfmt_dbg *objfmt_dbg = (yasm_objfmt_dbg *)object->objfmt;
+ fprintf(objfmt_dbg->dbgfile, "get_special_sym(object, \"%s\", \"%s\")\n",
+ name, parser);
+ return NULL;
+}
+
+/* Define valid debug formats to use with this object format */
+static const char *dbg_objfmt_dbgfmt_keywords[] = {
+ "null",
+ NULL
+};
+
+/* Define objfmt structure -- see objfmt.h for details */
+yasm_objfmt_module yasm_dbg_LTX_objfmt = {
+ "Trace of all info passed to object format module",
+ "dbg",
+ "dbg",
+ 32,
+ 0,
+ dbg_objfmt_dbgfmt_keywords,
+ "null",
+ NULL, /* no directives */
+ NULL, /* no standard macros */
+ dbg_objfmt_create,
+ dbg_objfmt_output,
+ dbg_objfmt_destroy,
+ dbg_objfmt_add_default_section,
+ dbg_objfmt_init_new_section,
+ dbg_objfmt_section_switch,
+ dbg_objfmt_get_special_sym
+};
diff --git a/contrib/tools/yasm/modules/objfmts/elf/elf-machine.h b/contrib/tools/yasm/modules/objfmts/elf/elf-machine.h
index ea6cb4ec94..346b4f6f34 100644
--- a/contrib/tools/yasm/modules/objfmts/elf/elf-machine.h
+++ b/contrib/tools/yasm/modules/objfmts/elf/elf-machine.h
@@ -1,108 +1,108 @@
-/*
- * ELF object machine specific format helpers
- *
- * Copyright (C) 2004-2007 Michael Urman
- *
- * 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.
- */
-
-#ifndef ELF_MACHINE_H_INCLUDED
-#define ELF_MACHINE_H_INCLUDED
-
-#define YASM_WRITE_32I_L(p, i) do {\
- assert(yasm_intnum_check_size(i, 32, 0, 2)); \
- yasm_intnum_get_sized(i, p, 4, 32, 0, 0, 0); \
- p += 4; } while (0)
-
-#define YASM_WRITE_64I_L(p, i) do {\
- assert(yasm_intnum_check_size(i, 64, 0, 2)); \
- yasm_intnum_get_sized(i, p, 8, 64, 0, 0, 0); \
- p += 8; } while (0)
-
-#define YASM_WRITE_64C_L(p, hi, lo) do {\
- YASM_WRITE_32_L(p, lo); \
- YASM_WRITE_32_L(p, hi); } while (0)
-
-#define YASM_WRITE_64Z_L(p, i) YASM_WRITE_64C_L(p, 0, i)
-
-typedef int(*func_accepts_reloc)(size_t val, yasm_symrec *wrt);
-typedef void(*func_write_symtab_entry)(unsigned char *bufp,
- elf_symtab_entry *entry,
- yasm_intnum *value_intn,
- yasm_intnum *size_intn);
-typedef void(*func_write_secthead)(unsigned char *bufp, elf_secthead *shead);
-typedef void(*func_write_secthead_rel)(unsigned char *bufp,
- elf_secthead *shead,
- elf_section_index symtab_idx,
- elf_section_index sindex);
-
-typedef void(*func_handle_reloc_addend)(yasm_intnum *intn,
- elf_reloc_entry *reloc,
- unsigned long offset);
-typedef unsigned int(*func_map_reloc_info_to_type)(elf_reloc_entry *reloc);
-typedef void(*func_write_reloc)(unsigned char *bufp,
- elf_reloc_entry *reloc,
- unsigned int r_type,
- unsigned int r_sym);
-typedef void (*func_write_proghead)(unsigned char **bufpp,
- elf_offset secthead_addr,
- unsigned long secthead_count,
- elf_section_index shstrtab_index);
-
-enum {
- ELF_SSYM_SYM_RELATIVE = 1 << 0,
- ELF_SSYM_CURPOS_ADJUST = 1 << 1,
- ELF_SSYM_THREAD_LOCAL = 1 << 2
-};
-
-typedef struct {
- const char *name; /* should be something like ..name */
- const int sym_rel; /* symbol or section-relative? */
- const unsigned int reloc; /* relocation type */
- const unsigned int size; /* legal data size */
-} elf_machine_ssym;
-
-struct elf_machine_handler {
- const char *arch;
- const char *machine;
- const char *reloc_section_prefix;
- const unsigned long symtab_entry_size;
- const unsigned long symtab_entry_align;
- const unsigned long reloc_entry_size;
- const unsigned long secthead_size;
- const unsigned long proghead_size;
- func_accepts_reloc accepts_reloc;
- func_write_symtab_entry write_symtab_entry;
- func_write_secthead write_secthead;
- func_write_secthead_rel write_secthead_rel;
- func_handle_reloc_addend handle_reloc_addend;
- func_map_reloc_info_to_type map_reloc_info_to_type;
- func_write_reloc write_reloc;
- func_write_proghead write_proghead;
-
- elf_machine_ssym *ssyms; /* array of "special" syms */
- const size_t num_ssyms; /* size of array */
-
- const int bits; /* usually 32 or 64 */
-};
-
-#endif /* ELF_MACHINE_H_INCLUDED */
+/*
+ * ELF object machine specific format helpers
+ *
+ * Copyright (C) 2004-2007 Michael Urman
+ *
+ * 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.
+ */
+
+#ifndef ELF_MACHINE_H_INCLUDED
+#define ELF_MACHINE_H_INCLUDED
+
+#define YASM_WRITE_32I_L(p, i) do {\
+ assert(yasm_intnum_check_size(i, 32, 0, 2)); \
+ yasm_intnum_get_sized(i, p, 4, 32, 0, 0, 0); \
+ p += 4; } while (0)
+
+#define YASM_WRITE_64I_L(p, i) do {\
+ assert(yasm_intnum_check_size(i, 64, 0, 2)); \
+ yasm_intnum_get_sized(i, p, 8, 64, 0, 0, 0); \
+ p += 8; } while (0)
+
+#define YASM_WRITE_64C_L(p, hi, lo) do {\
+ YASM_WRITE_32_L(p, lo); \
+ YASM_WRITE_32_L(p, hi); } while (0)
+
+#define YASM_WRITE_64Z_L(p, i) YASM_WRITE_64C_L(p, 0, i)
+
+typedef int(*func_accepts_reloc)(size_t val, yasm_symrec *wrt);
+typedef void(*func_write_symtab_entry)(unsigned char *bufp,
+ elf_symtab_entry *entry,
+ yasm_intnum *value_intn,
+ yasm_intnum *size_intn);
+typedef void(*func_write_secthead)(unsigned char *bufp, elf_secthead *shead);
+typedef void(*func_write_secthead_rel)(unsigned char *bufp,
+ elf_secthead *shead,
+ elf_section_index symtab_idx,
+ elf_section_index sindex);
+
+typedef void(*func_handle_reloc_addend)(yasm_intnum *intn,
+ elf_reloc_entry *reloc,
+ unsigned long offset);
+typedef unsigned int(*func_map_reloc_info_to_type)(elf_reloc_entry *reloc);
+typedef void(*func_write_reloc)(unsigned char *bufp,
+ elf_reloc_entry *reloc,
+ unsigned int r_type,
+ unsigned int r_sym);
+typedef void (*func_write_proghead)(unsigned char **bufpp,
+ elf_offset secthead_addr,
+ unsigned long secthead_count,
+ elf_section_index shstrtab_index);
+
+enum {
+ ELF_SSYM_SYM_RELATIVE = 1 << 0,
+ ELF_SSYM_CURPOS_ADJUST = 1 << 1,
+ ELF_SSYM_THREAD_LOCAL = 1 << 2
+};
+
+typedef struct {
+ const char *name; /* should be something like ..name */
+ const int sym_rel; /* symbol or section-relative? */
+ const unsigned int reloc; /* relocation type */
+ const unsigned int size; /* legal data size */
+} elf_machine_ssym;
+
+struct elf_machine_handler {
+ const char *arch;
+ const char *machine;
+ const char *reloc_section_prefix;
+ const unsigned long symtab_entry_size;
+ const unsigned long symtab_entry_align;
+ const unsigned long reloc_entry_size;
+ const unsigned long secthead_size;
+ const unsigned long proghead_size;
+ func_accepts_reloc accepts_reloc;
+ func_write_symtab_entry write_symtab_entry;
+ func_write_secthead write_secthead;
+ func_write_secthead_rel write_secthead_rel;
+ func_handle_reloc_addend handle_reloc_addend;
+ func_map_reloc_info_to_type map_reloc_info_to_type;
+ func_write_reloc write_reloc;
+ func_write_proghead write_proghead;
+
+ elf_machine_ssym *ssyms; /* array of "special" syms */
+ const size_t num_ssyms; /* size of array */
+
+ const int bits; /* usually 32 or 64 */
+};
+
+#endif /* ELF_MACHINE_H_INCLUDED */
diff --git a/contrib/tools/yasm/modules/objfmts/elf/elf-objfmt.c b/contrib/tools/yasm/modules/objfmts/elf/elf-objfmt.c
index 6874a1689f..e447218ad5 100644
--- a/contrib/tools/yasm/modules/objfmts/elf/elf-objfmt.c
+++ b/contrib/tools/yasm/modules/objfmts/elf/elf-objfmt.c
@@ -1,1403 +1,1403 @@
-/*
- * ELF object format
- *
- * Copyright (C) 2003-2007 Michael Urman
- *
- * 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>
-
-/* Notes
- *
- * elf-objfmt uses the "linking" view of an ELF file:
- * ELF header, an optional program header table, several sections,
- * and a section header table
- *
- * The ELF header tells us some overall program information,
- * where to find the PHT (if it exists) with phnum and phentsize,
- * and where to find the SHT with shnum and shentsize
- *
- * The PHT doesn't seem to be generated by NASM for elftest.asm
- *
- * The SHT
- *
- * Each Section is spatially disjoint, and has exactly one SHT entry.
- */
-
-#include <libyasm.h>
-
-#include "elf.h"
-#include "elf-machine.h"
-
-typedef struct yasm_objfmt_elf {
- yasm_objfmt_base objfmt; /* base structure */
-
- elf_symtab_head* elf_symtab; /* symbol table of indexed syms */
- elf_strtab_head* shstrtab; /* section name strtab */
- elf_strtab_head* strtab; /* strtab entries */
-
- elf_strtab_entry *file_strtab_entry;/* .file symbol associated string */
- yasm_symrec *dotdotsym; /* ..sym symbol */
-} yasm_objfmt_elf;
-
-typedef struct {
- yasm_objfmt_elf *objfmt_elf;
- yasm_errwarns *errwarns;
- FILE *f;
- elf_secthead *shead;
- yasm_section *sect;
- yasm_object *object;
- unsigned long sindex;
- yasm_symrec *GOT_sym;
-} elf_objfmt_output_info;
-
-typedef struct {
- yasm_object *object;
- yasm_objfmt_elf *objfmt_elf;
- yasm_errwarns *errwarns;
- int local_names;
-} build_symtab_info;
-
-yasm_objfmt_module yasm_elf_LTX_objfmt;
-yasm_objfmt_module yasm_elf32_LTX_objfmt;
-yasm_objfmt_module yasm_elf64_LTX_objfmt;
-yasm_objfmt_module yasm_elfx32_LTX_objfmt;
-
-
-static elf_symtab_entry *
-elf_objfmt_symtab_append(yasm_objfmt_elf *objfmt_elf, yasm_symrec *sym,
- elf_section_index sectidx, elf_symbol_binding bind,
- elf_symbol_type type, elf_symbol_vis vis,
- yasm_expr *size, elf_address *value,
- yasm_object *object)
-{
- elf_symtab_entry *entry = yasm_symrec_get_data(sym, &elf_symrec_data);
-
- if (!entry) {
- /*@only@*/ char *symname = yasm_symrec_get_global_name(sym, object);
- elf_strtab_entry *name =
- elf_strtab_append_str(objfmt_elf->strtab, symname);
- yasm_xfree(symname);
- entry = elf_symtab_entry_create(name, sym);
- yasm_symrec_add_data(sym, &elf_symrec_data, entry);
- }
-
- /* Only append to table if not already appended */
- if (!elf_sym_in_table(entry))
- elf_symtab_append_entry(objfmt_elf->elf_symtab, entry);
-
- elf_symtab_set_nonzero(entry, NULL, sectidx, bind, type, size, value);
- elf_sym_set_visibility(entry, vis);
-
- return entry;
-}
-
-static elf_symtab_entry *
-build_extern(yasm_objfmt_elf *objfmt_elf, yasm_symrec *sym, yasm_object *object)
-{
- yasm_valparamhead *objext_valparams =
- yasm_symrec_get_objext_valparams(sym);
-
- if (objext_valparams) {
- yasm_valparam *vp = yasm_vps_first(objext_valparams);
- for (; vp; vp = yasm_vps_next(vp)) {
- if (yasm_vp_string(vp))
- yasm_error_set(YASM_ERROR_TYPE,
- N_("unrecognized symbol type `%s'"),
- yasm_vp_string(vp));
- }
- }
-
- return elf_objfmt_symtab_append(objfmt_elf, sym, SHN_UNDEF, STB_GLOBAL, 0,
- STV_DEFAULT, NULL, NULL, object);
-}
-
-struct elf_build_global_data {
- yasm_expr *size;
- unsigned long type; /* elf_symbol_type */
- elf_symbol_vis vis;
- unsigned int vis_overrides;
-};
-
-static int
-elf_global_helper_valparam(void *obj, yasm_valparam *vp, unsigned long line,
- void *d)
-
-{
- struct elf_build_global_data *data = (struct elf_build_global_data *)d;
- const char *s;
-
- if (!vp->val && (s = yasm_vp_id(vp))) {
- yasm_error_set(YASM_ERROR_TYPE, N_("unrecognized symbol type `%s'"),
- s);
- return -1;
- } else if (!vp->val && vp->type == YASM_PARAM_EXPR && !data->size) {
- data->size = yasm_expr_copy(vp->param.e);
- return 0;
- } else
- return yasm_dir_helper_valparam_warn(obj, vp, line, d);
-}
-
-static int
-elf_global_helper_vis(void *obj, yasm_valparam *vp, unsigned long line,
- void *d, uintptr_t vis)
-{
- struct elf_build_global_data *data = (struct elf_build_global_data *)d;
- data->vis = vis;
- data->vis_overrides++;
- return 0;
-}
-
-
-static elf_symtab_entry *
-build_global(yasm_objfmt_elf *objfmt_elf, yasm_symrec *sym, yasm_object *object)
-{
- yasm_valparamhead *objext_valparams =
- yasm_symrec_get_objext_valparams(sym);
-
- struct elf_build_global_data data;
-
- static const yasm_dir_help help[] = {
- { "function", 0, yasm_dir_helper_flag_set,
- offsetof(struct elf_build_global_data, type), STT_FUNC },
- { "data", 0, yasm_dir_helper_flag_set,
- offsetof(struct elf_build_global_data, type), STT_OBJECT },
- { "object", 0, yasm_dir_helper_flag_set,
- offsetof(struct elf_build_global_data, type), STT_OBJECT },
- { "internal", 0, elf_global_helper_vis, 0, STV_INTERNAL },
- { "hidden", 0, elf_global_helper_vis, 0, STV_HIDDEN },
- { "protected", 0, elf_global_helper_vis, 0, STV_PROTECTED },
- };
-
- data.size = NULL;
- data.type = 0;
- data.vis = STV_DEFAULT;
- data.vis_overrides = 0;
-
- if (objext_valparams)
- yasm_dir_helper(sym, yasm_vps_first(objext_valparams),
- yasm_symrec_get_decl_line(sym), help, NELEMS(help),
- &data, elf_global_helper_valparam);
-
- if (data.vis_overrides > 1) {
- yasm_warn_set(YASM_WARN_GENERAL,
- N_("More than one symbol visibility provided; using last"));
- }
-
- return elf_objfmt_symtab_append(objfmt_elf, sym, SHN_UNDEF, STB_GLOBAL,
- data.type, data.vis, data.size, NULL,
- object);
-}
-
-static /*@null@*/ elf_symtab_entry *
-build_common(yasm_objfmt_elf *objfmt_elf, yasm_symrec *sym, yasm_object *object)
-{
- yasm_expr **size = yasm_symrec_get_common_size(sym);
- yasm_valparamhead *objext_valparams =
- yasm_symrec_get_objext_valparams(sym);
- unsigned long addralign = 0;
-
- if (objext_valparams) {
- yasm_valparam *vp = yasm_vps_first(objext_valparams);
- for (; vp; vp = yasm_vps_next(vp)) {
- if (!vp->val) {
- /*@only@*/ /*@null@*/ yasm_expr *align_expr;
- /*@dependent@*/ /*@null@*/ const yasm_intnum *align_intn;
-
- if (!(align_expr = yasm_vp_expr(vp, object->symtab,
- yasm_symrec_get_def_line(sym)))
- || !(align_intn = yasm_expr_get_intnum(&align_expr, 0))) {
- yasm_error_set(YASM_ERROR_VALUE,
- N_("alignment constraint is not an integer"));
- if (align_expr)
- yasm_expr_destroy(align_expr);
- return NULL;
- }
- addralign = yasm_intnum_get_uint(align_intn);
- yasm_expr_destroy(align_expr);
-
- /* Alignments must be a power of two. */
- if (!is_exp2(addralign)) {
- yasm_error_set(YASM_ERROR_VALUE,
- N_("alignment constraint is not a power of two"));
- return NULL;
- }
- } else
- yasm_warn_set(YASM_WARN_GENERAL,
- N_("Unrecognized qualifier `%s'"), vp->val);
- }
- }
-
- return elf_objfmt_symtab_append(objfmt_elf, sym, SHN_COMMON, STB_GLOBAL,
- 0, STV_DEFAULT, *size, &addralign, object);
-}
-
-static int
-elf_objfmt_build_symtab(yasm_symrec *sym, /*@null@*/ void *d)
-{
- build_symtab_info *info = (build_symtab_info *)d;
- yasm_sym_vis vis = yasm_symrec_get_visibility(sym);
- yasm_sym_status status = yasm_symrec_get_status(sym);
- elf_symtab_entry *entry = yasm_symrec_get_data(sym, &elf_symrec_data);
- elf_address value=0;
- yasm_section *sect=NULL;
- yasm_bytecode *precbc=NULL;
-
- assert(info != NULL);
-
- if (vis & YASM_SYM_EXTERN) {
- entry = build_extern(info->objfmt_elf, sym, info->object);
- yasm_errwarn_propagate(info->errwarns,
- yasm_symrec_get_decl_line(sym));
- return 0;
- }
-
- if (vis & YASM_SYM_COMMON) {
- entry = build_common(info->objfmt_elf, sym, info->object);
- yasm_errwarn_propagate(info->errwarns,
- yasm_symrec_get_decl_line(sym));
- /* If the COMMON variable was actually defined, fall through. */
- if (!(status & YASM_SYM_DEFINED))
- return 0;
- }
-
- /* Ignore any undefined at this point. */
- if (!(status & YASM_SYM_DEFINED))
- return 0;
-
- if (!yasm_symrec_get_label(sym, &precbc)) {
- if (!yasm_symrec_get_equ(sym) && !yasm_symrec_is_abs(sym))
- return 0;
- precbc = NULL;
- }
-
- if (precbc)
- sect = yasm_bc_get_section(precbc);
-
- if (entry && elf_sym_in_table(entry))
- ;
- else if (vis & YASM_SYM_GLOBAL) {
- entry = build_global(info->objfmt_elf, sym, info->object);
- yasm_errwarn_propagate(info->errwarns, yasm_symrec_get_decl_line(sym));
- } else {
- int is_sect = 0;
-
- /* Locals (except when debugging) do not need to be
- * in the symbol table, unless they're a section.
- */
- if (sect &&
- strcmp(yasm_symrec_get_name(sym), yasm_section_get_name(sect))==0)
- is_sect = 1;
-#if 0
- /* FIXME: to enable this we must have handling in place for special
- * symbols.
- */
- if (!info->local_names && !is_sect)
- return 0;
-#else
- if (yasm_symrec_get_equ(sym) && !yasm_symrec_is_abs(sym))
- return 0;
-#endif
- entry = yasm_symrec_get_data(sym, &elf_symrec_data);
- if (!entry) {
- /*@only@*/ char *symname =
- yasm_symrec_get_global_name(sym, info->object);
- elf_strtab_entry *name = !info->local_names || is_sect ? NULL :
- elf_strtab_append_str(info->objfmt_elf->strtab, symname);
- yasm_xfree(symname);
- entry = elf_symtab_entry_create(name, sym);
- yasm_symrec_add_data(sym, &elf_symrec_data, entry);
- }
-
- if (!elf_sym_in_table(entry))
- elf_symtab_insert_local_sym(info->objfmt_elf->elf_symtab, entry);
-
- elf_symtab_set_nonzero(entry, sect, 0, STB_LOCAL,
- is_sect ? STT_SECTION : 0, NULL, 0);
-
- if (is_sect)
- return 0;
- }
-
- if (precbc)
- value = yasm_bc_next_offset(precbc);
- elf_symtab_set_nonzero(entry, sect, 0, 0, 0, NULL, &value);
-
- return 0;
-}
-
-static yasm_objfmt *
-elf_objfmt_create_common(yasm_object *object, yasm_objfmt_module *module,
- int bits_pref,
- const elf_machine_handler **elf_march_out)
-{
- yasm_objfmt_elf *objfmt_elf = yasm_xmalloc(sizeof(yasm_objfmt_elf));
- yasm_symrec *filesym;
- elf_symtab_entry *entry;
- const elf_machine_handler *elf_march;
-
- objfmt_elf->objfmt.module = module;
- elf_march = elf_set_arch(object->arch, object->symtab, bits_pref);
- if (!elf_march) {
- yasm_xfree(objfmt_elf);
- return NULL;
- }
- if (elf_march_out)
- *elf_march_out = elf_march;
-
- objfmt_elf->shstrtab = elf_strtab_create();
- objfmt_elf->strtab = elf_strtab_create();
- objfmt_elf->elf_symtab = elf_symtab_create();
-
- /* FIXME: misuse of NULL bytecode here; it works, but only barely. */
- filesym = yasm_symtab_define_label(object->symtab, ".file", NULL, 0, 0);
+/*
+ * ELF object format
+ *
+ * Copyright (C) 2003-2007 Michael Urman
+ *
+ * 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>
+
+/* Notes
+ *
+ * elf-objfmt uses the "linking" view of an ELF file:
+ * ELF header, an optional program header table, several sections,
+ * and a section header table
+ *
+ * The ELF header tells us some overall program information,
+ * where to find the PHT (if it exists) with phnum and phentsize,
+ * and where to find the SHT with shnum and shentsize
+ *
+ * The PHT doesn't seem to be generated by NASM for elftest.asm
+ *
+ * The SHT
+ *
+ * Each Section is spatially disjoint, and has exactly one SHT entry.
+ */
+
+#include <libyasm.h>
+
+#include "elf.h"
+#include "elf-machine.h"
+
+typedef struct yasm_objfmt_elf {
+ yasm_objfmt_base objfmt; /* base structure */
+
+ elf_symtab_head* elf_symtab; /* symbol table of indexed syms */
+ elf_strtab_head* shstrtab; /* section name strtab */
+ elf_strtab_head* strtab; /* strtab entries */
+
+ elf_strtab_entry *file_strtab_entry;/* .file symbol associated string */
+ yasm_symrec *dotdotsym; /* ..sym symbol */
+} yasm_objfmt_elf;
+
+typedef struct {
+ yasm_objfmt_elf *objfmt_elf;
+ yasm_errwarns *errwarns;
+ FILE *f;
+ elf_secthead *shead;
+ yasm_section *sect;
+ yasm_object *object;
+ unsigned long sindex;
+ yasm_symrec *GOT_sym;
+} elf_objfmt_output_info;
+
+typedef struct {
+ yasm_object *object;
+ yasm_objfmt_elf *objfmt_elf;
+ yasm_errwarns *errwarns;
+ int local_names;
+} build_symtab_info;
+
+yasm_objfmt_module yasm_elf_LTX_objfmt;
+yasm_objfmt_module yasm_elf32_LTX_objfmt;
+yasm_objfmt_module yasm_elf64_LTX_objfmt;
+yasm_objfmt_module yasm_elfx32_LTX_objfmt;
+
+
+static elf_symtab_entry *
+elf_objfmt_symtab_append(yasm_objfmt_elf *objfmt_elf, yasm_symrec *sym,
+ elf_section_index sectidx, elf_symbol_binding bind,
+ elf_symbol_type type, elf_symbol_vis vis,
+ yasm_expr *size, elf_address *value,
+ yasm_object *object)
+{
+ elf_symtab_entry *entry = yasm_symrec_get_data(sym, &elf_symrec_data);
+
+ if (!entry) {
+ /*@only@*/ char *symname = yasm_symrec_get_global_name(sym, object);
+ elf_strtab_entry *name =
+ elf_strtab_append_str(objfmt_elf->strtab, symname);
+ yasm_xfree(symname);
+ entry = elf_symtab_entry_create(name, sym);
+ yasm_symrec_add_data(sym, &elf_symrec_data, entry);
+ }
+
+ /* Only append to table if not already appended */
+ if (!elf_sym_in_table(entry))
+ elf_symtab_append_entry(objfmt_elf->elf_symtab, entry);
+
+ elf_symtab_set_nonzero(entry, NULL, sectidx, bind, type, size, value);
+ elf_sym_set_visibility(entry, vis);
+
+ return entry;
+}
+
+static elf_symtab_entry *
+build_extern(yasm_objfmt_elf *objfmt_elf, yasm_symrec *sym, yasm_object *object)
+{
+ yasm_valparamhead *objext_valparams =
+ yasm_symrec_get_objext_valparams(sym);
+
+ if (objext_valparams) {
+ yasm_valparam *vp = yasm_vps_first(objext_valparams);
+ for (; vp; vp = yasm_vps_next(vp)) {
+ if (yasm_vp_string(vp))
+ yasm_error_set(YASM_ERROR_TYPE,
+ N_("unrecognized symbol type `%s'"),
+ yasm_vp_string(vp));
+ }
+ }
+
+ return elf_objfmt_symtab_append(objfmt_elf, sym, SHN_UNDEF, STB_GLOBAL, 0,
+ STV_DEFAULT, NULL, NULL, object);
+}
+
+struct elf_build_global_data {
+ yasm_expr *size;
+ unsigned long type; /* elf_symbol_type */
+ elf_symbol_vis vis;
+ unsigned int vis_overrides;
+};
+
+static int
+elf_global_helper_valparam(void *obj, yasm_valparam *vp, unsigned long line,
+ void *d)
+
+{
+ struct elf_build_global_data *data = (struct elf_build_global_data *)d;
+ const char *s;
+
+ if (!vp->val && (s = yasm_vp_id(vp))) {
+ yasm_error_set(YASM_ERROR_TYPE, N_("unrecognized symbol type `%s'"),
+ s);
+ return -1;
+ } else if (!vp->val && vp->type == YASM_PARAM_EXPR && !data->size) {
+ data->size = yasm_expr_copy(vp->param.e);
+ return 0;
+ } else
+ return yasm_dir_helper_valparam_warn(obj, vp, line, d);
+}
+
+static int
+elf_global_helper_vis(void *obj, yasm_valparam *vp, unsigned long line,
+ void *d, uintptr_t vis)
+{
+ struct elf_build_global_data *data = (struct elf_build_global_data *)d;
+ data->vis = vis;
+ data->vis_overrides++;
+ return 0;
+}
+
+
+static elf_symtab_entry *
+build_global(yasm_objfmt_elf *objfmt_elf, yasm_symrec *sym, yasm_object *object)
+{
+ yasm_valparamhead *objext_valparams =
+ yasm_symrec_get_objext_valparams(sym);
+
+ struct elf_build_global_data data;
+
+ static const yasm_dir_help help[] = {
+ { "function", 0, yasm_dir_helper_flag_set,
+ offsetof(struct elf_build_global_data, type), STT_FUNC },
+ { "data", 0, yasm_dir_helper_flag_set,
+ offsetof(struct elf_build_global_data, type), STT_OBJECT },
+ { "object", 0, yasm_dir_helper_flag_set,
+ offsetof(struct elf_build_global_data, type), STT_OBJECT },
+ { "internal", 0, elf_global_helper_vis, 0, STV_INTERNAL },
+ { "hidden", 0, elf_global_helper_vis, 0, STV_HIDDEN },
+ { "protected", 0, elf_global_helper_vis, 0, STV_PROTECTED },
+ };
+
+ data.size = NULL;
+ data.type = 0;
+ data.vis = STV_DEFAULT;
+ data.vis_overrides = 0;
+
+ if (objext_valparams)
+ yasm_dir_helper(sym, yasm_vps_first(objext_valparams),
+ yasm_symrec_get_decl_line(sym), help, NELEMS(help),
+ &data, elf_global_helper_valparam);
+
+ if (data.vis_overrides > 1) {
+ yasm_warn_set(YASM_WARN_GENERAL,
+ N_("More than one symbol visibility provided; using last"));
+ }
+
+ return elf_objfmt_symtab_append(objfmt_elf, sym, SHN_UNDEF, STB_GLOBAL,
+ data.type, data.vis, data.size, NULL,
+ object);
+}
+
+static /*@null@*/ elf_symtab_entry *
+build_common(yasm_objfmt_elf *objfmt_elf, yasm_symrec *sym, yasm_object *object)
+{
+ yasm_expr **size = yasm_symrec_get_common_size(sym);
+ yasm_valparamhead *objext_valparams =
+ yasm_symrec_get_objext_valparams(sym);
+ unsigned long addralign = 0;
+
+ if (objext_valparams) {
+ yasm_valparam *vp = yasm_vps_first(objext_valparams);
+ for (; vp; vp = yasm_vps_next(vp)) {
+ if (!vp->val) {
+ /*@only@*/ /*@null@*/ yasm_expr *align_expr;
+ /*@dependent@*/ /*@null@*/ const yasm_intnum *align_intn;
+
+ if (!(align_expr = yasm_vp_expr(vp, object->symtab,
+ yasm_symrec_get_def_line(sym)))
+ || !(align_intn = yasm_expr_get_intnum(&align_expr, 0))) {
+ yasm_error_set(YASM_ERROR_VALUE,
+ N_("alignment constraint is not an integer"));
+ if (align_expr)
+ yasm_expr_destroy(align_expr);
+ return NULL;
+ }
+ addralign = yasm_intnum_get_uint(align_intn);
+ yasm_expr_destroy(align_expr);
+
+ /* Alignments must be a power of two. */
+ if (!is_exp2(addralign)) {
+ yasm_error_set(YASM_ERROR_VALUE,
+ N_("alignment constraint is not a power of two"));
+ return NULL;
+ }
+ } else
+ yasm_warn_set(YASM_WARN_GENERAL,
+ N_("Unrecognized qualifier `%s'"), vp->val);
+ }
+ }
+
+ return elf_objfmt_symtab_append(objfmt_elf, sym, SHN_COMMON, STB_GLOBAL,
+ 0, STV_DEFAULT, *size, &addralign, object);
+}
+
+static int
+elf_objfmt_build_symtab(yasm_symrec *sym, /*@null@*/ void *d)
+{
+ build_symtab_info *info = (build_symtab_info *)d;
+ yasm_sym_vis vis = yasm_symrec_get_visibility(sym);
+ yasm_sym_status status = yasm_symrec_get_status(sym);
+ elf_symtab_entry *entry = yasm_symrec_get_data(sym, &elf_symrec_data);
+ elf_address value=0;
+ yasm_section *sect=NULL;
+ yasm_bytecode *precbc=NULL;
+
+ assert(info != NULL);
+
+ if (vis & YASM_SYM_EXTERN) {
+ entry = build_extern(info->objfmt_elf, sym, info->object);
+ yasm_errwarn_propagate(info->errwarns,
+ yasm_symrec_get_decl_line(sym));
+ return 0;
+ }
+
+ if (vis & YASM_SYM_COMMON) {
+ entry = build_common(info->objfmt_elf, sym, info->object);
+ yasm_errwarn_propagate(info->errwarns,
+ yasm_symrec_get_decl_line(sym));
+ /* If the COMMON variable was actually defined, fall through. */
+ if (!(status & YASM_SYM_DEFINED))
+ return 0;
+ }
+
+ /* Ignore any undefined at this point. */
+ if (!(status & YASM_SYM_DEFINED))
+ return 0;
+
+ if (!yasm_symrec_get_label(sym, &precbc)) {
+ if (!yasm_symrec_get_equ(sym) && !yasm_symrec_is_abs(sym))
+ return 0;
+ precbc = NULL;
+ }
+
+ if (precbc)
+ sect = yasm_bc_get_section(precbc);
+
+ if (entry && elf_sym_in_table(entry))
+ ;
+ else if (vis & YASM_SYM_GLOBAL) {
+ entry = build_global(info->objfmt_elf, sym, info->object);
+ yasm_errwarn_propagate(info->errwarns, yasm_symrec_get_decl_line(sym));
+ } else {
+ int is_sect = 0;
+
+ /* Locals (except when debugging) do not need to be
+ * in the symbol table, unless they're a section.
+ */
+ if (sect &&
+ strcmp(yasm_symrec_get_name(sym), yasm_section_get_name(sect))==0)
+ is_sect = 1;
+#if 0
+ /* FIXME: to enable this we must have handling in place for special
+ * symbols.
+ */
+ if (!info->local_names && !is_sect)
+ return 0;
+#else
+ if (yasm_symrec_get_equ(sym) && !yasm_symrec_is_abs(sym))
+ return 0;
+#endif
+ entry = yasm_symrec_get_data(sym, &elf_symrec_data);
+ if (!entry) {
+ /*@only@*/ char *symname =
+ yasm_symrec_get_global_name(sym, info->object);
+ elf_strtab_entry *name = !info->local_names || is_sect ? NULL :
+ elf_strtab_append_str(info->objfmt_elf->strtab, symname);
+ yasm_xfree(symname);
+ entry = elf_symtab_entry_create(name, sym);
+ yasm_symrec_add_data(sym, &elf_symrec_data, entry);
+ }
+
+ if (!elf_sym_in_table(entry))
+ elf_symtab_insert_local_sym(info->objfmt_elf->elf_symtab, entry);
+
+ elf_symtab_set_nonzero(entry, sect, 0, STB_LOCAL,
+ is_sect ? STT_SECTION : 0, NULL, 0);
+
+ if (is_sect)
+ return 0;
+ }
+
+ if (precbc)
+ value = yasm_bc_next_offset(precbc);
+ elf_symtab_set_nonzero(entry, sect, 0, 0, 0, NULL, &value);
+
+ return 0;
+}
+
+static yasm_objfmt *
+elf_objfmt_create_common(yasm_object *object, yasm_objfmt_module *module,
+ int bits_pref,
+ const elf_machine_handler **elf_march_out)
+{
+ yasm_objfmt_elf *objfmt_elf = yasm_xmalloc(sizeof(yasm_objfmt_elf));
+ yasm_symrec *filesym;
+ elf_symtab_entry *entry;
+ const elf_machine_handler *elf_march;
+
+ objfmt_elf->objfmt.module = module;
+ elf_march = elf_set_arch(object->arch, object->symtab, bits_pref);
+ if (!elf_march) {
+ yasm_xfree(objfmt_elf);
+ return NULL;
+ }
+ if (elf_march_out)
+ *elf_march_out = elf_march;
+
+ objfmt_elf->shstrtab = elf_strtab_create();
+ objfmt_elf->strtab = elf_strtab_create();
+ objfmt_elf->elf_symtab = elf_symtab_create();
+
+ /* FIXME: misuse of NULL bytecode here; it works, but only barely. */
+ filesym = yasm_symtab_define_label(object->symtab, ".file", NULL, 0, 0);
if (!object->deb_filename) {
object->deb_filename = yasm_replace_path(
module->replace_map, module->replace_map_size,
object->src_filename, strlen(object->src_filename));
}
- /* Put in current input filename; we'll replace it in output() */
- objfmt_elf->file_strtab_entry =
+ /* Put in current input filename; we'll replace it in output() */
+ objfmt_elf->file_strtab_entry =
elf_strtab_append_str(objfmt_elf->strtab, object->deb_filename);
- entry = elf_symtab_entry_create(objfmt_elf->file_strtab_entry, filesym);
- yasm_symrec_add_data(filesym, &elf_symrec_data, entry);
- elf_symtab_set_nonzero(entry, NULL, SHN_ABS, STB_LOCAL, STT_FILE, NULL,
- NULL);
- elf_symtab_append_entry(objfmt_elf->elf_symtab, entry);
-
- /* FIXME: misuse of NULL bytecode */
- objfmt_elf->dotdotsym =
- yasm_symtab_define_label(object->symtab, "..sym", NULL, 0, 0);
-
- return (yasm_objfmt *)objfmt_elf;
-}
-
-static yasm_objfmt *
-elf_objfmt_create(yasm_object *object)
-{
- const elf_machine_handler *elf_march;
- yasm_objfmt *objfmt;
- yasm_objfmt_elf *objfmt_elf;
-
- objfmt = elf_objfmt_create_common(object, &yasm_elf_LTX_objfmt, 0,
- &elf_march);
- if (objfmt) {
- objfmt_elf = (yasm_objfmt_elf *)objfmt;
- /* Figure out which bitness of object format to use */
- if (strcmp (elf_march->machine, "x32") == 0)
- objfmt_elf->objfmt.module = &yasm_elfx32_LTX_objfmt;
- else if (elf_march->bits == 32)
- objfmt_elf->objfmt.module = &yasm_elf32_LTX_objfmt;
- else if (elf_march->bits == 64)
- objfmt_elf->objfmt.module = &yasm_elf64_LTX_objfmt;
- }
- return objfmt;
-}
-
-static yasm_objfmt *
-elf32_objfmt_create(yasm_object *object)
-{
- return elf_objfmt_create_common(object, &yasm_elf32_LTX_objfmt, 32, NULL);
-}
-
-static yasm_objfmt *
-elf64_objfmt_create(yasm_object *object)
-{
- return elf_objfmt_create_common(object, &yasm_elf64_LTX_objfmt, 64, NULL);
-}
-
-static yasm_objfmt *
-elfx32_objfmt_create(yasm_object *object)
-{
- return elf_objfmt_create_common(object, &yasm_elfx32_LTX_objfmt, 32, NULL);
-}
-
-static long
-elf_objfmt_output_align(FILE *f, unsigned int align)
-{
- long pos;
- unsigned long delta;
- if (!is_exp2(align))
- yasm_internal_error("requested alignment not a power of two");
-
- pos = ftell(f);
- if (pos == -1) {
- yasm_error_set(YASM_ERROR_IO,
- N_("could not get file position on output file"));
- return -1;
- }
- delta = align - (pos & (align-1));
- if (delta != align) {
- pos += delta;
- if (fseek(f, pos, SEEK_SET) < 0) {
- yasm_error_set(YASM_ERROR_IO,
- N_("could not set file position on output file"));
- return -1;
- }
- }
- return pos;
-}
-
-static int
-elf_objfmt_output_reloc(yasm_symrec *sym, yasm_bytecode *bc,
- unsigned char *buf, unsigned int destsize,
- unsigned int valsize, int warn, void *d)
-{
- elf_reloc_entry *reloc;
- elf_objfmt_output_info *info = d;
- yasm_intnum *zero;
- int retval;
-
- reloc = elf_reloc_entry_create(sym, NULL,
- yasm_intnum_create_uint(bc->offset), 0, valsize, 0);
- if (reloc == NULL) {
- yasm_error_set(YASM_ERROR_TYPE, N_("elf: invalid relocation size"));
- return 1;
- }
- /* allocate .rel[a] sections on a need-basis */
- elf_secthead_append_reloc(info->sect, info->shead, reloc);
-
- zero = yasm_intnum_create_uint(0);
- elf_handle_reloc_addend(zero, reloc, 0);
- retval = yasm_arch_intnum_tobytes(info->object->arch, zero, buf, destsize,
- valsize, 0, bc, warn);
- yasm_intnum_destroy(zero);
- return retval;
-}
-
-static int
-elf_objfmt_output_value(yasm_value *value, unsigned char *buf,
- unsigned int destsize, unsigned long offset,
- yasm_bytecode *bc, int warn, /*@null@*/ void *d)
-{
- /*@null@*/ elf_objfmt_output_info *info = (elf_objfmt_output_info *)d;
- /*@dependent@*/ /*@null@*/ yasm_intnum *intn;
- unsigned long intn_val;
- /*@null@*/ elf_reloc_entry *reloc = NULL;
- int retval;
- unsigned int valsize = value->size;
-
- if (info == NULL)
- yasm_internal_error("null info struct");
-
- if (value->abs)
- value->abs = yasm_expr_simplify(value->abs, 1);
-
- /* Try to output constant and PC-relative section-local first.
- * Note this does NOT output any value with a SEG, WRT, external,
- * cross-section, or non-PC-relative reference (those are handled below).
- */
- switch (yasm_value_output_basic(value, buf, destsize, bc, warn,
- info->object->arch)) {
- case -1:
- return 1;
- case 0:
- break;
- default:
- return 0;
- }
-
- /* Handle other expressions, with relocation if necessary */
- if (value->seg_of || value->section_rel || value->rshift > 0) {
- yasm_error_set(YASM_ERROR_TOO_COMPLEX,
- N_("elf: relocation too complex"));
- return 1;
- }
-
- intn_val = 0;
- if (value->rel) {
- yasm_sym_vis vis = yasm_symrec_get_visibility(value->rel);
- /*@dependent@*/ /*@null@*/ yasm_symrec *sym = value->rel;
- /*@dependent@*/ /*@null@*/ yasm_symrec *wrt = value->wrt;
-
- if (wrt == info->objfmt_elf->dotdotsym)
- wrt = NULL;
- else if (wrt && elf_is_wrt_sym_relative(wrt))
- ;
- else if (wrt && elf_is_wrt_pos_adjusted(wrt))
- intn_val = offset + bc->offset;
- else if (vis == YASM_SYM_LOCAL) {
- yasm_bytecode *sym_precbc;
- /* Local symbols need relocation to their section's start, and
- * add in the offset of the bytecode (within the target section)
- * into the abs portion.
- *
- * This is only done if the symbol is relocated against the
- * section instead of the symbol itself.
- */
- if (yasm_symrec_get_label(sym, &sym_precbc)) {
- /* Relocate to section start */
- yasm_section *sym_sect = yasm_bc_get_section(sym_precbc);
- /*@null@*/ elf_secthead *sym_shead;
- sym_shead = yasm_section_get_data(sym_sect, &elf_section_data);
- assert(sym_shead != NULL);
- sym = elf_secthead_get_sym(sym_shead);
-
- intn_val = yasm_bc_next_offset(sym_precbc);
- }
- }
-
- /* For PC-relative, need to add offset of expression within bc. */
- if (value->curpos_rel)
- intn_val += offset;
-
- /* Check for _GLOBAL_OFFSET_TABLE_ symbol reference */
- reloc = elf_reloc_entry_create(sym, wrt,
- yasm_intnum_create_uint(bc->offset + offset), value->curpos_rel,
- valsize, sym == info->GOT_sym);
- if (reloc == NULL) {
- yasm_error_set(YASM_ERROR_TYPE,
- N_("elf: invalid relocation (WRT or size)"));
- return 1;
- }
- /* allocate .rel[a] sections on a need-basis */
- elf_secthead_append_reloc(info->sect, info->shead, reloc);
- }
-
- intn = yasm_intnum_create_uint(intn_val);
-
- if (value->abs) {
- yasm_intnum *intn2 = yasm_expr_get_intnum(&value->abs, 0);
- if (!intn2) {
- yasm_error_set(YASM_ERROR_TOO_COMPLEX,
- N_("elf: relocation too complex"));
- yasm_intnum_destroy(intn);
- return 1;
- }
- yasm_intnum_calc(intn, YASM_EXPR_ADD, intn2);
- }
-
- if (reloc)
- elf_handle_reloc_addend(intn, reloc, offset);
- retval = yasm_arch_intnum_tobytes(info->object->arch, intn, buf, destsize,
- valsize, 0, bc, warn);
- yasm_intnum_destroy(intn);
- return retval;
-}
-
-static int
-elf_objfmt_output_bytecode(yasm_bytecode *bc, /*@null@*/ void *d)
-{
- /*@null@*/ elf_objfmt_output_info *info = (elf_objfmt_output_info *)d;
- unsigned char buf[256];
- /*@null@*/ /*@only@*/ unsigned char *bigbuf;
- unsigned long size = 256;
- int gap;
-
- if (info == NULL)
- yasm_internal_error("null info struct");
-
- bigbuf = yasm_bc_tobytes(bc, buf, &size, &gap, info,
- elf_objfmt_output_value, elf_objfmt_output_reloc);
-
- /* Don't bother doing anything else if size ended up being 0. */
- if (size == 0) {
- if (bigbuf)
- yasm_xfree(bigbuf);
- return 0;
- }
- else {
- yasm_intnum *bcsize = yasm_intnum_create_uint(size);
- elf_secthead_add_size(info->shead, bcsize);
- yasm_intnum_destroy(bcsize);
- }
-
- /* 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(buf, 0, 256);
- left = size;
- while (left > 256) {
- fwrite(buf, 256, 1, info->f);
- left -= 256;
- }
- fwrite(buf, left, 1, info->f);
- } else {
- /* Output buf (or bigbuf if non-NULL) to file */
- fwrite(bigbuf ? bigbuf : buf, (size_t)size, 1, info->f);
- }
-
- /* If bigbuf was allocated, free it */
- if (bigbuf)
- yasm_xfree(bigbuf);
-
- return 0;
-}
-
-static int
-elf_objfmt_output_section(yasm_section *sect, /*@null@*/ void *d)
-{
- /*@null@*/ elf_objfmt_output_info *info = (elf_objfmt_output_info *)d;
- /*@dependent@*/ /*@null@*/ elf_secthead *shead;
- long pos;
- char *relname;
- const char *sectname;
-
- if (info == NULL)
- yasm_internal_error("null info struct");
- shead = yasm_section_get_data(sect, &elf_section_data);
- if (shead == NULL)
- yasm_internal_error("no associated data");
-
- if (elf_secthead_get_align(shead) == 0)
- elf_secthead_set_align(shead, yasm_section_get_align(sect));
-
- /* don't output header-only sections */
- if ((elf_secthead_get_type(shead) & SHT_NOBITS) == SHT_NOBITS)
- {
- yasm_bytecode *last = yasm_section_bcs_last(sect);
- if (last) {
- yasm_intnum *sectsize;
- sectsize = yasm_intnum_create_uint(yasm_bc_next_offset(last));
- elf_secthead_add_size(shead, sectsize);
- yasm_intnum_destroy(sectsize);
- }
- elf_secthead_set_index(shead, ++info->sindex);
- return 0;
- }
-
- if ((pos = ftell(info->f)) == -1) {
- yasm_error_set(YASM_ERROR_IO,
- N_("couldn't read position on output stream"));
- yasm_errwarn_propagate(info->errwarns, 0);
- }
- pos = elf_secthead_set_file_offset(shead, pos);
- if (fseek(info->f, pos, SEEK_SET) < 0) {
- yasm_error_set(YASM_ERROR_IO, N_("couldn't seek on output stream"));
- yasm_errwarn_propagate(info->errwarns, 0);
- }
-
- info->sect = sect;
- info->shead = shead;
- yasm_section_bcs_traverse(sect, info->errwarns, info,
- elf_objfmt_output_bytecode);
-
- elf_secthead_set_index(shead, ++info->sindex);
-
- /* No relocations to output? Go on to next section */
- if (elf_secthead_write_relocs_to_file(info->f, sect, shead,
- info->errwarns) == 0)
- return 0;
- elf_secthead_set_rel_index(shead, ++info->sindex);
-
- /* name the relocation section .rel[a].foo */
- sectname = yasm_section_get_name(sect);
- relname = elf_secthead_name_reloc_section(sectname);
- elf_secthead_set_rel_name(shead,
- elf_strtab_append_str(info->objfmt_elf->shstrtab, relname));
- yasm_xfree(relname);
-
- return 0;
-}
-
-static int
-elf_objfmt_output_secthead(yasm_section *sect, /*@null@*/ void *d)
-{
- /*@null@*/ elf_objfmt_output_info *info = (elf_objfmt_output_info *)d;
- /*@dependent@*/ /*@null@*/ elf_secthead *shead;
-
- if (info == NULL)
- yasm_internal_error("null info struct");
- shead = yasm_section_get_data(sect, &elf_section_data);
- if (shead == NULL)
- yasm_internal_error("no section header attached to section");
-
- if(elf_secthead_write_to_file(info->f, shead, info->sindex+1))
- info->sindex++;
-
- /* output strtab headers here? */
-
- /* relocation entries for .foo are stored in section .rel[a].foo */
- if(elf_secthead_write_rel_to_file(info->f, 3, sect, shead,
- info->sindex+1))
- info->sindex++;
-
- return 0;
-}
-
-static void
-elf_objfmt_output(yasm_object *object, FILE *f, int all_syms,
- yasm_errwarns *errwarns)
-{
- yasm_objfmt_elf *objfmt_elf = (yasm_objfmt_elf *)object->objfmt;
- elf_objfmt_output_info info;
- build_symtab_info buildsym_info;
- long pos;
- unsigned long elf_shead_addr;
- elf_secthead *esdn;
- unsigned long elf_strtab_offset, elf_shstrtab_offset, elf_symtab_offset;
- unsigned long elf_strtab_size, elf_shstrtab_size, elf_symtab_size;
- elf_strtab_entry *elf_strtab_name, *elf_shstrtab_name, *elf_symtab_name;
- unsigned long elf_symtab_nlocal;
-
- info.object = object;
- info.objfmt_elf = objfmt_elf;
- info.errwarns = errwarns;
- info.f = f;
- info.GOT_sym = yasm_symtab_get(object->symtab, "_GLOBAL_OFFSET_TABLE_");
-
+ entry = elf_symtab_entry_create(objfmt_elf->file_strtab_entry, filesym);
+ yasm_symrec_add_data(filesym, &elf_symrec_data, entry);
+ elf_symtab_set_nonzero(entry, NULL, SHN_ABS, STB_LOCAL, STT_FILE, NULL,
+ NULL);
+ elf_symtab_append_entry(objfmt_elf->elf_symtab, entry);
+
+ /* FIXME: misuse of NULL bytecode */
+ objfmt_elf->dotdotsym =
+ yasm_symtab_define_label(object->symtab, "..sym", NULL, 0, 0);
+
+ return (yasm_objfmt *)objfmt_elf;
+}
+
+static yasm_objfmt *
+elf_objfmt_create(yasm_object *object)
+{
+ const elf_machine_handler *elf_march;
+ yasm_objfmt *objfmt;
+ yasm_objfmt_elf *objfmt_elf;
+
+ objfmt = elf_objfmt_create_common(object, &yasm_elf_LTX_objfmt, 0,
+ &elf_march);
+ if (objfmt) {
+ objfmt_elf = (yasm_objfmt_elf *)objfmt;
+ /* Figure out which bitness of object format to use */
+ if (strcmp (elf_march->machine, "x32") == 0)
+ objfmt_elf->objfmt.module = &yasm_elfx32_LTX_objfmt;
+ else if (elf_march->bits == 32)
+ objfmt_elf->objfmt.module = &yasm_elf32_LTX_objfmt;
+ else if (elf_march->bits == 64)
+ objfmt_elf->objfmt.module = &yasm_elf64_LTX_objfmt;
+ }
+ return objfmt;
+}
+
+static yasm_objfmt *
+elf32_objfmt_create(yasm_object *object)
+{
+ return elf_objfmt_create_common(object, &yasm_elf32_LTX_objfmt, 32, NULL);
+}
+
+static yasm_objfmt *
+elf64_objfmt_create(yasm_object *object)
+{
+ return elf_objfmt_create_common(object, &yasm_elf64_LTX_objfmt, 64, NULL);
+}
+
+static yasm_objfmt *
+elfx32_objfmt_create(yasm_object *object)
+{
+ return elf_objfmt_create_common(object, &yasm_elfx32_LTX_objfmt, 32, NULL);
+}
+
+static long
+elf_objfmt_output_align(FILE *f, unsigned int align)
+{
+ long pos;
+ unsigned long delta;
+ if (!is_exp2(align))
+ yasm_internal_error("requested alignment not a power of two");
+
+ pos = ftell(f);
+ if (pos == -1) {
+ yasm_error_set(YASM_ERROR_IO,
+ N_("could not get file position on output file"));
+ return -1;
+ }
+ delta = align - (pos & (align-1));
+ if (delta != align) {
+ pos += delta;
+ if (fseek(f, pos, SEEK_SET) < 0) {
+ yasm_error_set(YASM_ERROR_IO,
+ N_("could not set file position on output file"));
+ return -1;
+ }
+ }
+ return pos;
+}
+
+static int
+elf_objfmt_output_reloc(yasm_symrec *sym, yasm_bytecode *bc,
+ unsigned char *buf, unsigned int destsize,
+ unsigned int valsize, int warn, void *d)
+{
+ elf_reloc_entry *reloc;
+ elf_objfmt_output_info *info = d;
+ yasm_intnum *zero;
+ int retval;
+
+ reloc = elf_reloc_entry_create(sym, NULL,
+ yasm_intnum_create_uint(bc->offset), 0, valsize, 0);
+ if (reloc == NULL) {
+ yasm_error_set(YASM_ERROR_TYPE, N_("elf: invalid relocation size"));
+ return 1;
+ }
+ /* allocate .rel[a] sections on a need-basis */
+ elf_secthead_append_reloc(info->sect, info->shead, reloc);
+
+ zero = yasm_intnum_create_uint(0);
+ elf_handle_reloc_addend(zero, reloc, 0);
+ retval = yasm_arch_intnum_tobytes(info->object->arch, zero, buf, destsize,
+ valsize, 0, bc, warn);
+ yasm_intnum_destroy(zero);
+ return retval;
+}
+
+static int
+elf_objfmt_output_value(yasm_value *value, unsigned char *buf,
+ unsigned int destsize, unsigned long offset,
+ yasm_bytecode *bc, int warn, /*@null@*/ void *d)
+{
+ /*@null@*/ elf_objfmt_output_info *info = (elf_objfmt_output_info *)d;
+ /*@dependent@*/ /*@null@*/ yasm_intnum *intn;
+ unsigned long intn_val;
+ /*@null@*/ elf_reloc_entry *reloc = NULL;
+ int retval;
+ unsigned int valsize = value->size;
+
+ if (info == NULL)
+ yasm_internal_error("null info struct");
+
+ if (value->abs)
+ value->abs = yasm_expr_simplify(value->abs, 1);
+
+ /* Try to output constant and PC-relative section-local first.
+ * Note this does NOT output any value with a SEG, WRT, external,
+ * cross-section, or non-PC-relative reference (those are handled below).
+ */
+ switch (yasm_value_output_basic(value, buf, destsize, bc, warn,
+ info->object->arch)) {
+ case -1:
+ return 1;
+ case 0:
+ break;
+ default:
+ return 0;
+ }
+
+ /* Handle other expressions, with relocation if necessary */
+ if (value->seg_of || value->section_rel || value->rshift > 0) {
+ yasm_error_set(YASM_ERROR_TOO_COMPLEX,
+ N_("elf: relocation too complex"));
+ return 1;
+ }
+
+ intn_val = 0;
+ if (value->rel) {
+ yasm_sym_vis vis = yasm_symrec_get_visibility(value->rel);
+ /*@dependent@*/ /*@null@*/ yasm_symrec *sym = value->rel;
+ /*@dependent@*/ /*@null@*/ yasm_symrec *wrt = value->wrt;
+
+ if (wrt == info->objfmt_elf->dotdotsym)
+ wrt = NULL;
+ else if (wrt && elf_is_wrt_sym_relative(wrt))
+ ;
+ else if (wrt && elf_is_wrt_pos_adjusted(wrt))
+ intn_val = offset + bc->offset;
+ else if (vis == YASM_SYM_LOCAL) {
+ yasm_bytecode *sym_precbc;
+ /* Local symbols need relocation to their section's start, and
+ * add in the offset of the bytecode (within the target section)
+ * into the abs portion.
+ *
+ * This is only done if the symbol is relocated against the
+ * section instead of the symbol itself.
+ */
+ if (yasm_symrec_get_label(sym, &sym_precbc)) {
+ /* Relocate to section start */
+ yasm_section *sym_sect = yasm_bc_get_section(sym_precbc);
+ /*@null@*/ elf_secthead *sym_shead;
+ sym_shead = yasm_section_get_data(sym_sect, &elf_section_data);
+ assert(sym_shead != NULL);
+ sym = elf_secthead_get_sym(sym_shead);
+
+ intn_val = yasm_bc_next_offset(sym_precbc);
+ }
+ }
+
+ /* For PC-relative, need to add offset of expression within bc. */
+ if (value->curpos_rel)
+ intn_val += offset;
+
+ /* Check for _GLOBAL_OFFSET_TABLE_ symbol reference */
+ reloc = elf_reloc_entry_create(sym, wrt,
+ yasm_intnum_create_uint(bc->offset + offset), value->curpos_rel,
+ valsize, sym == info->GOT_sym);
+ if (reloc == NULL) {
+ yasm_error_set(YASM_ERROR_TYPE,
+ N_("elf: invalid relocation (WRT or size)"));
+ return 1;
+ }
+ /* allocate .rel[a] sections on a need-basis */
+ elf_secthead_append_reloc(info->sect, info->shead, reloc);
+ }
+
+ intn = yasm_intnum_create_uint(intn_val);
+
+ if (value->abs) {
+ yasm_intnum *intn2 = yasm_expr_get_intnum(&value->abs, 0);
+ if (!intn2) {
+ yasm_error_set(YASM_ERROR_TOO_COMPLEX,
+ N_("elf: relocation too complex"));
+ yasm_intnum_destroy(intn);
+ return 1;
+ }
+ yasm_intnum_calc(intn, YASM_EXPR_ADD, intn2);
+ }
+
+ if (reloc)
+ elf_handle_reloc_addend(intn, reloc, offset);
+ retval = yasm_arch_intnum_tobytes(info->object->arch, intn, buf, destsize,
+ valsize, 0, bc, warn);
+ yasm_intnum_destroy(intn);
+ return retval;
+}
+
+static int
+elf_objfmt_output_bytecode(yasm_bytecode *bc, /*@null@*/ void *d)
+{
+ /*@null@*/ elf_objfmt_output_info *info = (elf_objfmt_output_info *)d;
+ unsigned char buf[256];
+ /*@null@*/ /*@only@*/ unsigned char *bigbuf;
+ unsigned long size = 256;
+ int gap;
+
+ if (info == NULL)
+ yasm_internal_error("null info struct");
+
+ bigbuf = yasm_bc_tobytes(bc, buf, &size, &gap, info,
+ elf_objfmt_output_value, elf_objfmt_output_reloc);
+
+ /* Don't bother doing anything else if size ended up being 0. */
+ if (size == 0) {
+ if (bigbuf)
+ yasm_xfree(bigbuf);
+ return 0;
+ }
+ else {
+ yasm_intnum *bcsize = yasm_intnum_create_uint(size);
+ elf_secthead_add_size(info->shead, bcsize);
+ yasm_intnum_destroy(bcsize);
+ }
+
+ /* 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(buf, 0, 256);
+ left = size;
+ while (left > 256) {
+ fwrite(buf, 256, 1, info->f);
+ left -= 256;
+ }
+ fwrite(buf, left, 1, info->f);
+ } else {
+ /* Output buf (or bigbuf if non-NULL) to file */
+ fwrite(bigbuf ? bigbuf : buf, (size_t)size, 1, info->f);
+ }
+
+ /* If bigbuf was allocated, free it */
+ if (bigbuf)
+ yasm_xfree(bigbuf);
+
+ return 0;
+}
+
+static int
+elf_objfmt_output_section(yasm_section *sect, /*@null@*/ void *d)
+{
+ /*@null@*/ elf_objfmt_output_info *info = (elf_objfmt_output_info *)d;
+ /*@dependent@*/ /*@null@*/ elf_secthead *shead;
+ long pos;
+ char *relname;
+ const char *sectname;
+
+ if (info == NULL)
+ yasm_internal_error("null info struct");
+ shead = yasm_section_get_data(sect, &elf_section_data);
+ if (shead == NULL)
+ yasm_internal_error("no associated data");
+
+ if (elf_secthead_get_align(shead) == 0)
+ elf_secthead_set_align(shead, yasm_section_get_align(sect));
+
+ /* don't output header-only sections */
+ if ((elf_secthead_get_type(shead) & SHT_NOBITS) == SHT_NOBITS)
+ {
+ yasm_bytecode *last = yasm_section_bcs_last(sect);
+ if (last) {
+ yasm_intnum *sectsize;
+ sectsize = yasm_intnum_create_uint(yasm_bc_next_offset(last));
+ elf_secthead_add_size(shead, sectsize);
+ yasm_intnum_destroy(sectsize);
+ }
+ elf_secthead_set_index(shead, ++info->sindex);
+ return 0;
+ }
+
+ if ((pos = ftell(info->f)) == -1) {
+ yasm_error_set(YASM_ERROR_IO,
+ N_("couldn't read position on output stream"));
+ yasm_errwarn_propagate(info->errwarns, 0);
+ }
+ pos = elf_secthead_set_file_offset(shead, pos);
+ if (fseek(info->f, pos, SEEK_SET) < 0) {
+ yasm_error_set(YASM_ERROR_IO, N_("couldn't seek on output stream"));
+ yasm_errwarn_propagate(info->errwarns, 0);
+ }
+
+ info->sect = sect;
+ info->shead = shead;
+ yasm_section_bcs_traverse(sect, info->errwarns, info,
+ elf_objfmt_output_bytecode);
+
+ elf_secthead_set_index(shead, ++info->sindex);
+
+ /* No relocations to output? Go on to next section */
+ if (elf_secthead_write_relocs_to_file(info->f, sect, shead,
+ info->errwarns) == 0)
+ return 0;
+ elf_secthead_set_rel_index(shead, ++info->sindex);
+
+ /* name the relocation section .rel[a].foo */
+ sectname = yasm_section_get_name(sect);
+ relname = elf_secthead_name_reloc_section(sectname);
+ elf_secthead_set_rel_name(shead,
+ elf_strtab_append_str(info->objfmt_elf->shstrtab, relname));
+ yasm_xfree(relname);
+
+ return 0;
+}
+
+static int
+elf_objfmt_output_secthead(yasm_section *sect, /*@null@*/ void *d)
+{
+ /*@null@*/ elf_objfmt_output_info *info = (elf_objfmt_output_info *)d;
+ /*@dependent@*/ /*@null@*/ elf_secthead *shead;
+
+ if (info == NULL)
+ yasm_internal_error("null info struct");
+ shead = yasm_section_get_data(sect, &elf_section_data);
+ if (shead == NULL)
+ yasm_internal_error("no section header attached to section");
+
+ if(elf_secthead_write_to_file(info->f, shead, info->sindex+1))
+ info->sindex++;
+
+ /* output strtab headers here? */
+
+ /* relocation entries for .foo are stored in section .rel[a].foo */
+ if(elf_secthead_write_rel_to_file(info->f, 3, sect, shead,
+ info->sindex+1))
+ info->sindex++;
+
+ return 0;
+}
+
+static void
+elf_objfmt_output(yasm_object *object, FILE *f, int all_syms,
+ yasm_errwarns *errwarns)
+{
+ yasm_objfmt_elf *objfmt_elf = (yasm_objfmt_elf *)object->objfmt;
+ elf_objfmt_output_info info;
+ build_symtab_info buildsym_info;
+ long pos;
+ unsigned long elf_shead_addr;
+ elf_secthead *esdn;
+ unsigned long elf_strtab_offset, elf_shstrtab_offset, elf_symtab_offset;
+ unsigned long elf_strtab_size, elf_shstrtab_size, elf_symtab_size;
+ elf_strtab_entry *elf_strtab_name, *elf_shstrtab_name, *elf_symtab_name;
+ unsigned long elf_symtab_nlocal;
+
+ info.object = object;
+ info.objfmt_elf = objfmt_elf;
+ info.errwarns = errwarns;
+ info.f = f;
+ info.GOT_sym = yasm_symtab_get(object->symtab, "_GLOBAL_OFFSET_TABLE_");
+
if (!object->deb_filename) {
object->deb_filename = yasm_replace_path(
objfmt_elf->objfmt.module->replace_map, objfmt_elf->objfmt.module->replace_map_size,
object->src_filename, strlen(object->src_filename));
}
- /* Update filename strtab */
- elf_strtab_entry_set_str(objfmt_elf->file_strtab_entry,
+ /* Update filename strtab */
+ elf_strtab_entry_set_str(objfmt_elf->file_strtab_entry,
object->deb_filename);
-
- /* Allocate space for Ehdr by seeking forward */
- if (fseek(f, (long)(elf_proghead_get_size()), SEEK_SET) < 0) {
- yasm_error_set(YASM_ERROR_IO, N_("could not seek on output file"));
- yasm_errwarn_propagate(errwarns, 0);
- return;
- }
-
- /* add all (local) syms to symtab because relocation needs a symtab index
- * if all_syms, register them by name. if not, use strtab entry 0 */
- buildsym_info.object = object;
- buildsym_info.objfmt_elf = objfmt_elf;
- buildsym_info.errwarns = errwarns;
- buildsym_info.local_names = all_syms;
- yasm_symtab_traverse(object->symtab, &buildsym_info,
- elf_objfmt_build_symtab);
- elf_symtab_nlocal = elf_symtab_assign_indices(objfmt_elf->elf_symtab);
-
- /* output known sections - includes reloc sections which aren't in yasm's
- * list. Assign indices as we go. */
- info.sindex = 3;
- if (yasm_object_sections_traverse(object, &info,
- elf_objfmt_output_section))
- return;
-
- /* add final sections to the shstrtab */
- elf_strtab_name = elf_strtab_append_str(objfmt_elf->shstrtab, ".strtab");
- elf_symtab_name = elf_strtab_append_str(objfmt_elf->shstrtab, ".symtab");
- elf_shstrtab_name = elf_strtab_append_str(objfmt_elf->shstrtab,
- ".shstrtab");
-
- /* output .shstrtab */
- if ((pos = elf_objfmt_output_align(f, 4)) == -1) {
- yasm_errwarn_propagate(errwarns, 0);
- return;
- }
- elf_shstrtab_offset = (unsigned long) pos;
- elf_shstrtab_size = elf_strtab_output_to_file(f, objfmt_elf->shstrtab);
-
- /* output .strtab */
- if ((pos = elf_objfmt_output_align(f, 4)) == -1) {
- yasm_errwarn_propagate(errwarns, 0);
- return;
- }
- elf_strtab_offset = (unsigned long) pos;
- elf_strtab_size = elf_strtab_output_to_file(f, objfmt_elf->strtab);
-
- /* output .symtab - last section so all others have indexes */
- if ((pos = elf_objfmt_output_align(f, 4)) == -1) {
- yasm_errwarn_propagate(errwarns, 0);
- return;
- }
- elf_symtab_offset = (unsigned long) pos;
- elf_symtab_size = elf_symtab_write_to_file(f, objfmt_elf->elf_symtab,
- errwarns);
-
- /* output section header table */
- if ((pos = elf_objfmt_output_align(f, 16)) == -1) {
- yasm_errwarn_propagate(errwarns, 0);
- return;
- }
- elf_shead_addr = (unsigned long) pos;
-
- /* stabs debugging support */
- if (strcmp(yasm_dbgfmt_keyword(object->dbgfmt), "stabs")==0) {
- yasm_section *stabsect = yasm_object_find_general(object, ".stab");
- yasm_section *stabstrsect =
- yasm_object_find_general(object, ".stabstr");
- if (stabsect && stabstrsect) {
- elf_secthead *stab =
- yasm_section_get_data(stabsect, &elf_section_data);
- elf_secthead *stabstr =
- yasm_section_get_data(stabstrsect, &elf_section_data);
- if (stab && stabstr) {
- elf_secthead_set_link(stab, elf_secthead_get_index(stabstr));
- }
- else
- yasm_internal_error(N_("missing .stab or .stabstr section/data"));
- }
- }
-
- /* output dummy section header - 0 */
- info.sindex = 0;
-
- esdn = elf_secthead_create(NULL, SHT_NULL, 0, 0, 0);
- elf_secthead_set_index(esdn, 0);
- elf_secthead_write_to_file(f, esdn, 0);
- elf_secthead_destroy(esdn);
-
- esdn = elf_secthead_create(elf_shstrtab_name, SHT_STRTAB, 0,
- elf_shstrtab_offset, elf_shstrtab_size);
- elf_secthead_set_index(esdn, 1);
- elf_secthead_write_to_file(f, esdn, 1);
- elf_secthead_destroy(esdn);
-
- esdn = elf_secthead_create(elf_strtab_name, SHT_STRTAB, 0,
- elf_strtab_offset, elf_strtab_size);
- elf_secthead_set_index(esdn, 2);
- elf_secthead_write_to_file(f, esdn, 2);
- elf_secthead_destroy(esdn);
-
- esdn = elf_secthead_create(elf_symtab_name, SHT_SYMTAB, 0,
- elf_symtab_offset, elf_symtab_size);
- elf_secthead_set_index(esdn, 3);
- elf_secthead_set_info(esdn, elf_symtab_nlocal);
- elf_secthead_set_link(esdn, 2); /* for .strtab, which is index 2 */
- elf_secthead_write_to_file(f, esdn, 3);
- elf_secthead_destroy(esdn);
-
- info.sindex = 3;
- /* output remaining section headers */
- yasm_object_sections_traverse(object, &info, elf_objfmt_output_secthead);
-
- /* output Ehdr */
- if (fseek(f, 0, SEEK_SET) < 0) {
- yasm_error_set(YASM_ERROR_IO, N_("could not seek on output file"));
- yasm_errwarn_propagate(errwarns, 0);
- return;
- }
-
- elf_proghead_write_to_file(f, elf_shead_addr, info.sindex+1, 1);
-}
-
-static void
-elf_objfmt_destroy(yasm_objfmt *objfmt)
-{
- yasm_objfmt_elf *objfmt_elf = (yasm_objfmt_elf *)objfmt;
- elf_symtab_destroy(objfmt_elf->elf_symtab);
- elf_strtab_destroy(objfmt_elf->shstrtab);
- elf_strtab_destroy(objfmt_elf->strtab);
- yasm_xfree(objfmt);
-}
-
-static void
-elf_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_elf *objfmt_elf = (yasm_objfmt_elf *)object->objfmt;
- elf_secthead *esd;
- yasm_symrec *sym;
- elf_strtab_entry *name = elf_strtab_append_str(objfmt_elf->shstrtab,
- sectname);
-
- elf_section_type type=SHT_PROGBITS;
- elf_size entsize=0;
-
- if (yasm__strcasecmp(sectname, ".stab")==0) {
- entsize = 12;
- } else if (yasm__strcasecmp(sectname, ".stabstr")==0) {
- type = SHT_STRTAB;
- }
-
- esd = elf_secthead_create(name, type, 0, 0, 0);
- elf_secthead_set_entsize(esd, entsize);
- yasm_section_add_data(sect, &elf_section_data, esd);
- sym = yasm_symtab_define_label(object->symtab, sectname,
- yasm_section_bcs_first(sect), 1, line);
-
- elf_secthead_set_sym(esd, sym);
-}
-
-static yasm_section *
-elf_objfmt_add_default_section(yasm_object *object)
-{
- yasm_section *retval;
- int isnew;
-
- retval = yasm_object_get_general(object, ".text", 16, 1, 0, &isnew, 0);
- if (isnew)
- {
- elf_secthead *esd = yasm_section_get_data(retval, &elf_section_data);
- elf_secthead_set_typeflags(esd, SHT_PROGBITS,
- SHF_ALLOC + SHF_EXECINSTR);
- yasm_section_set_default(retval, 1);
- }
- return retval;
-}
-
-struct elf_section_switch_data {
- /*@only@*/ /*@null@*/ yasm_intnum *align_intn;
- unsigned long flags;
- unsigned long type;
- int gasflags;
- int stdsect;
-};
-
-/* GAS-style flags */
-static int
-elf_helper_gasflags(void *obj, yasm_valparam *vp, unsigned long line, void *d,
- /*@unused@*/ uintptr_t arg)
-{
- struct elf_section_switch_data *data = (struct elf_section_switch_data *)d;
- const char *s = yasm_vp_string(vp);
- size_t i;
-
- if (!s) {
- yasm_error_set(YASM_ERROR_VALUE,
- N_("non-string section attribute"));
- return -1;
- }
-
- if (data->stdsect && strlen(s) == 0) {
- data->gasflags = 1;
- return 0;
- }
-
- data->flags = 0;
- for (i=0; i<strlen(s); i++) {
- switch (s[i]) {
- case 'a':
- data->flags |= SHF_ALLOC;
- break;
- case 'w':
- data->flags |= SHF_WRITE;
- break;
- case 'x':
- data->flags |= SHF_EXECINSTR;
- break;
- case 'M':
- data->flags |= SHF_MERGE;
- break;
- case 'S':
- data->flags |= SHF_STRINGS;
- break;
- case 'G':
- data->flags |= SHF_GROUP;
- break;
- case 'T':
- data->flags |= SHF_TLS;
- break;
- default:
- yasm_warn_set(YASM_WARN_GENERAL,
- N_("unrecognized section attribute: `%c'"),
- s[i]);
- }
- }
-
- data->gasflags = 1;
- return 0;
-}
-
-static /*@observer@*/ /*@null@*/ yasm_section *
-elf_objfmt_section_switch(yasm_object *object, yasm_valparamhead *valparams,
- /*@null@*/ yasm_valparamhead *objext_valparams,
- unsigned long line)
-{
- yasm_valparam *vp;
- yasm_section *retval;
- int isnew;
- unsigned long align = 4;
- int flags_override = 0;
- const char *sectname;
- int resonly = 0;
-
- struct elf_section_switch_data data;
-
- static const yasm_dir_help help[] = {
- { "alloc", 0, yasm_dir_helper_flag_or,
- offsetof(struct elf_section_switch_data, flags), SHF_ALLOC },
- { "exec", 0, yasm_dir_helper_flag_or,
- offsetof(struct elf_section_switch_data, flags), SHF_EXECINSTR },
- { "write", 0, yasm_dir_helper_flag_or,
- offsetof(struct elf_section_switch_data, flags), SHF_WRITE },
- { "tls", 0, yasm_dir_helper_flag_or,
- offsetof(struct elf_section_switch_data, flags), SHF_TLS },
- { "progbits", 0, yasm_dir_helper_flag_set,
- offsetof(struct elf_section_switch_data, type), SHT_PROGBITS },
- { "noalloc", 0, yasm_dir_helper_flag_and,
- offsetof(struct elf_section_switch_data, flags), SHF_ALLOC },
- { "noexec", 0, yasm_dir_helper_flag_and,
- offsetof(struct elf_section_switch_data, flags), SHF_EXECINSTR },
- { "nowrite", 0, yasm_dir_helper_flag_and,
- offsetof(struct elf_section_switch_data, flags), SHF_WRITE },
- { "notls", 0, yasm_dir_helper_flag_and,
- offsetof(struct elf_section_switch_data, flags), SHF_TLS },
- { "noprogbits", 0, yasm_dir_helper_flag_set,
- offsetof(struct elf_section_switch_data, type), SHT_NOBITS },
- { "nobits", 0, yasm_dir_helper_flag_set,
- offsetof(struct elf_section_switch_data, type), SHT_NOBITS },
- { "gasflags", 1, elf_helper_gasflags, 0, 0 },
- { "align", 1, yasm_dir_helper_intn,
- offsetof(struct elf_section_switch_data, align_intn), 0 }
- };
- /*@only@*/ /*@null@*/ yasm_expr *merge_expr = NULL;
- /*@dependent@*/ /*@null@*/ const yasm_intnum *merge_intn = NULL;
- elf_secthead *esd;
-
- data.align_intn = NULL;
- data.flags = SHF_ALLOC;
- data.type = SHT_PROGBITS;
- data.gasflags = 0;
- data.stdsect = 1;
-
- vp = yasm_vps_first(valparams);
- sectname = yasm_vp_string(vp);
- if (!sectname)
- return NULL;
- vp = yasm_vps_next(vp);
-
- if (strcmp(sectname, ".bss") == 0) {
- data.type = SHT_NOBITS;
- data.flags = SHF_ALLOC + SHF_WRITE;
- resonly = 1;
- } else if (strcmp(sectname, ".data") == 0) {
- data.type = SHT_PROGBITS;
- data.flags = SHF_ALLOC + SHF_WRITE;
- } else if (strcmp(sectname, ".tdata") == 0) {
- data.type = SHT_PROGBITS;
- data.flags = SHF_ALLOC + SHF_WRITE + SHF_TLS;
- } else if (strcmp(sectname, ".rodata") == 0) {
- data.type = SHT_PROGBITS;
- data.flags = SHF_ALLOC;
- } else if (strcmp(sectname, ".text") == 0) {
- align = 16;
- data.type = SHT_PROGBITS;
- data.flags = SHF_ALLOC + SHF_EXECINSTR;
- } else if (strcmp(sectname, ".comment") == 0) {
- align = 0;
- data.type = SHT_PROGBITS;
- data.flags = 0;
- } else {
- /* Default to code */
- align = 1;
- data.stdsect = 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.align_intn) {
- align = yasm_intnum_get_uint(data.align_intn);
- yasm_intnum_destroy(data.align_intn);
-
- /* 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;
- }
- }
-
- /* Handle merge entity size */
- if (data.flags & SHF_MERGE) {
- if (objext_valparams && (vp = yasm_vps_first(objext_valparams))
- && !vp->val) {
- if (!(merge_expr = yasm_vp_expr(vp, object->symtab, line)) ||
- !(merge_intn = yasm_expr_get_intnum(&merge_expr, 0)))
- yasm_warn_set(YASM_WARN_GENERAL,
- N_("invalid merge entity size"));
- } else {
- yasm_warn_set(YASM_WARN_GENERAL,
- N_("entity size for SHF_MERGE not specified"));
- data.flags &= ~SHF_MERGE;
- }
- }
-
- retval = yasm_object_get_general(object, sectname, align,
- (data.flags & SHF_EXECINSTR) != 0,
- resonly, &isnew, line);
-
- esd = yasm_section_get_data(retval, &elf_section_data);
-
- if (isnew || yasm_section_is_default(retval)) {
- yasm_section_set_default(retval, 0);
- elf_secthead_set_typeflags(esd, data.type, data.flags);
- if (merge_intn)
- elf_secthead_set_entsize(esd, yasm_intnum_get_uint(merge_intn));
- yasm_section_set_align(retval, align, line);
- } else if (flags_override && !data.gasflags)
- yasm_warn_set(YASM_WARN_GENERAL,
- N_("section flags ignored on section redeclaration"));
- if (merge_expr)
- yasm_expr_destroy(merge_expr);
- return retval;
-}
-
-static /*@observer@*/ /*@null@*/ yasm_symrec *
-elf_objfmt_get_special_sym(yasm_object *object, const char *name,
- const char *parser)
-{
- if (yasm__strcasecmp(name, "sym") == 0) {
- yasm_objfmt_elf *objfmt_elf = (yasm_objfmt_elf *)object->objfmt;
- return objfmt_elf->dotdotsym;
- }
- return elf_get_special_sym(name, parser);
-}
-
-static void
-dir_type(yasm_object *object, yasm_valparamhead *valparams,
- yasm_valparamhead *objext_valparams, unsigned long line)
-{
- yasm_objfmt_elf *objfmt_elf = (yasm_objfmt_elf *)object->objfmt;
- yasm_valparam *vp = yasm_vps_first(valparams);
- const char *symname = yasm_vp_id(vp);
- /* Get symbol elf data */
- yasm_symrec *sym = yasm_symtab_use(object->symtab, symname, line);
- elf_symtab_entry *entry = yasm_symrec_get_data(sym, &elf_symrec_data);
- /*@null@*/ const char *type;
-
- /* Create entry if necessary */
- if (!entry) {
- entry = elf_symtab_entry_create(
- elf_strtab_append_str(objfmt_elf->strtab, symname), sym);
- yasm_symrec_add_data(sym, &elf_symrec_data, entry);
- }
-
- /* Pull new type from param */
- vp = yasm_vps_next(vp);
- if (vp && !vp->val && (type = yasm_vp_id(vp))) {
- if (yasm__strcasecmp(type, "function") == 0)
- elf_sym_set_type(entry, STT_FUNC);
- else if (yasm__strcasecmp(type, "object") == 0)
- elf_sym_set_type(entry, STT_OBJECT);
- else if (yasm__strcasecmp(type, "tls_object") == 0)
- elf_sym_set_type(entry, STT_TLS);
- else if (yasm__strcasecmp(type, "notype") == 0)
- elf_sym_set_type(entry, STT_NOTYPE);
- else
- yasm_warn_set(YASM_WARN_GENERAL,
- N_("unrecognized symbol type `%s'"), type);
- } else
- yasm_error_set(YASM_ERROR_SYNTAX, N_("no type specified"));
-}
-
-static void
-dir_size(yasm_object *object, yasm_valparamhead *valparams,
- yasm_valparamhead *objext_valparams, unsigned long line)
-{
- yasm_objfmt_elf *objfmt_elf = (yasm_objfmt_elf *)object->objfmt;
- yasm_valparam *vp = yasm_vps_first(valparams);
- const char *symname = yasm_vp_id(vp);
- /* Get symbol elf data */
- yasm_symrec *sym = yasm_symtab_use(object->symtab, symname, line);
- elf_symtab_entry *entry = yasm_symrec_get_data(sym, &elf_symrec_data);
- /*@only@*/ /*@null@*/ yasm_expr *size;
-
- /* Create entry if necessary */
- if (!entry) {
- entry = elf_symtab_entry_create(
- elf_strtab_append_str(objfmt_elf->strtab, symname), sym);
- yasm_symrec_add_data(sym, &elf_symrec_data, entry);
- }
-
- /* Pull new size from param */
- vp = yasm_vps_next(vp);
- if (vp && !vp->val && (size = yasm_vp_expr(vp, object->symtab, line)))
- elf_sym_set_size(entry, size);
- else
- yasm_error_set(YASM_ERROR_SYNTAX, N_("no size specified"));
-}
-
-static void
-dir_weak(yasm_object *object, yasm_valparamhead *valparams,
- yasm_valparamhead *objext_valparams, unsigned long line)
-{
- yasm_objfmt_elf *objfmt_elf = (yasm_objfmt_elf *)object->objfmt;
- yasm_valparam *vp = yasm_vps_first(valparams);
- const char *symname = yasm_vp_id(vp);
- yasm_symrec *sym = yasm_symtab_declare(object->symtab, symname,
- YASM_SYM_GLOBAL, line);
- elf_objfmt_symtab_append(objfmt_elf, sym, SHN_UNDEF, STB_WEAK, 0,
- STV_DEFAULT, NULL, NULL, object);
-}
-
-static void
-dir_ident(yasm_object *object, yasm_valparamhead *valparams,
- yasm_valparamhead *objext_valparams, unsigned long line)
-{
- yasm_valparamhead sect_vps;
- yasm_datavalhead dvs;
- yasm_section *comment;
- yasm_valparam *vp;
- yasm_valparam *vp2;
-
- /* Accept, but do nothing with empty ident */
- if (!valparams)
- return;
- vp = yasm_vps_first(valparams);
- if (!vp)
- return;
-
- /* Put ident data into .comment section */
- yasm_vps_initialize(&sect_vps);
- vp2 = yasm_vp_create_string(NULL, yasm__xstrdup(".comment"));
- yasm_vps_append(&sect_vps, vp2);
- comment = elf_objfmt_section_switch(object, &sect_vps, NULL, line);
- yasm_vps_delete(&sect_vps);
-
- /* To match GAS output, if the comment section is empty, put an
- * initial 0 byte in the section.
- */
- if (yasm_section_bcs_first(comment) == yasm_section_bcs_last(comment)) {
- yasm_dvs_initialize(&dvs);
- yasm_dvs_append(&dvs, yasm_dv_create_expr(
- yasm_expr_create_ident(
- yasm_expr_int(yasm_intnum_create_uint(0)), line)));
- yasm_section_bcs_append(comment,
- yasm_bc_create_data(&dvs, 1, 0, object->arch, line));
- }
-
- yasm_dvs_initialize(&dvs);
- do {
- const char *s = yasm_vp_string(vp);
- if (!s) {
- yasm_error_set(YASM_ERROR_VALUE,
- N_(".comment requires string parameters"));
- yasm_dvs_delete(&dvs);
- return;
- }
- yasm_dvs_append(&dvs,
- yasm_dv_create_string(yasm__xstrdup(s), strlen(s)));
- } while ((vp = yasm_vps_next(vp)));
-
- yasm_section_bcs_append(comment,
- yasm_bc_create_data(&dvs, 1, 1, object->arch, line));
-}
-
-/* Define valid debug formats to use with this object format */
-static const char *elf_objfmt_dbgfmt_keywords[] = {
- "null",
- "stabs",
- "dwarf2",
- NULL
-};
-
-static const yasm_directive elf_objfmt_directives[] = {
- { ".type", "gas", dir_type, YASM_DIR_ID_REQUIRED },
- { ".size", "gas", dir_size, YASM_DIR_ID_REQUIRED },
- { ".weak", "gas", dir_weak, YASM_DIR_ID_REQUIRED },
- { ".ident", "gas", dir_ident, YASM_DIR_ANY },
- { "type", "nasm", dir_type, YASM_DIR_ID_REQUIRED },
- { "size", "nasm", dir_size, YASM_DIR_ID_REQUIRED },
- { "weak", "nasm", dir_weak, YASM_DIR_ID_REQUIRED },
- { "ident", "nasm", dir_ident, YASM_DIR_ANY },
- { NULL, NULL, NULL, 0 }
-};
-
-static const char *elf_nasm_stdmac[] = {
- "%imacro type 1+.nolist",
- "[type %1]",
- "%endmacro",
- "%imacro size 1+.nolist",
- "[size %1]",
- "%endmacro",
- "%imacro weak 1+.nolist",
- "[weak %1]",
- "%endmacro",
- NULL
-};
-
-static const yasm_stdmac elf_objfmt_stdmacs[] = {
- { "nasm", "nasm", elf_nasm_stdmac },
- { NULL, NULL, NULL }
-};
-
-/* Define objfmt structure -- see objfmt.h for details */
-yasm_objfmt_module yasm_elf_LTX_objfmt = {
- "ELF",
- "elf",
- "o",
- 32,
- 0,
- elf_objfmt_dbgfmt_keywords,
- "null",
- elf_objfmt_directives,
- elf_objfmt_stdmacs,
- elf_objfmt_create,
- elf_objfmt_output,
- elf_objfmt_destroy,
- elf_objfmt_add_default_section,
- elf_objfmt_init_new_section,
- elf_objfmt_section_switch,
- elf_objfmt_get_special_sym
-};
-
-yasm_objfmt_module yasm_elf32_LTX_objfmt = {
- "ELF (32-bit)",
- "elf32",
- "o",
- 32,
- 0,
- elf_objfmt_dbgfmt_keywords,
- "null",
- elf_objfmt_directives,
- elf_objfmt_stdmacs,
- elf32_objfmt_create,
- elf_objfmt_output,
- elf_objfmt_destroy,
- elf_objfmt_add_default_section,
- elf_objfmt_init_new_section,
- elf_objfmt_section_switch,
- elf_objfmt_get_special_sym
-};
-
-yasm_objfmt_module yasm_elf64_LTX_objfmt = {
- "ELF (64-bit)",
- "elf64",
- "o",
- 64,
- 0,
- elf_objfmt_dbgfmt_keywords,
- "null",
- elf_objfmt_directives,
- elf_objfmt_stdmacs,
- elf64_objfmt_create,
- elf_objfmt_output,
- elf_objfmt_destroy,
- elf_objfmt_add_default_section,
- elf_objfmt_init_new_section,
- elf_objfmt_section_switch,
- elf_objfmt_get_special_sym
-};
-
-yasm_objfmt_module yasm_elfx32_LTX_objfmt = {
- "ELF (x32)",
- "elfx32",
- "o",
- 64,
- 0,
- elf_objfmt_dbgfmt_keywords,
- "null",
- elf_objfmt_directives,
- elf_objfmt_stdmacs,
- elfx32_objfmt_create,
- elf_objfmt_output,
- elf_objfmt_destroy,
- elf_objfmt_add_default_section,
- elf_objfmt_init_new_section,
- elf_objfmt_section_switch,
- elf_objfmt_get_special_sym
-};
+
+ /* Allocate space for Ehdr by seeking forward */
+ if (fseek(f, (long)(elf_proghead_get_size()), SEEK_SET) < 0) {
+ yasm_error_set(YASM_ERROR_IO, N_("could not seek on output file"));
+ yasm_errwarn_propagate(errwarns, 0);
+ return;
+ }
+
+ /* add all (local) syms to symtab because relocation needs a symtab index
+ * if all_syms, register them by name. if not, use strtab entry 0 */
+ buildsym_info.object = object;
+ buildsym_info.objfmt_elf = objfmt_elf;
+ buildsym_info.errwarns = errwarns;
+ buildsym_info.local_names = all_syms;
+ yasm_symtab_traverse(object->symtab, &buildsym_info,
+ elf_objfmt_build_symtab);
+ elf_symtab_nlocal = elf_symtab_assign_indices(objfmt_elf->elf_symtab);
+
+ /* output known sections - includes reloc sections which aren't in yasm's
+ * list. Assign indices as we go. */
+ info.sindex = 3;
+ if (yasm_object_sections_traverse(object, &info,
+ elf_objfmt_output_section))
+ return;
+
+ /* add final sections to the shstrtab */
+ elf_strtab_name = elf_strtab_append_str(objfmt_elf->shstrtab, ".strtab");
+ elf_symtab_name = elf_strtab_append_str(objfmt_elf->shstrtab, ".symtab");
+ elf_shstrtab_name = elf_strtab_append_str(objfmt_elf->shstrtab,
+ ".shstrtab");
+
+ /* output .shstrtab */
+ if ((pos = elf_objfmt_output_align(f, 4)) == -1) {
+ yasm_errwarn_propagate(errwarns, 0);
+ return;
+ }
+ elf_shstrtab_offset = (unsigned long) pos;
+ elf_shstrtab_size = elf_strtab_output_to_file(f, objfmt_elf->shstrtab);
+
+ /* output .strtab */
+ if ((pos = elf_objfmt_output_align(f, 4)) == -1) {
+ yasm_errwarn_propagate(errwarns, 0);
+ return;
+ }
+ elf_strtab_offset = (unsigned long) pos;
+ elf_strtab_size = elf_strtab_output_to_file(f, objfmt_elf->strtab);
+
+ /* output .symtab - last section so all others have indexes */
+ if ((pos = elf_objfmt_output_align(f, 4)) == -1) {
+ yasm_errwarn_propagate(errwarns, 0);
+ return;
+ }
+ elf_symtab_offset = (unsigned long) pos;
+ elf_symtab_size = elf_symtab_write_to_file(f, objfmt_elf->elf_symtab,
+ errwarns);
+
+ /* output section header table */
+ if ((pos = elf_objfmt_output_align(f, 16)) == -1) {
+ yasm_errwarn_propagate(errwarns, 0);
+ return;
+ }
+ elf_shead_addr = (unsigned long) pos;
+
+ /* stabs debugging support */
+ if (strcmp(yasm_dbgfmt_keyword(object->dbgfmt), "stabs")==0) {
+ yasm_section *stabsect = yasm_object_find_general(object, ".stab");
+ yasm_section *stabstrsect =
+ yasm_object_find_general(object, ".stabstr");
+ if (stabsect && stabstrsect) {
+ elf_secthead *stab =
+ yasm_section_get_data(stabsect, &elf_section_data);
+ elf_secthead *stabstr =
+ yasm_section_get_data(stabstrsect, &elf_section_data);
+ if (stab && stabstr) {
+ elf_secthead_set_link(stab, elf_secthead_get_index(stabstr));
+ }
+ else
+ yasm_internal_error(N_("missing .stab or .stabstr section/data"));
+ }
+ }
+
+ /* output dummy section header - 0 */
+ info.sindex = 0;
+
+ esdn = elf_secthead_create(NULL, SHT_NULL, 0, 0, 0);
+ elf_secthead_set_index(esdn, 0);
+ elf_secthead_write_to_file(f, esdn, 0);
+ elf_secthead_destroy(esdn);
+
+ esdn = elf_secthead_create(elf_shstrtab_name, SHT_STRTAB, 0,
+ elf_shstrtab_offset, elf_shstrtab_size);
+ elf_secthead_set_index(esdn, 1);
+ elf_secthead_write_to_file(f, esdn, 1);
+ elf_secthead_destroy(esdn);
+
+ esdn = elf_secthead_create(elf_strtab_name, SHT_STRTAB, 0,
+ elf_strtab_offset, elf_strtab_size);
+ elf_secthead_set_index(esdn, 2);
+ elf_secthead_write_to_file(f, esdn, 2);
+ elf_secthead_destroy(esdn);
+
+ esdn = elf_secthead_create(elf_symtab_name, SHT_SYMTAB, 0,
+ elf_symtab_offset, elf_symtab_size);
+ elf_secthead_set_index(esdn, 3);
+ elf_secthead_set_info(esdn, elf_symtab_nlocal);
+ elf_secthead_set_link(esdn, 2); /* for .strtab, which is index 2 */
+ elf_secthead_write_to_file(f, esdn, 3);
+ elf_secthead_destroy(esdn);
+
+ info.sindex = 3;
+ /* output remaining section headers */
+ yasm_object_sections_traverse(object, &info, elf_objfmt_output_secthead);
+
+ /* output Ehdr */
+ if (fseek(f, 0, SEEK_SET) < 0) {
+ yasm_error_set(YASM_ERROR_IO, N_("could not seek on output file"));
+ yasm_errwarn_propagate(errwarns, 0);
+ return;
+ }
+
+ elf_proghead_write_to_file(f, elf_shead_addr, info.sindex+1, 1);
+}
+
+static void
+elf_objfmt_destroy(yasm_objfmt *objfmt)
+{
+ yasm_objfmt_elf *objfmt_elf = (yasm_objfmt_elf *)objfmt;
+ elf_symtab_destroy(objfmt_elf->elf_symtab);
+ elf_strtab_destroy(objfmt_elf->shstrtab);
+ elf_strtab_destroy(objfmt_elf->strtab);
+ yasm_xfree(objfmt);
+}
+
+static void
+elf_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_elf *objfmt_elf = (yasm_objfmt_elf *)object->objfmt;
+ elf_secthead *esd;
+ yasm_symrec *sym;
+ elf_strtab_entry *name = elf_strtab_append_str(objfmt_elf->shstrtab,
+ sectname);
+
+ elf_section_type type=SHT_PROGBITS;
+ elf_size entsize=0;
+
+ if (yasm__strcasecmp(sectname, ".stab")==0) {
+ entsize = 12;
+ } else if (yasm__strcasecmp(sectname, ".stabstr")==0) {
+ type = SHT_STRTAB;
+ }
+
+ esd = elf_secthead_create(name, type, 0, 0, 0);
+ elf_secthead_set_entsize(esd, entsize);
+ yasm_section_add_data(sect, &elf_section_data, esd);
+ sym = yasm_symtab_define_label(object->symtab, sectname,
+ yasm_section_bcs_first(sect), 1, line);
+
+ elf_secthead_set_sym(esd, sym);
+}
+
+static yasm_section *
+elf_objfmt_add_default_section(yasm_object *object)
+{
+ yasm_section *retval;
+ int isnew;
+
+ retval = yasm_object_get_general(object, ".text", 16, 1, 0, &isnew, 0);
+ if (isnew)
+ {
+ elf_secthead *esd = yasm_section_get_data(retval, &elf_section_data);
+ elf_secthead_set_typeflags(esd, SHT_PROGBITS,
+ SHF_ALLOC + SHF_EXECINSTR);
+ yasm_section_set_default(retval, 1);
+ }
+ return retval;
+}
+
+struct elf_section_switch_data {
+ /*@only@*/ /*@null@*/ yasm_intnum *align_intn;
+ unsigned long flags;
+ unsigned long type;
+ int gasflags;
+ int stdsect;
+};
+
+/* GAS-style flags */
+static int
+elf_helper_gasflags(void *obj, yasm_valparam *vp, unsigned long line, void *d,
+ /*@unused@*/ uintptr_t arg)
+{
+ struct elf_section_switch_data *data = (struct elf_section_switch_data *)d;
+ const char *s = yasm_vp_string(vp);
+ size_t i;
+
+ if (!s) {
+ yasm_error_set(YASM_ERROR_VALUE,
+ N_("non-string section attribute"));
+ return -1;
+ }
+
+ if (data->stdsect && strlen(s) == 0) {
+ data->gasflags = 1;
+ return 0;
+ }
+
+ data->flags = 0;
+ for (i=0; i<strlen(s); i++) {
+ switch (s[i]) {
+ case 'a':
+ data->flags |= SHF_ALLOC;
+ break;
+ case 'w':
+ data->flags |= SHF_WRITE;
+ break;
+ case 'x':
+ data->flags |= SHF_EXECINSTR;
+ break;
+ case 'M':
+ data->flags |= SHF_MERGE;
+ break;
+ case 'S':
+ data->flags |= SHF_STRINGS;
+ break;
+ case 'G':
+ data->flags |= SHF_GROUP;
+ break;
+ case 'T':
+ data->flags |= SHF_TLS;
+ break;
+ default:
+ yasm_warn_set(YASM_WARN_GENERAL,
+ N_("unrecognized section attribute: `%c'"),
+ s[i]);
+ }
+ }
+
+ data->gasflags = 1;
+ return 0;
+}
+
+static /*@observer@*/ /*@null@*/ yasm_section *
+elf_objfmt_section_switch(yasm_object *object, yasm_valparamhead *valparams,
+ /*@null@*/ yasm_valparamhead *objext_valparams,
+ unsigned long line)
+{
+ yasm_valparam *vp;
+ yasm_section *retval;
+ int isnew;
+ unsigned long align = 4;
+ int flags_override = 0;
+ const char *sectname;
+ int resonly = 0;
+
+ struct elf_section_switch_data data;
+
+ static const yasm_dir_help help[] = {
+ { "alloc", 0, yasm_dir_helper_flag_or,
+ offsetof(struct elf_section_switch_data, flags), SHF_ALLOC },
+ { "exec", 0, yasm_dir_helper_flag_or,
+ offsetof(struct elf_section_switch_data, flags), SHF_EXECINSTR },
+ { "write", 0, yasm_dir_helper_flag_or,
+ offsetof(struct elf_section_switch_data, flags), SHF_WRITE },
+ { "tls", 0, yasm_dir_helper_flag_or,
+ offsetof(struct elf_section_switch_data, flags), SHF_TLS },
+ { "progbits", 0, yasm_dir_helper_flag_set,
+ offsetof(struct elf_section_switch_data, type), SHT_PROGBITS },
+ { "noalloc", 0, yasm_dir_helper_flag_and,
+ offsetof(struct elf_section_switch_data, flags), SHF_ALLOC },
+ { "noexec", 0, yasm_dir_helper_flag_and,
+ offsetof(struct elf_section_switch_data, flags), SHF_EXECINSTR },
+ { "nowrite", 0, yasm_dir_helper_flag_and,
+ offsetof(struct elf_section_switch_data, flags), SHF_WRITE },
+ { "notls", 0, yasm_dir_helper_flag_and,
+ offsetof(struct elf_section_switch_data, flags), SHF_TLS },
+ { "noprogbits", 0, yasm_dir_helper_flag_set,
+ offsetof(struct elf_section_switch_data, type), SHT_NOBITS },
+ { "nobits", 0, yasm_dir_helper_flag_set,
+ offsetof(struct elf_section_switch_data, type), SHT_NOBITS },
+ { "gasflags", 1, elf_helper_gasflags, 0, 0 },
+ { "align", 1, yasm_dir_helper_intn,
+ offsetof(struct elf_section_switch_data, align_intn), 0 }
+ };
+ /*@only@*/ /*@null@*/ yasm_expr *merge_expr = NULL;
+ /*@dependent@*/ /*@null@*/ const yasm_intnum *merge_intn = NULL;
+ elf_secthead *esd;
+
+ data.align_intn = NULL;
+ data.flags = SHF_ALLOC;
+ data.type = SHT_PROGBITS;
+ data.gasflags = 0;
+ data.stdsect = 1;
+
+ vp = yasm_vps_first(valparams);
+ sectname = yasm_vp_string(vp);
+ if (!sectname)
+ return NULL;
+ vp = yasm_vps_next(vp);
+
+ if (strcmp(sectname, ".bss") == 0) {
+ data.type = SHT_NOBITS;
+ data.flags = SHF_ALLOC + SHF_WRITE;
+ resonly = 1;
+ } else if (strcmp(sectname, ".data") == 0) {
+ data.type = SHT_PROGBITS;
+ data.flags = SHF_ALLOC + SHF_WRITE;
+ } else if (strcmp(sectname, ".tdata") == 0) {
+ data.type = SHT_PROGBITS;
+ data.flags = SHF_ALLOC + SHF_WRITE + SHF_TLS;
+ } else if (strcmp(sectname, ".rodata") == 0) {
+ data.type = SHT_PROGBITS;
+ data.flags = SHF_ALLOC;
+ } else if (strcmp(sectname, ".text") == 0) {
+ align = 16;
+ data.type = SHT_PROGBITS;
+ data.flags = SHF_ALLOC + SHF_EXECINSTR;
+ } else if (strcmp(sectname, ".comment") == 0) {
+ align = 0;
+ data.type = SHT_PROGBITS;
+ data.flags = 0;
+ } else {
+ /* Default to code */
+ align = 1;
+ data.stdsect = 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.align_intn) {
+ align = yasm_intnum_get_uint(data.align_intn);
+ yasm_intnum_destroy(data.align_intn);
+
+ /* 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;
+ }
+ }
+
+ /* Handle merge entity size */
+ if (data.flags & SHF_MERGE) {
+ if (objext_valparams && (vp = yasm_vps_first(objext_valparams))
+ && !vp->val) {
+ if (!(merge_expr = yasm_vp_expr(vp, object->symtab, line)) ||
+ !(merge_intn = yasm_expr_get_intnum(&merge_expr, 0)))
+ yasm_warn_set(YASM_WARN_GENERAL,
+ N_("invalid merge entity size"));
+ } else {
+ yasm_warn_set(YASM_WARN_GENERAL,
+ N_("entity size for SHF_MERGE not specified"));
+ data.flags &= ~SHF_MERGE;
+ }
+ }
+
+ retval = yasm_object_get_general(object, sectname, align,
+ (data.flags & SHF_EXECINSTR) != 0,
+ resonly, &isnew, line);
+
+ esd = yasm_section_get_data(retval, &elf_section_data);
+
+ if (isnew || yasm_section_is_default(retval)) {
+ yasm_section_set_default(retval, 0);
+ elf_secthead_set_typeflags(esd, data.type, data.flags);
+ if (merge_intn)
+ elf_secthead_set_entsize(esd, yasm_intnum_get_uint(merge_intn));
+ yasm_section_set_align(retval, align, line);
+ } else if (flags_override && !data.gasflags)
+ yasm_warn_set(YASM_WARN_GENERAL,
+ N_("section flags ignored on section redeclaration"));
+ if (merge_expr)
+ yasm_expr_destroy(merge_expr);
+ return retval;
+}
+
+static /*@observer@*/ /*@null@*/ yasm_symrec *
+elf_objfmt_get_special_sym(yasm_object *object, const char *name,
+ const char *parser)
+{
+ if (yasm__strcasecmp(name, "sym") == 0) {
+ yasm_objfmt_elf *objfmt_elf = (yasm_objfmt_elf *)object->objfmt;
+ return objfmt_elf->dotdotsym;
+ }
+ return elf_get_special_sym(name, parser);
+}
+
+static void
+dir_type(yasm_object *object, yasm_valparamhead *valparams,
+ yasm_valparamhead *objext_valparams, unsigned long line)
+{
+ yasm_objfmt_elf *objfmt_elf = (yasm_objfmt_elf *)object->objfmt;
+ yasm_valparam *vp = yasm_vps_first(valparams);
+ const char *symname = yasm_vp_id(vp);
+ /* Get symbol elf data */
+ yasm_symrec *sym = yasm_symtab_use(object->symtab, symname, line);
+ elf_symtab_entry *entry = yasm_symrec_get_data(sym, &elf_symrec_data);
+ /*@null@*/ const char *type;
+
+ /* Create entry if necessary */
+ if (!entry) {
+ entry = elf_symtab_entry_create(
+ elf_strtab_append_str(objfmt_elf->strtab, symname), sym);
+ yasm_symrec_add_data(sym, &elf_symrec_data, entry);
+ }
+
+ /* Pull new type from param */
+ vp = yasm_vps_next(vp);
+ if (vp && !vp->val && (type = yasm_vp_id(vp))) {
+ if (yasm__strcasecmp(type, "function") == 0)
+ elf_sym_set_type(entry, STT_FUNC);
+ else if (yasm__strcasecmp(type, "object") == 0)
+ elf_sym_set_type(entry, STT_OBJECT);
+ else if (yasm__strcasecmp(type, "tls_object") == 0)
+ elf_sym_set_type(entry, STT_TLS);
+ else if (yasm__strcasecmp(type, "notype") == 0)
+ elf_sym_set_type(entry, STT_NOTYPE);
+ else
+ yasm_warn_set(YASM_WARN_GENERAL,
+ N_("unrecognized symbol type `%s'"), type);
+ } else
+ yasm_error_set(YASM_ERROR_SYNTAX, N_("no type specified"));
+}
+
+static void
+dir_size(yasm_object *object, yasm_valparamhead *valparams,
+ yasm_valparamhead *objext_valparams, unsigned long line)
+{
+ yasm_objfmt_elf *objfmt_elf = (yasm_objfmt_elf *)object->objfmt;
+ yasm_valparam *vp = yasm_vps_first(valparams);
+ const char *symname = yasm_vp_id(vp);
+ /* Get symbol elf data */
+ yasm_symrec *sym = yasm_symtab_use(object->symtab, symname, line);
+ elf_symtab_entry *entry = yasm_symrec_get_data(sym, &elf_symrec_data);
+ /*@only@*/ /*@null@*/ yasm_expr *size;
+
+ /* Create entry if necessary */
+ if (!entry) {
+ entry = elf_symtab_entry_create(
+ elf_strtab_append_str(objfmt_elf->strtab, symname), sym);
+ yasm_symrec_add_data(sym, &elf_symrec_data, entry);
+ }
+
+ /* Pull new size from param */
+ vp = yasm_vps_next(vp);
+ if (vp && !vp->val && (size = yasm_vp_expr(vp, object->symtab, line)))
+ elf_sym_set_size(entry, size);
+ else
+ yasm_error_set(YASM_ERROR_SYNTAX, N_("no size specified"));
+}
+
+static void
+dir_weak(yasm_object *object, yasm_valparamhead *valparams,
+ yasm_valparamhead *objext_valparams, unsigned long line)
+{
+ yasm_objfmt_elf *objfmt_elf = (yasm_objfmt_elf *)object->objfmt;
+ yasm_valparam *vp = yasm_vps_first(valparams);
+ const char *symname = yasm_vp_id(vp);
+ yasm_symrec *sym = yasm_symtab_declare(object->symtab, symname,
+ YASM_SYM_GLOBAL, line);
+ elf_objfmt_symtab_append(objfmt_elf, sym, SHN_UNDEF, STB_WEAK, 0,
+ STV_DEFAULT, NULL, NULL, object);
+}
+
+static void
+dir_ident(yasm_object *object, yasm_valparamhead *valparams,
+ yasm_valparamhead *objext_valparams, unsigned long line)
+{
+ yasm_valparamhead sect_vps;
+ yasm_datavalhead dvs;
+ yasm_section *comment;
+ yasm_valparam *vp;
+ yasm_valparam *vp2;
+
+ /* Accept, but do nothing with empty ident */
+ if (!valparams)
+ return;
+ vp = yasm_vps_first(valparams);
+ if (!vp)
+ return;
+
+ /* Put ident data into .comment section */
+ yasm_vps_initialize(&sect_vps);
+ vp2 = yasm_vp_create_string(NULL, yasm__xstrdup(".comment"));
+ yasm_vps_append(&sect_vps, vp2);
+ comment = elf_objfmt_section_switch(object, &sect_vps, NULL, line);
+ yasm_vps_delete(&sect_vps);
+
+ /* To match GAS output, if the comment section is empty, put an
+ * initial 0 byte in the section.
+ */
+ if (yasm_section_bcs_first(comment) == yasm_section_bcs_last(comment)) {
+ yasm_dvs_initialize(&dvs);
+ yasm_dvs_append(&dvs, yasm_dv_create_expr(
+ yasm_expr_create_ident(
+ yasm_expr_int(yasm_intnum_create_uint(0)), line)));
+ yasm_section_bcs_append(comment,
+ yasm_bc_create_data(&dvs, 1, 0, object->arch, line));
+ }
+
+ yasm_dvs_initialize(&dvs);
+ do {
+ const char *s = yasm_vp_string(vp);
+ if (!s) {
+ yasm_error_set(YASM_ERROR_VALUE,
+ N_(".comment requires string parameters"));
+ yasm_dvs_delete(&dvs);
+ return;
+ }
+ yasm_dvs_append(&dvs,
+ yasm_dv_create_string(yasm__xstrdup(s), strlen(s)));
+ } while ((vp = yasm_vps_next(vp)));
+
+ yasm_section_bcs_append(comment,
+ yasm_bc_create_data(&dvs, 1, 1, object->arch, line));
+}
+
+/* Define valid debug formats to use with this object format */
+static const char *elf_objfmt_dbgfmt_keywords[] = {
+ "null",
+ "stabs",
+ "dwarf2",
+ NULL
+};
+
+static const yasm_directive elf_objfmt_directives[] = {
+ { ".type", "gas", dir_type, YASM_DIR_ID_REQUIRED },
+ { ".size", "gas", dir_size, YASM_DIR_ID_REQUIRED },
+ { ".weak", "gas", dir_weak, YASM_DIR_ID_REQUIRED },
+ { ".ident", "gas", dir_ident, YASM_DIR_ANY },
+ { "type", "nasm", dir_type, YASM_DIR_ID_REQUIRED },
+ { "size", "nasm", dir_size, YASM_DIR_ID_REQUIRED },
+ { "weak", "nasm", dir_weak, YASM_DIR_ID_REQUIRED },
+ { "ident", "nasm", dir_ident, YASM_DIR_ANY },
+ { NULL, NULL, NULL, 0 }
+};
+
+static const char *elf_nasm_stdmac[] = {
+ "%imacro type 1+.nolist",
+ "[type %1]",
+ "%endmacro",
+ "%imacro size 1+.nolist",
+ "[size %1]",
+ "%endmacro",
+ "%imacro weak 1+.nolist",
+ "[weak %1]",
+ "%endmacro",
+ NULL
+};
+
+static const yasm_stdmac elf_objfmt_stdmacs[] = {
+ { "nasm", "nasm", elf_nasm_stdmac },
+ { NULL, NULL, NULL }
+};
+
+/* Define objfmt structure -- see objfmt.h for details */
+yasm_objfmt_module yasm_elf_LTX_objfmt = {
+ "ELF",
+ "elf",
+ "o",
+ 32,
+ 0,
+ elf_objfmt_dbgfmt_keywords,
+ "null",
+ elf_objfmt_directives,
+ elf_objfmt_stdmacs,
+ elf_objfmt_create,
+ elf_objfmt_output,
+ elf_objfmt_destroy,
+ elf_objfmt_add_default_section,
+ elf_objfmt_init_new_section,
+ elf_objfmt_section_switch,
+ elf_objfmt_get_special_sym
+};
+
+yasm_objfmt_module yasm_elf32_LTX_objfmt = {
+ "ELF (32-bit)",
+ "elf32",
+ "o",
+ 32,
+ 0,
+ elf_objfmt_dbgfmt_keywords,
+ "null",
+ elf_objfmt_directives,
+ elf_objfmt_stdmacs,
+ elf32_objfmt_create,
+ elf_objfmt_output,
+ elf_objfmt_destroy,
+ elf_objfmt_add_default_section,
+ elf_objfmt_init_new_section,
+ elf_objfmt_section_switch,
+ elf_objfmt_get_special_sym
+};
+
+yasm_objfmt_module yasm_elf64_LTX_objfmt = {
+ "ELF (64-bit)",
+ "elf64",
+ "o",
+ 64,
+ 0,
+ elf_objfmt_dbgfmt_keywords,
+ "null",
+ elf_objfmt_directives,
+ elf_objfmt_stdmacs,
+ elf64_objfmt_create,
+ elf_objfmt_output,
+ elf_objfmt_destroy,
+ elf_objfmt_add_default_section,
+ elf_objfmt_init_new_section,
+ elf_objfmt_section_switch,
+ elf_objfmt_get_special_sym
+};
+
+yasm_objfmt_module yasm_elfx32_LTX_objfmt = {
+ "ELF (x32)",
+ "elfx32",
+ "o",
+ 64,
+ 0,
+ elf_objfmt_dbgfmt_keywords,
+ "null",
+ elf_objfmt_directives,
+ elf_objfmt_stdmacs,
+ elfx32_objfmt_create,
+ elf_objfmt_output,
+ elf_objfmt_destroy,
+ elf_objfmt_add_default_section,
+ elf_objfmt_init_new_section,
+ elf_objfmt_section_switch,
+ elf_objfmt_get_special_sym
+};
diff --git a/contrib/tools/yasm/modules/objfmts/elf/elf-x86-amd64.c b/contrib/tools/yasm/modules/objfmts/elf/elf-x86-amd64.c
index 3ba376af03..5384b768ed 100644
--- a/contrib/tools/yasm/modules/objfmts/elf/elf-x86-amd64.c
+++ b/contrib/tools/yasm/modules/objfmts/elf/elf-x86-amd64.c
@@ -1,256 +1,256 @@
-/*
- * ELF object format helpers - x86:amd64
- *
- * Copyright (C) 2004-2007 Michael Urman
- *
- * 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>
-
-#include <libyasm.h>
-#define YASM_OBJFMT_ELF_INTERNAL
-#include "elf.h"
-#include "elf-machine.h"
-
-static elf_machine_ssym elf_x86_amd64_ssyms[] = {
- {"pltoff", ELF_SSYM_SYM_RELATIVE, R_X86_64_PLTOFF64, 64},
- {"plt", ELF_SSYM_SYM_RELATIVE, R_X86_64_PLT32, 32},
- {"gotplt", ELF_SSYM_SYM_RELATIVE, R_X86_64_GOTPLT64, 64},
- {"gotoff", ELF_SSYM_SYM_RELATIVE, R_X86_64_GOTOFF64, 64},
- {"gotpcrel", ELF_SSYM_SYM_RELATIVE, R_X86_64_GOTPCREL, 32},
- {"tlsgd", ELF_SSYM_SYM_RELATIVE|ELF_SSYM_THREAD_LOCAL,
- R_X86_64_TLSGD, 32},
- {"tlsld", ELF_SSYM_SYM_RELATIVE|ELF_SSYM_THREAD_LOCAL,
- R_X86_64_TLSLD, 32},
- {"gottpoff", ELF_SSYM_SYM_RELATIVE|ELF_SSYM_THREAD_LOCAL,
- R_X86_64_GOTTPOFF, 32},
- {"tpoff", ELF_SSYM_SYM_RELATIVE|ELF_SSYM_THREAD_LOCAL,
- R_X86_64_TPOFF32, 32},
- {"dtpoff", ELF_SSYM_SYM_RELATIVE|ELF_SSYM_THREAD_LOCAL,
- R_X86_64_DTPOFF32, 32},
- {"got", ELF_SSYM_SYM_RELATIVE, R_X86_64_GOT32, 32},
- {"tlsdesc", ELF_SSYM_SYM_RELATIVE|ELF_SSYM_THREAD_LOCAL,
- R_X86_64_GOTPC32_TLSDESC, 32},
- {"tlscall", ELF_SSYM_SYM_RELATIVE|ELF_SSYM_THREAD_LOCAL,
- R_X86_64_TLSDESC_CALL, 32}
-};
-
-static int
-elf_x86_amd64_accepts_reloc(size_t val, yasm_symrec *wrt)
-{
- if (wrt) {
- const elf_machine_ssym *ssym = (elf_machine_ssym *)
- yasm_symrec_get_data(wrt, &elf_ssym_symrec_data);
- if (!ssym || val != ssym->size)
- return 0;
- return 1;
- }
- return (val&(val-1)) ? 0 : ((val & (8|16|32|64)) != 0);
-}
-
-static void
-elf_x86_amd64_write_symtab_entry(unsigned char *bufp,
- elf_symtab_entry *entry,
- yasm_intnum *value_intn,
- yasm_intnum *size_intn)
-{
- YASM_WRITE_32_L(bufp, entry->name ? entry->name->index : 0);
- YASM_WRITE_8(bufp, ELF64_ST_INFO(entry->bind, entry->type));
- YASM_WRITE_8(bufp, ELF64_ST_OTHER(entry->vis));
- if (entry->sect) {
- elf_secthead *shead =
- yasm_section_get_data(entry->sect, &elf_section_data);
- if (!shead)
- yasm_internal_error(N_("symbol references section without data"));
- YASM_WRITE_16_L(bufp, shead->index);
- } else {
- YASM_WRITE_16_L(bufp, entry->index);
- }
- YASM_WRITE_64I_L(bufp, value_intn);
- YASM_WRITE_64I_L(bufp, size_intn);
-}
-
-static void
-elf_x86_amd64_write_secthead(unsigned char *bufp, elf_secthead *shead)
-{
- YASM_WRITE_32_L(bufp, shead->name ? shead->name->index : 0);
- YASM_WRITE_32_L(bufp, shead->type);
- YASM_WRITE_64Z_L(bufp, shead->flags);
- YASM_WRITE_64Z_L(bufp, 0); /* vmem address */
- YASM_WRITE_64Z_L(bufp, shead->offset);
- YASM_WRITE_64I_L(bufp, shead->size);
-
- YASM_WRITE_32_L(bufp, shead->link);
- YASM_WRITE_32_L(bufp, shead->info);
-
- YASM_WRITE_64Z_L(bufp, shead->align);
- YASM_WRITE_64Z_L(bufp, shead->entsize);
-}
-
-static void
-elf_x86_amd64_write_secthead_rel(unsigned char *bufp,
- elf_secthead *shead,
- elf_section_index symtab_idx,
- elf_section_index sindex)
-{
- yasm_intnum *nreloc;
- yasm_intnum *relocsize;
-
- YASM_WRITE_32_L(bufp, shead->rel_name ? shead->rel_name->index : 0);
- YASM_WRITE_32_L(bufp, SHT_RELA);
- YASM_WRITE_64Z_L(bufp, 0);
- YASM_WRITE_64Z_L(bufp, 0);
- YASM_WRITE_64Z_L(bufp, shead->rel_offset);
-
- nreloc = yasm_intnum_create_uint(shead->nreloc);
- relocsize = yasm_intnum_create_uint(RELOC64A_SIZE);
- yasm_intnum_calc(relocsize, YASM_EXPR_MUL, nreloc);
- YASM_WRITE_64I_L(bufp, relocsize); /* size */
- yasm_intnum_destroy(nreloc);
- yasm_intnum_destroy(relocsize);
-
- YASM_WRITE_32_L(bufp, symtab_idx); /* link: symtab index */
- YASM_WRITE_32_L(bufp, shead->index); /* info: relocated's index */
- YASM_WRITE_64Z_L(bufp, RELOC64_ALIGN); /* align */
- YASM_WRITE_64Z_L(bufp, RELOC64A_SIZE); /* entity size */
-}
-
-static void
-elf_x86_amd64_handle_reloc_addend(yasm_intnum *intn,
- elf_reloc_entry *reloc,
- unsigned long offset)
-{
- /* .rela: copy value out as addend, replace original with 0 */
- reloc->addend = yasm_intnum_copy(intn);
- yasm_intnum_zero(intn);
-}
-
-static unsigned int
-elf_x86_amd64_map_reloc_info_to_type(elf_reloc_entry *reloc)
-{
- if (reloc->wrt) {
- const elf_machine_ssym *ssym = (elf_machine_ssym *)
- yasm_symrec_get_data(reloc->wrt, &elf_ssym_symrec_data);
- if (!ssym || reloc->valsize != ssym->size)
- yasm_internal_error(N_("Unsupported WRT"));
-
- /* Force TLS type; this is required by the linker. */
- if (ssym->sym_rel & ELF_SSYM_THREAD_LOCAL) {
- elf_symtab_entry *esym;
-
- esym = yasm_symrec_get_data(reloc->reloc.sym, &elf_symrec_data);
- if (esym)
- esym->type = STT_TLS;
- }
- /* Map PC-relative GOT to appropriate relocation */
- if (reloc->rtype_rel && ssym->reloc == R_X86_64_GOT32)
- return (unsigned char) R_X86_64_GOTPCREL;
- return (unsigned char) ssym->reloc;
- } else if (reloc->is_GOT_sym && reloc->valsize == 32) {
- return (unsigned char) R_X86_64_GOTPC32;
- } else if (reloc->is_GOT_sym && reloc->valsize == 64) {
- return (unsigned char) R_X86_64_GOTPC64;
- } else if (reloc->rtype_rel) {
- switch (reloc->valsize) {
- case 8: return (unsigned char) R_X86_64_PC8;
- case 16: return (unsigned char) R_X86_64_PC16;
- case 32: return (unsigned char) R_X86_64_PC32;
- case 64: return (unsigned char) R_X86_64_PC64;
- default: yasm_internal_error(N_("Unsupported relocation size"));
- }
- } else {
- switch (reloc->valsize) {
- case 8: return (unsigned char) R_X86_64_8;
- case 16: return (unsigned char) R_X86_64_16;
- case 32: return (unsigned char) R_X86_64_32;
- case 64: return (unsigned char) R_X86_64_64;
- default: yasm_internal_error(N_("Unsupported relocation size"));
- }
- }
- return 0;
-}
-
-static void
-elf_x86_amd64_write_reloc(unsigned char *bufp, elf_reloc_entry *reloc,
- unsigned int r_type, unsigned int r_sym)
-{
- YASM_WRITE_64I_L(bufp, reloc->reloc.addr);
- /*YASM_WRITE_64_L(bufp, ELF64_R_INFO(r_sym, r_type));*/
- YASM_WRITE_64C_L(bufp, r_sym, r_type);
- if (reloc->addend)
- YASM_WRITE_64I_L(bufp, reloc->addend);
- else {
- YASM_WRITE_32_L(bufp, 0);
- YASM_WRITE_32_L(bufp, 0);
- }
-}
-
-static void
-elf_x86_amd64_write_proghead(unsigned char **bufpp,
- elf_offset secthead_addr,
- unsigned long secthead_count,
- elf_section_index shstrtab_index)
-{
- unsigned char *bufp = *bufpp;
- unsigned char *buf = bufp-4;
- YASM_WRITE_8(bufp, ELFCLASS64); /* elf class */
- YASM_WRITE_8(bufp, ELFDATA2LSB); /* data encoding :: MSB? */
- YASM_WRITE_8(bufp, EV_CURRENT); /* elf version */
- YASM_WRITE_8(bufp, ELFOSABI_SYSV); /* os/abi */
- YASM_WRITE_8(bufp, 0); /* SYSV v3 ABI=0 */
- while (bufp-buf < EI_NIDENT) /* e_ident padding */
- YASM_WRITE_8(bufp, 0);
-
- YASM_WRITE_16_L(bufp, ET_REL); /* e_type - object file */
- YASM_WRITE_16_L(bufp, EM_X86_64); /* e_machine - or others */
- YASM_WRITE_32_L(bufp, EV_CURRENT); /* elf version */
- YASM_WRITE_64Z_L(bufp, 0); /* e_entry */
- YASM_WRITE_64Z_L(bufp, 0); /* e_phoff */
- YASM_WRITE_64Z_L(bufp, secthead_addr); /* e_shoff secthead off */
-
- YASM_WRITE_32_L(bufp, 0); /* e_flags */
- YASM_WRITE_16_L(bufp, EHDR64_SIZE); /* e_ehsize */
- YASM_WRITE_16_L(bufp, 0); /* e_phentsize */
- YASM_WRITE_16_L(bufp, 0); /* e_phnum */
- YASM_WRITE_16_L(bufp, SHDR64_SIZE); /* e_shentsize */
- YASM_WRITE_16_L(bufp, secthead_count); /* e_shnum */
- YASM_WRITE_16_L(bufp, shstrtab_index); /* e_shstrndx */
- *bufpp = bufp;
-}
-
-const elf_machine_handler
-elf_machine_handler_x86_amd64 = {
- "x86", "amd64", ".rela",
- SYMTAB64_SIZE, SYMTAB64_ALIGN, RELOC64A_SIZE, SHDR64_SIZE, EHDR64_SIZE,
- elf_x86_amd64_accepts_reloc,
- elf_x86_amd64_write_symtab_entry,
- elf_x86_amd64_write_secthead,
- elf_x86_amd64_write_secthead_rel,
- elf_x86_amd64_handle_reloc_addend,
- elf_x86_amd64_map_reloc_info_to_type,
- elf_x86_amd64_write_reloc,
- elf_x86_amd64_write_proghead,
- elf_x86_amd64_ssyms,
- sizeof(elf_x86_amd64_ssyms)/sizeof(elf_x86_amd64_ssyms[0]),
- 64
-};
+/*
+ * ELF object format helpers - x86:amd64
+ *
+ * Copyright (C) 2004-2007 Michael Urman
+ *
+ * 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>
+
+#include <libyasm.h>
+#define YASM_OBJFMT_ELF_INTERNAL
+#include "elf.h"
+#include "elf-machine.h"
+
+static elf_machine_ssym elf_x86_amd64_ssyms[] = {
+ {"pltoff", ELF_SSYM_SYM_RELATIVE, R_X86_64_PLTOFF64, 64},
+ {"plt", ELF_SSYM_SYM_RELATIVE, R_X86_64_PLT32, 32},
+ {"gotplt", ELF_SSYM_SYM_RELATIVE, R_X86_64_GOTPLT64, 64},
+ {"gotoff", ELF_SSYM_SYM_RELATIVE, R_X86_64_GOTOFF64, 64},
+ {"gotpcrel", ELF_SSYM_SYM_RELATIVE, R_X86_64_GOTPCREL, 32},
+ {"tlsgd", ELF_SSYM_SYM_RELATIVE|ELF_SSYM_THREAD_LOCAL,
+ R_X86_64_TLSGD, 32},
+ {"tlsld", ELF_SSYM_SYM_RELATIVE|ELF_SSYM_THREAD_LOCAL,
+ R_X86_64_TLSLD, 32},
+ {"gottpoff", ELF_SSYM_SYM_RELATIVE|ELF_SSYM_THREAD_LOCAL,
+ R_X86_64_GOTTPOFF, 32},
+ {"tpoff", ELF_SSYM_SYM_RELATIVE|ELF_SSYM_THREAD_LOCAL,
+ R_X86_64_TPOFF32, 32},
+ {"dtpoff", ELF_SSYM_SYM_RELATIVE|ELF_SSYM_THREAD_LOCAL,
+ R_X86_64_DTPOFF32, 32},
+ {"got", ELF_SSYM_SYM_RELATIVE, R_X86_64_GOT32, 32},
+ {"tlsdesc", ELF_SSYM_SYM_RELATIVE|ELF_SSYM_THREAD_LOCAL,
+ R_X86_64_GOTPC32_TLSDESC, 32},
+ {"tlscall", ELF_SSYM_SYM_RELATIVE|ELF_SSYM_THREAD_LOCAL,
+ R_X86_64_TLSDESC_CALL, 32}
+};
+
+static int
+elf_x86_amd64_accepts_reloc(size_t val, yasm_symrec *wrt)
+{
+ if (wrt) {
+ const elf_machine_ssym *ssym = (elf_machine_ssym *)
+ yasm_symrec_get_data(wrt, &elf_ssym_symrec_data);
+ if (!ssym || val != ssym->size)
+ return 0;
+ return 1;
+ }
+ return (val&(val-1)) ? 0 : ((val & (8|16|32|64)) != 0);
+}
+
+static void
+elf_x86_amd64_write_symtab_entry(unsigned char *bufp,
+ elf_symtab_entry *entry,
+ yasm_intnum *value_intn,
+ yasm_intnum *size_intn)
+{
+ YASM_WRITE_32_L(bufp, entry->name ? entry->name->index : 0);
+ YASM_WRITE_8(bufp, ELF64_ST_INFO(entry->bind, entry->type));
+ YASM_WRITE_8(bufp, ELF64_ST_OTHER(entry->vis));
+ if (entry->sect) {
+ elf_secthead *shead =
+ yasm_section_get_data(entry->sect, &elf_section_data);
+ if (!shead)
+ yasm_internal_error(N_("symbol references section without data"));
+ YASM_WRITE_16_L(bufp, shead->index);
+ } else {
+ YASM_WRITE_16_L(bufp, entry->index);
+ }
+ YASM_WRITE_64I_L(bufp, value_intn);
+ YASM_WRITE_64I_L(bufp, size_intn);
+}
+
+static void
+elf_x86_amd64_write_secthead(unsigned char *bufp, elf_secthead *shead)
+{
+ YASM_WRITE_32_L(bufp, shead->name ? shead->name->index : 0);
+ YASM_WRITE_32_L(bufp, shead->type);
+ YASM_WRITE_64Z_L(bufp, shead->flags);
+ YASM_WRITE_64Z_L(bufp, 0); /* vmem address */
+ YASM_WRITE_64Z_L(bufp, shead->offset);
+ YASM_WRITE_64I_L(bufp, shead->size);
+
+ YASM_WRITE_32_L(bufp, shead->link);
+ YASM_WRITE_32_L(bufp, shead->info);
+
+ YASM_WRITE_64Z_L(bufp, shead->align);
+ YASM_WRITE_64Z_L(bufp, shead->entsize);
+}
+
+static void
+elf_x86_amd64_write_secthead_rel(unsigned char *bufp,
+ elf_secthead *shead,
+ elf_section_index symtab_idx,
+ elf_section_index sindex)
+{
+ yasm_intnum *nreloc;
+ yasm_intnum *relocsize;
+
+ YASM_WRITE_32_L(bufp, shead->rel_name ? shead->rel_name->index : 0);
+ YASM_WRITE_32_L(bufp, SHT_RELA);
+ YASM_WRITE_64Z_L(bufp, 0);
+ YASM_WRITE_64Z_L(bufp, 0);
+ YASM_WRITE_64Z_L(bufp, shead->rel_offset);
+
+ nreloc = yasm_intnum_create_uint(shead->nreloc);
+ relocsize = yasm_intnum_create_uint(RELOC64A_SIZE);
+ yasm_intnum_calc(relocsize, YASM_EXPR_MUL, nreloc);
+ YASM_WRITE_64I_L(bufp, relocsize); /* size */
+ yasm_intnum_destroy(nreloc);
+ yasm_intnum_destroy(relocsize);
+
+ YASM_WRITE_32_L(bufp, symtab_idx); /* link: symtab index */
+ YASM_WRITE_32_L(bufp, shead->index); /* info: relocated's index */
+ YASM_WRITE_64Z_L(bufp, RELOC64_ALIGN); /* align */
+ YASM_WRITE_64Z_L(bufp, RELOC64A_SIZE); /* entity size */
+}
+
+static void
+elf_x86_amd64_handle_reloc_addend(yasm_intnum *intn,
+ elf_reloc_entry *reloc,
+ unsigned long offset)
+{
+ /* .rela: copy value out as addend, replace original with 0 */
+ reloc->addend = yasm_intnum_copy(intn);
+ yasm_intnum_zero(intn);
+}
+
+static unsigned int
+elf_x86_amd64_map_reloc_info_to_type(elf_reloc_entry *reloc)
+{
+ if (reloc->wrt) {
+ const elf_machine_ssym *ssym = (elf_machine_ssym *)
+ yasm_symrec_get_data(reloc->wrt, &elf_ssym_symrec_data);
+ if (!ssym || reloc->valsize != ssym->size)
+ yasm_internal_error(N_("Unsupported WRT"));
+
+ /* Force TLS type; this is required by the linker. */
+ if (ssym->sym_rel & ELF_SSYM_THREAD_LOCAL) {
+ elf_symtab_entry *esym;
+
+ esym = yasm_symrec_get_data(reloc->reloc.sym, &elf_symrec_data);
+ if (esym)
+ esym->type = STT_TLS;
+ }
+ /* Map PC-relative GOT to appropriate relocation */
+ if (reloc->rtype_rel && ssym->reloc == R_X86_64_GOT32)
+ return (unsigned char) R_X86_64_GOTPCREL;
+ return (unsigned char) ssym->reloc;
+ } else if (reloc->is_GOT_sym && reloc->valsize == 32) {
+ return (unsigned char) R_X86_64_GOTPC32;
+ } else if (reloc->is_GOT_sym && reloc->valsize == 64) {
+ return (unsigned char) R_X86_64_GOTPC64;
+ } else if (reloc->rtype_rel) {
+ switch (reloc->valsize) {
+ case 8: return (unsigned char) R_X86_64_PC8;
+ case 16: return (unsigned char) R_X86_64_PC16;
+ case 32: return (unsigned char) R_X86_64_PC32;
+ case 64: return (unsigned char) R_X86_64_PC64;
+ default: yasm_internal_error(N_("Unsupported relocation size"));
+ }
+ } else {
+ switch (reloc->valsize) {
+ case 8: return (unsigned char) R_X86_64_8;
+ case 16: return (unsigned char) R_X86_64_16;
+ case 32: return (unsigned char) R_X86_64_32;
+ case 64: return (unsigned char) R_X86_64_64;
+ default: yasm_internal_error(N_("Unsupported relocation size"));
+ }
+ }
+ return 0;
+}
+
+static void
+elf_x86_amd64_write_reloc(unsigned char *bufp, elf_reloc_entry *reloc,
+ unsigned int r_type, unsigned int r_sym)
+{
+ YASM_WRITE_64I_L(bufp, reloc->reloc.addr);
+ /*YASM_WRITE_64_L(bufp, ELF64_R_INFO(r_sym, r_type));*/
+ YASM_WRITE_64C_L(bufp, r_sym, r_type);
+ if (reloc->addend)
+ YASM_WRITE_64I_L(bufp, reloc->addend);
+ else {
+ YASM_WRITE_32_L(bufp, 0);
+ YASM_WRITE_32_L(bufp, 0);
+ }
+}
+
+static void
+elf_x86_amd64_write_proghead(unsigned char **bufpp,
+ elf_offset secthead_addr,
+ unsigned long secthead_count,
+ elf_section_index shstrtab_index)
+{
+ unsigned char *bufp = *bufpp;
+ unsigned char *buf = bufp-4;
+ YASM_WRITE_8(bufp, ELFCLASS64); /* elf class */
+ YASM_WRITE_8(bufp, ELFDATA2LSB); /* data encoding :: MSB? */
+ YASM_WRITE_8(bufp, EV_CURRENT); /* elf version */
+ YASM_WRITE_8(bufp, ELFOSABI_SYSV); /* os/abi */
+ YASM_WRITE_8(bufp, 0); /* SYSV v3 ABI=0 */
+ while (bufp-buf < EI_NIDENT) /* e_ident padding */
+ YASM_WRITE_8(bufp, 0);
+
+ YASM_WRITE_16_L(bufp, ET_REL); /* e_type - object file */
+ YASM_WRITE_16_L(bufp, EM_X86_64); /* e_machine - or others */
+ YASM_WRITE_32_L(bufp, EV_CURRENT); /* elf version */
+ YASM_WRITE_64Z_L(bufp, 0); /* e_entry */
+ YASM_WRITE_64Z_L(bufp, 0); /* e_phoff */
+ YASM_WRITE_64Z_L(bufp, secthead_addr); /* e_shoff secthead off */
+
+ YASM_WRITE_32_L(bufp, 0); /* e_flags */
+ YASM_WRITE_16_L(bufp, EHDR64_SIZE); /* e_ehsize */
+ YASM_WRITE_16_L(bufp, 0); /* e_phentsize */
+ YASM_WRITE_16_L(bufp, 0); /* e_phnum */
+ YASM_WRITE_16_L(bufp, SHDR64_SIZE); /* e_shentsize */
+ YASM_WRITE_16_L(bufp, secthead_count); /* e_shnum */
+ YASM_WRITE_16_L(bufp, shstrtab_index); /* e_shstrndx */
+ *bufpp = bufp;
+}
+
+const elf_machine_handler
+elf_machine_handler_x86_amd64 = {
+ "x86", "amd64", ".rela",
+ SYMTAB64_SIZE, SYMTAB64_ALIGN, RELOC64A_SIZE, SHDR64_SIZE, EHDR64_SIZE,
+ elf_x86_amd64_accepts_reloc,
+ elf_x86_amd64_write_symtab_entry,
+ elf_x86_amd64_write_secthead,
+ elf_x86_amd64_write_secthead_rel,
+ elf_x86_amd64_handle_reloc_addend,
+ elf_x86_amd64_map_reloc_info_to_type,
+ elf_x86_amd64_write_reloc,
+ elf_x86_amd64_write_proghead,
+ elf_x86_amd64_ssyms,
+ sizeof(elf_x86_amd64_ssyms)/sizeof(elf_x86_amd64_ssyms[0]),
+ 64
+};
diff --git a/contrib/tools/yasm/modules/objfmts/elf/elf-x86-x32.c b/contrib/tools/yasm/modules/objfmts/elf/elf-x86-x32.c
index 40a25a12a7..aad2d10dac 100644
--- a/contrib/tools/yasm/modules/objfmts/elf/elf-x86-x32.c
+++ b/contrib/tools/yasm/modules/objfmts/elf/elf-x86-x32.c
@@ -1,251 +1,251 @@
-/*
- * ELF object format helpers - x86:x32
- *
- * Copyright (C) 2012 Michael Urman and H.J. Lu
- *
- * 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>
-
-#include <libyasm.h>
-#define YASM_OBJFMT_ELF_INTERNAL
-#include "elf.h"
-#include "elf-machine.h"
-
-static elf_machine_ssym elf_x86_x32_ssyms[] = {
- {"plt", ELF_SSYM_SYM_RELATIVE, R_X86_64_PLT32, 32},
- {"gotpcrel", ELF_SSYM_SYM_RELATIVE, R_X86_64_GOTPCREL, 32},
- {"tlsgd", ELF_SSYM_SYM_RELATIVE|ELF_SSYM_THREAD_LOCAL,
- R_X86_64_TLSGD, 32},
- {"tlsld", ELF_SSYM_SYM_RELATIVE|ELF_SSYM_THREAD_LOCAL,
- R_X86_64_TLSLD, 32},
- {"gottpoff", ELF_SSYM_SYM_RELATIVE|ELF_SSYM_THREAD_LOCAL,
- R_X86_64_GOTTPOFF, 32},
- {"tpoff", ELF_SSYM_SYM_RELATIVE|ELF_SSYM_THREAD_LOCAL,
- R_X86_64_TPOFF32, 32},
- {"dtpoff", ELF_SSYM_SYM_RELATIVE|ELF_SSYM_THREAD_LOCAL,
- R_X86_64_DTPOFF32, 32},
- {"got", ELF_SSYM_SYM_RELATIVE, R_X86_64_GOT32, 32},
- {"tlsdesc", ELF_SSYM_SYM_RELATIVE|ELF_SSYM_THREAD_LOCAL,
- R_X86_64_GOTPC32_TLSDESC, 32},
- {"tlscall", ELF_SSYM_SYM_RELATIVE|ELF_SSYM_THREAD_LOCAL,
- R_X86_64_TLSDESC_CALL, 32}
-};
-
-static int
-elf_x86_x32_accepts_reloc(size_t val, yasm_symrec *wrt)
-{
- if (wrt) {
- const elf_machine_ssym *ssym = (elf_machine_ssym *)
- yasm_symrec_get_data(wrt, &elf_ssym_symrec_data);
- if (!ssym || val != ssym->size)
- return 0;
- return 1;
- }
- return (val&(val-1)) ? 0 : ((val & (8|16|32)) != 0);
-}
-
-static void
-elf_x86_x32_write_symtab_entry(unsigned char *bufp,
- elf_symtab_entry *entry,
- yasm_intnum *value_intn,
- yasm_intnum *size_intn)
-{
- YASM_WRITE_32_L(bufp, entry->name ? entry->name->index : 0);
- YASM_WRITE_32I_L(bufp, value_intn);
- YASM_WRITE_32I_L(bufp, size_intn);
-
- YASM_WRITE_8(bufp, ELF32_ST_INFO(entry->bind, entry->type));
- YASM_WRITE_8(bufp, ELF32_ST_OTHER(entry->vis));
- if (entry->sect) {
- elf_secthead *shead =
- yasm_section_get_data(entry->sect, &elf_section_data);
- if (!shead)
- yasm_internal_error(N_("symbol references section without data"));
- YASM_WRITE_16_L(bufp, shead->index);
- } else {
- YASM_WRITE_16_L(bufp, entry->index);
- }
-}
-
-static void
-elf_x86_x32_write_secthead(unsigned char *bufp, elf_secthead *shead)
-{
- YASM_WRITE_32_L(bufp, shead->name ? shead->name->index : 0);
- YASM_WRITE_32_L(bufp, shead->type);
- YASM_WRITE_32_L(bufp, shead->flags);
- YASM_WRITE_32_L(bufp, 0); /* vmem address */
- YASM_WRITE_32_L(bufp, shead->offset);
- YASM_WRITE_32I_L(bufp, shead->size);
-
- YASM_WRITE_32_L(bufp, shead->link);
- YASM_WRITE_32_L(bufp, shead->info);
-
- YASM_WRITE_32_L(bufp, shead->align);
- YASM_WRITE_32_L(bufp, shead->entsize);
-}
-
-static void
-elf_x86_x32_write_secthead_rel(unsigned char *bufp,
- elf_secthead *shead,
- elf_section_index symtab_idx,
- elf_section_index sindex)
-{
- yasm_intnum *nreloc;
- yasm_intnum *relocsize;
-
- YASM_WRITE_32_L(bufp, shead->rel_name ? shead->rel_name->index : 0);
- YASM_WRITE_32_L(bufp, SHT_RELA);
- YASM_WRITE_32_L(bufp, 0);
- YASM_WRITE_32_L(bufp, 0);
- YASM_WRITE_32_L(bufp, shead->rel_offset);
-
- nreloc = yasm_intnum_create_uint(shead->nreloc);
- relocsize = yasm_intnum_create_uint(RELOC32A_SIZE);
- yasm_intnum_calc(relocsize, YASM_EXPR_MUL, nreloc);
- YASM_WRITE_32I_L(bufp, relocsize); /* size */
- yasm_intnum_destroy(nreloc);
- yasm_intnum_destroy(relocsize);
-
- YASM_WRITE_32_L(bufp, symtab_idx); /* link: symtab index */
- YASM_WRITE_32_L(bufp, shead->index); /* info: relocated's index */
- YASM_WRITE_32_L(bufp, RELOC32_ALIGN); /* align */
- YASM_WRITE_32_L(bufp, RELOC32A_SIZE); /* entity size */
-}
-
-static void
-elf_x86_x32_handle_reloc_addend(yasm_intnum *intn,
- elf_reloc_entry *reloc,
- unsigned long offset)
-{
- /* .rela: copy value out as addend, replace original with 0 */
- reloc->addend = yasm_intnum_copy(intn);
- yasm_intnum_zero(intn);
-}
-
-static unsigned int
-elf_x86_x32_map_reloc_info_to_type(elf_reloc_entry *reloc)
-{
- if (reloc->wrt) {
- const elf_machine_ssym *ssym = (elf_machine_ssym *)
- yasm_symrec_get_data(reloc->wrt, &elf_ssym_symrec_data);
- if (!ssym || reloc->valsize != ssym->size)
- yasm_internal_error(N_("Unsupported WRT"));
-
- /* Force TLS type; this is required by the linker. */
- if (ssym->sym_rel & ELF_SSYM_THREAD_LOCAL) {
- elf_symtab_entry *esym;
-
- esym = yasm_symrec_get_data(reloc->reloc.sym, &elf_symrec_data);
- if (esym)
- esym->type = STT_TLS;
- }
- /* Map PC-relative GOT to appropriate relocation */
- if (reloc->rtype_rel && ssym->reloc == R_X86_64_GOT32)
- return (unsigned char) R_X86_64_GOTPCREL;
- return (unsigned char) ssym->reloc;
- } else if (reloc->is_GOT_sym && reloc->valsize == 32) {
- return (unsigned char) R_X86_64_GOTPC32;
- } else if (reloc->is_GOT_sym && reloc->valsize == 64) {
- yasm_internal_error(N_("Unsupported relocation size"));
- } else if (reloc->rtype_rel) {
- switch (reloc->valsize) {
- case 8: return (unsigned char) R_X86_64_PC8;
- case 16: return (unsigned char) R_X86_64_PC16;
- case 32: return (unsigned char) R_X86_64_PC32;
- default: yasm_internal_error(N_("Unsupported relocation size"));
- }
- } else {
- switch (reloc->valsize) {
- case 8: return (unsigned char) R_X86_64_8;
- case 16: return (unsigned char) R_X86_64_16;
- case 32: return (unsigned char) R_X86_64_32;
- case 64: return (unsigned char) R_X86_64_64;
- default: yasm_internal_error(N_("Unsupported relocation size"));
- }
- }
- return 0;
-}
-
-static void
-elf_x86_x32_write_reloc(unsigned char *bufp, elf_reloc_entry *reloc,
- unsigned int r_type, unsigned int r_sym)
-{
- YASM_WRITE_32I_L(bufp, reloc->reloc.addr);
- YASM_WRITE_32_L(bufp, ELF32_R_INFO((unsigned long)r_sym, (unsigned char)r_type));
- if (reloc->addend)
- YASM_WRITE_32I_L(bufp, reloc->addend);
- else {
- YASM_WRITE_32_L(bufp, 0);
- }
-}
-
-static void
-elf_x86_x32_write_proghead(unsigned char **bufpp,
- elf_offset secthead_addr,
- unsigned long secthead_count,
- elf_section_index shstrtab_index)
-{
- unsigned char *bufp = *bufpp;
- unsigned char *buf = bufp-4;
- YASM_WRITE_8(bufp, ELFCLASS32); /* elf class */
- YASM_WRITE_8(bufp, ELFDATA2LSB); /* data encoding :: MSB? */
- YASM_WRITE_8(bufp, EV_CURRENT); /* elf version */
- YASM_WRITE_8(bufp, ELFOSABI_SYSV); /* os/abi */
- YASM_WRITE_8(bufp, 0); /* SYSV v3 ABI=0 */
- while (bufp-buf < EI_NIDENT) /* e_ident padding */
- YASM_WRITE_8(bufp, 0);
-
- YASM_WRITE_16_L(bufp, ET_REL); /* e_type - object file */
- YASM_WRITE_16_L(bufp, EM_X86_64); /* e_machine - or others */
- YASM_WRITE_32_L(bufp, EV_CURRENT); /* elf version */
- YASM_WRITE_32_L(bufp, 0); /* e_entry */
- YASM_WRITE_32_L(bufp, 0); /* e_phoff */
- YASM_WRITE_32_L(bufp, secthead_addr); /* e_shoff secthead off */
-
- YASM_WRITE_32_L(bufp, 0); /* e_flags */
- YASM_WRITE_16_L(bufp, EHDR32_SIZE); /* e_ehsize */
- YASM_WRITE_16_L(bufp, 0); /* e_phentsize */
- YASM_WRITE_16_L(bufp, 0); /* e_phnum */
- YASM_WRITE_16_L(bufp, SHDR32_SIZE); /* e_shentsize */
- YASM_WRITE_16_L(bufp, secthead_count); /* e_shnum */
- YASM_WRITE_16_L(bufp, shstrtab_index); /* e_shstrndx */
- *bufpp = bufp;
-}
-
-const elf_machine_handler
-elf_machine_handler_x86_x32 = {
- "x86", "x32", ".rela",
- SYMTAB32_SIZE, SYMTAB32_ALIGN, RELOC32A_SIZE, SHDR32_SIZE, EHDR32_SIZE,
- elf_x86_x32_accepts_reloc,
- elf_x86_x32_write_symtab_entry,
- elf_x86_x32_write_secthead,
- elf_x86_x32_write_secthead_rel,
- elf_x86_x32_handle_reloc_addend,
- elf_x86_x32_map_reloc_info_to_type,
- elf_x86_x32_write_reloc,
- elf_x86_x32_write_proghead,
- elf_x86_x32_ssyms,
- sizeof(elf_x86_x32_ssyms)/sizeof(elf_x86_x32_ssyms[0]),
- 32
-};
+/*
+ * ELF object format helpers - x86:x32
+ *
+ * Copyright (C) 2012 Michael Urman and H.J. Lu
+ *
+ * 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>
+
+#include <libyasm.h>
+#define YASM_OBJFMT_ELF_INTERNAL
+#include "elf.h"
+#include "elf-machine.h"
+
+static elf_machine_ssym elf_x86_x32_ssyms[] = {
+ {"plt", ELF_SSYM_SYM_RELATIVE, R_X86_64_PLT32, 32},
+ {"gotpcrel", ELF_SSYM_SYM_RELATIVE, R_X86_64_GOTPCREL, 32},
+ {"tlsgd", ELF_SSYM_SYM_RELATIVE|ELF_SSYM_THREAD_LOCAL,
+ R_X86_64_TLSGD, 32},
+ {"tlsld", ELF_SSYM_SYM_RELATIVE|ELF_SSYM_THREAD_LOCAL,
+ R_X86_64_TLSLD, 32},
+ {"gottpoff", ELF_SSYM_SYM_RELATIVE|ELF_SSYM_THREAD_LOCAL,
+ R_X86_64_GOTTPOFF, 32},
+ {"tpoff", ELF_SSYM_SYM_RELATIVE|ELF_SSYM_THREAD_LOCAL,
+ R_X86_64_TPOFF32, 32},
+ {"dtpoff", ELF_SSYM_SYM_RELATIVE|ELF_SSYM_THREAD_LOCAL,
+ R_X86_64_DTPOFF32, 32},
+ {"got", ELF_SSYM_SYM_RELATIVE, R_X86_64_GOT32, 32},
+ {"tlsdesc", ELF_SSYM_SYM_RELATIVE|ELF_SSYM_THREAD_LOCAL,
+ R_X86_64_GOTPC32_TLSDESC, 32},
+ {"tlscall", ELF_SSYM_SYM_RELATIVE|ELF_SSYM_THREAD_LOCAL,
+ R_X86_64_TLSDESC_CALL, 32}
+};
+
+static int
+elf_x86_x32_accepts_reloc(size_t val, yasm_symrec *wrt)
+{
+ if (wrt) {
+ const elf_machine_ssym *ssym = (elf_machine_ssym *)
+ yasm_symrec_get_data(wrt, &elf_ssym_symrec_data);
+ if (!ssym || val != ssym->size)
+ return 0;
+ return 1;
+ }
+ return (val&(val-1)) ? 0 : ((val & (8|16|32)) != 0);
+}
+
+static void
+elf_x86_x32_write_symtab_entry(unsigned char *bufp,
+ elf_symtab_entry *entry,
+ yasm_intnum *value_intn,
+ yasm_intnum *size_intn)
+{
+ YASM_WRITE_32_L(bufp, entry->name ? entry->name->index : 0);
+ YASM_WRITE_32I_L(bufp, value_intn);
+ YASM_WRITE_32I_L(bufp, size_intn);
+
+ YASM_WRITE_8(bufp, ELF32_ST_INFO(entry->bind, entry->type));
+ YASM_WRITE_8(bufp, ELF32_ST_OTHER(entry->vis));
+ if (entry->sect) {
+ elf_secthead *shead =
+ yasm_section_get_data(entry->sect, &elf_section_data);
+ if (!shead)
+ yasm_internal_error(N_("symbol references section without data"));
+ YASM_WRITE_16_L(bufp, shead->index);
+ } else {
+ YASM_WRITE_16_L(bufp, entry->index);
+ }
+}
+
+static void
+elf_x86_x32_write_secthead(unsigned char *bufp, elf_secthead *shead)
+{
+ YASM_WRITE_32_L(bufp, shead->name ? shead->name->index : 0);
+ YASM_WRITE_32_L(bufp, shead->type);
+ YASM_WRITE_32_L(bufp, shead->flags);
+ YASM_WRITE_32_L(bufp, 0); /* vmem address */
+ YASM_WRITE_32_L(bufp, shead->offset);
+ YASM_WRITE_32I_L(bufp, shead->size);
+
+ YASM_WRITE_32_L(bufp, shead->link);
+ YASM_WRITE_32_L(bufp, shead->info);
+
+ YASM_WRITE_32_L(bufp, shead->align);
+ YASM_WRITE_32_L(bufp, shead->entsize);
+}
+
+static void
+elf_x86_x32_write_secthead_rel(unsigned char *bufp,
+ elf_secthead *shead,
+ elf_section_index symtab_idx,
+ elf_section_index sindex)
+{
+ yasm_intnum *nreloc;
+ yasm_intnum *relocsize;
+
+ YASM_WRITE_32_L(bufp, shead->rel_name ? shead->rel_name->index : 0);
+ YASM_WRITE_32_L(bufp, SHT_RELA);
+ YASM_WRITE_32_L(bufp, 0);
+ YASM_WRITE_32_L(bufp, 0);
+ YASM_WRITE_32_L(bufp, shead->rel_offset);
+
+ nreloc = yasm_intnum_create_uint(shead->nreloc);
+ relocsize = yasm_intnum_create_uint(RELOC32A_SIZE);
+ yasm_intnum_calc(relocsize, YASM_EXPR_MUL, nreloc);
+ YASM_WRITE_32I_L(bufp, relocsize); /* size */
+ yasm_intnum_destroy(nreloc);
+ yasm_intnum_destroy(relocsize);
+
+ YASM_WRITE_32_L(bufp, symtab_idx); /* link: symtab index */
+ YASM_WRITE_32_L(bufp, shead->index); /* info: relocated's index */
+ YASM_WRITE_32_L(bufp, RELOC32_ALIGN); /* align */
+ YASM_WRITE_32_L(bufp, RELOC32A_SIZE); /* entity size */
+}
+
+static void
+elf_x86_x32_handle_reloc_addend(yasm_intnum *intn,
+ elf_reloc_entry *reloc,
+ unsigned long offset)
+{
+ /* .rela: copy value out as addend, replace original with 0 */
+ reloc->addend = yasm_intnum_copy(intn);
+ yasm_intnum_zero(intn);
+}
+
+static unsigned int
+elf_x86_x32_map_reloc_info_to_type(elf_reloc_entry *reloc)
+{
+ if (reloc->wrt) {
+ const elf_machine_ssym *ssym = (elf_machine_ssym *)
+ yasm_symrec_get_data(reloc->wrt, &elf_ssym_symrec_data);
+ if (!ssym || reloc->valsize != ssym->size)
+ yasm_internal_error(N_("Unsupported WRT"));
+
+ /* Force TLS type; this is required by the linker. */
+ if (ssym->sym_rel & ELF_SSYM_THREAD_LOCAL) {
+ elf_symtab_entry *esym;
+
+ esym = yasm_symrec_get_data(reloc->reloc.sym, &elf_symrec_data);
+ if (esym)
+ esym->type = STT_TLS;
+ }
+ /* Map PC-relative GOT to appropriate relocation */
+ if (reloc->rtype_rel && ssym->reloc == R_X86_64_GOT32)
+ return (unsigned char) R_X86_64_GOTPCREL;
+ return (unsigned char) ssym->reloc;
+ } else if (reloc->is_GOT_sym && reloc->valsize == 32) {
+ return (unsigned char) R_X86_64_GOTPC32;
+ } else if (reloc->is_GOT_sym && reloc->valsize == 64) {
+ yasm_internal_error(N_("Unsupported relocation size"));
+ } else if (reloc->rtype_rel) {
+ switch (reloc->valsize) {
+ case 8: return (unsigned char) R_X86_64_PC8;
+ case 16: return (unsigned char) R_X86_64_PC16;
+ case 32: return (unsigned char) R_X86_64_PC32;
+ default: yasm_internal_error(N_("Unsupported relocation size"));
+ }
+ } else {
+ switch (reloc->valsize) {
+ case 8: return (unsigned char) R_X86_64_8;
+ case 16: return (unsigned char) R_X86_64_16;
+ case 32: return (unsigned char) R_X86_64_32;
+ case 64: return (unsigned char) R_X86_64_64;
+ default: yasm_internal_error(N_("Unsupported relocation size"));
+ }
+ }
+ return 0;
+}
+
+static void
+elf_x86_x32_write_reloc(unsigned char *bufp, elf_reloc_entry *reloc,
+ unsigned int r_type, unsigned int r_sym)
+{
+ YASM_WRITE_32I_L(bufp, reloc->reloc.addr);
+ YASM_WRITE_32_L(bufp, ELF32_R_INFO((unsigned long)r_sym, (unsigned char)r_type));
+ if (reloc->addend)
+ YASM_WRITE_32I_L(bufp, reloc->addend);
+ else {
+ YASM_WRITE_32_L(bufp, 0);
+ }
+}
+
+static void
+elf_x86_x32_write_proghead(unsigned char **bufpp,
+ elf_offset secthead_addr,
+ unsigned long secthead_count,
+ elf_section_index shstrtab_index)
+{
+ unsigned char *bufp = *bufpp;
+ unsigned char *buf = bufp-4;
+ YASM_WRITE_8(bufp, ELFCLASS32); /* elf class */
+ YASM_WRITE_8(bufp, ELFDATA2LSB); /* data encoding :: MSB? */
+ YASM_WRITE_8(bufp, EV_CURRENT); /* elf version */
+ YASM_WRITE_8(bufp, ELFOSABI_SYSV); /* os/abi */
+ YASM_WRITE_8(bufp, 0); /* SYSV v3 ABI=0 */
+ while (bufp-buf < EI_NIDENT) /* e_ident padding */
+ YASM_WRITE_8(bufp, 0);
+
+ YASM_WRITE_16_L(bufp, ET_REL); /* e_type - object file */
+ YASM_WRITE_16_L(bufp, EM_X86_64); /* e_machine - or others */
+ YASM_WRITE_32_L(bufp, EV_CURRENT); /* elf version */
+ YASM_WRITE_32_L(bufp, 0); /* e_entry */
+ YASM_WRITE_32_L(bufp, 0); /* e_phoff */
+ YASM_WRITE_32_L(bufp, secthead_addr); /* e_shoff secthead off */
+
+ YASM_WRITE_32_L(bufp, 0); /* e_flags */
+ YASM_WRITE_16_L(bufp, EHDR32_SIZE); /* e_ehsize */
+ YASM_WRITE_16_L(bufp, 0); /* e_phentsize */
+ YASM_WRITE_16_L(bufp, 0); /* e_phnum */
+ YASM_WRITE_16_L(bufp, SHDR32_SIZE); /* e_shentsize */
+ YASM_WRITE_16_L(bufp, secthead_count); /* e_shnum */
+ YASM_WRITE_16_L(bufp, shstrtab_index); /* e_shstrndx */
+ *bufpp = bufp;
+}
+
+const elf_machine_handler
+elf_machine_handler_x86_x32 = {
+ "x86", "x32", ".rela",
+ SYMTAB32_SIZE, SYMTAB32_ALIGN, RELOC32A_SIZE, SHDR32_SIZE, EHDR32_SIZE,
+ elf_x86_x32_accepts_reloc,
+ elf_x86_x32_write_symtab_entry,
+ elf_x86_x32_write_secthead,
+ elf_x86_x32_write_secthead_rel,
+ elf_x86_x32_handle_reloc_addend,
+ elf_x86_x32_map_reloc_info_to_type,
+ elf_x86_x32_write_reloc,
+ elf_x86_x32_write_proghead,
+ elf_x86_x32_ssyms,
+ sizeof(elf_x86_x32_ssyms)/sizeof(elf_x86_x32_ssyms[0]),
+ 32
+};
diff --git a/contrib/tools/yasm/modules/objfmts/elf/elf-x86-x86.c b/contrib/tools/yasm/modules/objfmts/elf/elf-x86-x86.c
index d79ec6eabd..8ebaa87381 100644
--- a/contrib/tools/yasm/modules/objfmts/elf/elf-x86-x86.c
+++ b/contrib/tools/yasm/modules/objfmts/elf/elf-x86-x86.c
@@ -1,242 +1,242 @@
-/*
- * ELF object format helpers - x86:x86
- *
- * Copyright (C) 2004-2007 Michael Urman
- *
- * 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>
-
-#include <libyasm.h>
-#define YASM_OBJFMT_ELF_INTERNAL
-#include "elf.h"
-#include "elf-machine.h"
-
-static elf_machine_ssym elf_x86_x86_ssyms[] = {
- {"plt", ELF_SSYM_SYM_RELATIVE, R_386_PLT32, 32},
- {"gotoff", 0, R_386_GOTOFF, 32},
- /* special one for NASM */
- {"gotpc", ELF_SSYM_CURPOS_ADJUST, R_386_GOTPC, 32},
- {"tlsgd", ELF_SSYM_SYM_RELATIVE|ELF_SSYM_THREAD_LOCAL,
- R_386_TLS_GD, 32},
- {"tlsldm", ELF_SSYM_SYM_RELATIVE|ELF_SSYM_THREAD_LOCAL,
- R_386_TLS_LDM, 32},
- {"gottpoff", ELF_SSYM_SYM_RELATIVE|ELF_SSYM_THREAD_LOCAL,
- R_386_TLS_IE_32, 32},
- {"tpoff", ELF_SSYM_SYM_RELATIVE|ELF_SSYM_THREAD_LOCAL,
- R_386_TLS_LE_32, 32},
- {"ntpoff", ELF_SSYM_SYM_RELATIVE|ELF_SSYM_THREAD_LOCAL,
- R_386_TLS_LE, 32},
- {"dtpoff", ELF_SSYM_SYM_RELATIVE|ELF_SSYM_THREAD_LOCAL,
- R_386_TLS_LDO_32, 32},
- {"gotntpoff", ELF_SSYM_SYM_RELATIVE|ELF_SSYM_THREAD_LOCAL,
- R_386_TLS_GOTIE, 32},
- {"indntpoff", ELF_SSYM_SYM_RELATIVE|ELF_SSYM_THREAD_LOCAL,
- R_386_TLS_IE, 32},
- {"got", ELF_SSYM_SYM_RELATIVE, R_386_GOT32, 32},
- {"tlsdesc", ELF_SSYM_SYM_RELATIVE|ELF_SSYM_THREAD_LOCAL,
- R_386_TLS_GOTDESC, 32},
- {"tlscall", ELF_SSYM_SYM_RELATIVE|ELF_SSYM_THREAD_LOCAL,
- R_386_TLS_DESC_CALL, 32}
-};
-
-static int
-elf_x86_x86_accepts_reloc(size_t val, yasm_symrec *wrt)
-{
- if (wrt) {
- const elf_machine_ssym *ssym = (elf_machine_ssym *)
- yasm_symrec_get_data(wrt, &elf_ssym_symrec_data);
- if (!ssym || val != ssym->size)
- return 0;
- return 1;
- }
- return (val&(val-1)) ? 0 : ((val & (8|16|32)) != 0);
-}
-
-static void
-elf_x86_x86_write_symtab_entry(unsigned char *bufp,
- elf_symtab_entry *entry,
- yasm_intnum *value_intn,
- yasm_intnum *size_intn)
-{
- YASM_WRITE_32_L(bufp, entry->name ? entry->name->index : 0);
- YASM_WRITE_32I_L(bufp, value_intn);
- YASM_WRITE_32I_L(bufp, size_intn);
-
- YASM_WRITE_8(bufp, ELF32_ST_INFO(entry->bind, entry->type));
- YASM_WRITE_8(bufp, ELF32_ST_OTHER(entry->vis));
- if (entry->sect) {
- elf_secthead *shead =
- yasm_section_get_data(entry->sect, &elf_section_data);
- if (!shead)
- yasm_internal_error(N_("symbol references section without data"));
- YASM_WRITE_16_L(bufp, shead->index);
- } else {
- YASM_WRITE_16_L(bufp, entry->index);
- }
-}
-
-static void
-elf_x86_x86_write_secthead(unsigned char *bufp, elf_secthead *shead)
-{
- YASM_WRITE_32_L(bufp, shead->name ? shead->name->index : 0);
- YASM_WRITE_32_L(bufp, shead->type);
- YASM_WRITE_32_L(bufp, shead->flags);
- YASM_WRITE_32_L(bufp, 0); /* vmem address */
-
- YASM_WRITE_32_L(bufp, shead->offset);
- YASM_WRITE_32I_L(bufp, shead->size);
- YASM_WRITE_32_L(bufp, shead->link);
- YASM_WRITE_32_L(bufp, shead->info);
-
- YASM_WRITE_32_L(bufp, shead->align);
- YASM_WRITE_32_L(bufp, shead->entsize);
-
-}
-
-static void
-elf_x86_x86_write_secthead_rel(unsigned char *bufp,
- elf_secthead *shead,
- elf_section_index symtab_idx,
- elf_section_index sindex)
-{
- YASM_WRITE_32_L(bufp, shead->rel_name ? shead->rel_name->index : 0);
- YASM_WRITE_32_L(bufp, SHT_REL);
- YASM_WRITE_32_L(bufp, 0);
- YASM_WRITE_32_L(bufp, 0);
-
- YASM_WRITE_32_L(bufp, shead->rel_offset);
- YASM_WRITE_32_L(bufp, RELOC32_SIZE * shead->nreloc);/* size */
- YASM_WRITE_32_L(bufp, symtab_idx); /* link: symtab index */
- YASM_WRITE_32_L(bufp, shead->index); /* info: relocated's index */
-
- YASM_WRITE_32_L(bufp, RELOC32_ALIGN); /* align */
- YASM_WRITE_32_L(bufp, RELOC32_SIZE); /* entity size */
-}
-
-static void
-elf_x86_x86_handle_reloc_addend(yasm_intnum *intn,
- elf_reloc_entry *reloc,
- unsigned long offset)
-{
- if (!reloc->wrt && reloc->is_GOT_sym && reloc->valsize == 32 && offset != 0)
- {
- yasm_intnum *off_intn = yasm_intnum_create_uint(offset);
- yasm_intnum_calc(intn, YASM_EXPR_ADD, off_intn);
- yasm_intnum_destroy(off_intn);
- }
- return; /* .rel: Leave addend in intn */
-}
-
-static unsigned int
-elf_x86_x86_map_reloc_info_to_type(elf_reloc_entry *reloc)
-{
- if (reloc->wrt) {
- const elf_machine_ssym *ssym = (elf_machine_ssym *)
- yasm_symrec_get_data(reloc->wrt, &elf_ssym_symrec_data);
- if (!ssym || reloc->valsize != ssym->size)
- yasm_internal_error(N_("Unsupported WRT"));
-
- /* Force TLS type; this is required by the linker. */
- if (ssym->sym_rel & ELF_SSYM_THREAD_LOCAL) {
- elf_symtab_entry *esym;
-
- esym = yasm_symrec_get_data(reloc->reloc.sym, &elf_symrec_data);
- if (esym)
- esym->type = STT_TLS;
- }
- return (unsigned char) ssym->reloc;
- } else if (reloc->is_GOT_sym && reloc->valsize == 32) {
- return (unsigned char) R_386_GOTPC;
- } else if (reloc->rtype_rel) {
- switch (reloc->valsize) {
- case 8: return (unsigned char) R_386_PC8;
- case 16: return (unsigned char) R_386_PC16;
- case 32: return (unsigned char) R_386_PC32;
- default: yasm_internal_error(N_("Unsupported relocation size"));
- }
- } else {
- switch (reloc->valsize) {
- case 8: return (unsigned char) R_386_8;
- case 16: return (unsigned char) R_386_16;
- case 32: return (unsigned char) R_386_32;
- default: yasm_internal_error(N_("Unsupported relocation size"));
- }
- }
- return 0;
-}
-
-static void
-elf_x86_x86_write_reloc(unsigned char *bufp, elf_reloc_entry *reloc,
- unsigned int r_type, unsigned int r_sym)
-{
- YASM_WRITE_32I_L(bufp, reloc->reloc.addr);
- YASM_WRITE_32_L(bufp, ELF32_R_INFO((unsigned long)r_sym, (unsigned char)r_type));
-}
-
-static void
-elf_x86_x86_write_proghead(unsigned char **bufpp,
- elf_offset secthead_addr,
- unsigned long secthead_count,
- elf_section_index shstrtab_index)
-{
- unsigned char *bufp = *bufpp;
- unsigned char *buf = bufp-4;
- YASM_WRITE_8(bufp, ELFCLASS32); /* elf class */
- YASM_WRITE_8(bufp, ELFDATA2LSB); /* data encoding :: MSB? */
- YASM_WRITE_8(bufp, EV_CURRENT); /* elf version */
- while (bufp-buf < EI_NIDENT) /* e_ident padding */
- YASM_WRITE_8(bufp, 0);
-
- YASM_WRITE_16_L(bufp, ET_REL); /* e_type - object file */
- YASM_WRITE_16_L(bufp, EM_386); /* e_machine - or others */
- YASM_WRITE_32_L(bufp, EV_CURRENT); /* elf version */
- YASM_WRITE_32_L(bufp, 0); /* e_entry exection startaddr */
- YASM_WRITE_32_L(bufp, 0); /* e_phoff program header off */
- YASM_WRITE_32_L(bufp, secthead_addr); /* e_shoff section header off */
- YASM_WRITE_32_L(bufp, 0); /* e_flags also by arch */
- YASM_WRITE_16_L(bufp, EHDR32_SIZE); /* e_ehsize */
- YASM_WRITE_16_L(bufp, 0); /* e_phentsize */
- YASM_WRITE_16_L(bufp, 0); /* e_phnum */
- YASM_WRITE_16_L(bufp, SHDR32_SIZE); /* e_shentsize */
- YASM_WRITE_16_L(bufp, secthead_count); /* e_shnum */
- YASM_WRITE_16_L(bufp, shstrtab_index); /* e_shstrndx */
- *bufpp = bufp;
-}
-
-const elf_machine_handler
-elf_machine_handler_x86_x86 = {
- "x86", "x86", ".rel",
- SYMTAB32_SIZE, SYMTAB32_ALIGN, RELOC32_SIZE, SHDR32_SIZE, EHDR32_SIZE,
- elf_x86_x86_accepts_reloc,
- elf_x86_x86_write_symtab_entry,
- elf_x86_x86_write_secthead,
- elf_x86_x86_write_secthead_rel,
- elf_x86_x86_handle_reloc_addend,
- elf_x86_x86_map_reloc_info_to_type,
- elf_x86_x86_write_reloc,
- elf_x86_x86_write_proghead,
- elf_x86_x86_ssyms,
- sizeof(elf_x86_x86_ssyms)/sizeof(elf_x86_x86_ssyms[0]),
- 32
-};
+/*
+ * ELF object format helpers - x86:x86
+ *
+ * Copyright (C) 2004-2007 Michael Urman
+ *
+ * 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>
+
+#include <libyasm.h>
+#define YASM_OBJFMT_ELF_INTERNAL
+#include "elf.h"
+#include "elf-machine.h"
+
+static elf_machine_ssym elf_x86_x86_ssyms[] = {
+ {"plt", ELF_SSYM_SYM_RELATIVE, R_386_PLT32, 32},
+ {"gotoff", 0, R_386_GOTOFF, 32},
+ /* special one for NASM */
+ {"gotpc", ELF_SSYM_CURPOS_ADJUST, R_386_GOTPC, 32},
+ {"tlsgd", ELF_SSYM_SYM_RELATIVE|ELF_SSYM_THREAD_LOCAL,
+ R_386_TLS_GD, 32},
+ {"tlsldm", ELF_SSYM_SYM_RELATIVE|ELF_SSYM_THREAD_LOCAL,
+ R_386_TLS_LDM, 32},
+ {"gottpoff", ELF_SSYM_SYM_RELATIVE|ELF_SSYM_THREAD_LOCAL,
+ R_386_TLS_IE_32, 32},
+ {"tpoff", ELF_SSYM_SYM_RELATIVE|ELF_SSYM_THREAD_LOCAL,
+ R_386_TLS_LE_32, 32},
+ {"ntpoff", ELF_SSYM_SYM_RELATIVE|ELF_SSYM_THREAD_LOCAL,
+ R_386_TLS_LE, 32},
+ {"dtpoff", ELF_SSYM_SYM_RELATIVE|ELF_SSYM_THREAD_LOCAL,
+ R_386_TLS_LDO_32, 32},
+ {"gotntpoff", ELF_SSYM_SYM_RELATIVE|ELF_SSYM_THREAD_LOCAL,
+ R_386_TLS_GOTIE, 32},
+ {"indntpoff", ELF_SSYM_SYM_RELATIVE|ELF_SSYM_THREAD_LOCAL,
+ R_386_TLS_IE, 32},
+ {"got", ELF_SSYM_SYM_RELATIVE, R_386_GOT32, 32},
+ {"tlsdesc", ELF_SSYM_SYM_RELATIVE|ELF_SSYM_THREAD_LOCAL,
+ R_386_TLS_GOTDESC, 32},
+ {"tlscall", ELF_SSYM_SYM_RELATIVE|ELF_SSYM_THREAD_LOCAL,
+ R_386_TLS_DESC_CALL, 32}
+};
+
+static int
+elf_x86_x86_accepts_reloc(size_t val, yasm_symrec *wrt)
+{
+ if (wrt) {
+ const elf_machine_ssym *ssym = (elf_machine_ssym *)
+ yasm_symrec_get_data(wrt, &elf_ssym_symrec_data);
+ if (!ssym || val != ssym->size)
+ return 0;
+ return 1;
+ }
+ return (val&(val-1)) ? 0 : ((val & (8|16|32)) != 0);
+}
+
+static void
+elf_x86_x86_write_symtab_entry(unsigned char *bufp,
+ elf_symtab_entry *entry,
+ yasm_intnum *value_intn,
+ yasm_intnum *size_intn)
+{
+ YASM_WRITE_32_L(bufp, entry->name ? entry->name->index : 0);
+ YASM_WRITE_32I_L(bufp, value_intn);
+ YASM_WRITE_32I_L(bufp, size_intn);
+
+ YASM_WRITE_8(bufp, ELF32_ST_INFO(entry->bind, entry->type));
+ YASM_WRITE_8(bufp, ELF32_ST_OTHER(entry->vis));
+ if (entry->sect) {
+ elf_secthead *shead =
+ yasm_section_get_data(entry->sect, &elf_section_data);
+ if (!shead)
+ yasm_internal_error(N_("symbol references section without data"));
+ YASM_WRITE_16_L(bufp, shead->index);
+ } else {
+ YASM_WRITE_16_L(bufp, entry->index);
+ }
+}
+
+static void
+elf_x86_x86_write_secthead(unsigned char *bufp, elf_secthead *shead)
+{
+ YASM_WRITE_32_L(bufp, shead->name ? shead->name->index : 0);
+ YASM_WRITE_32_L(bufp, shead->type);
+ YASM_WRITE_32_L(bufp, shead->flags);
+ YASM_WRITE_32_L(bufp, 0); /* vmem address */
+
+ YASM_WRITE_32_L(bufp, shead->offset);
+ YASM_WRITE_32I_L(bufp, shead->size);
+ YASM_WRITE_32_L(bufp, shead->link);
+ YASM_WRITE_32_L(bufp, shead->info);
+
+ YASM_WRITE_32_L(bufp, shead->align);
+ YASM_WRITE_32_L(bufp, shead->entsize);
+
+}
+
+static void
+elf_x86_x86_write_secthead_rel(unsigned char *bufp,
+ elf_secthead *shead,
+ elf_section_index symtab_idx,
+ elf_section_index sindex)
+{
+ YASM_WRITE_32_L(bufp, shead->rel_name ? shead->rel_name->index : 0);
+ YASM_WRITE_32_L(bufp, SHT_REL);
+ YASM_WRITE_32_L(bufp, 0);
+ YASM_WRITE_32_L(bufp, 0);
+
+ YASM_WRITE_32_L(bufp, shead->rel_offset);
+ YASM_WRITE_32_L(bufp, RELOC32_SIZE * shead->nreloc);/* size */
+ YASM_WRITE_32_L(bufp, symtab_idx); /* link: symtab index */
+ YASM_WRITE_32_L(bufp, shead->index); /* info: relocated's index */
+
+ YASM_WRITE_32_L(bufp, RELOC32_ALIGN); /* align */
+ YASM_WRITE_32_L(bufp, RELOC32_SIZE); /* entity size */
+}
+
+static void
+elf_x86_x86_handle_reloc_addend(yasm_intnum *intn,
+ elf_reloc_entry *reloc,
+ unsigned long offset)
+{
+ if (!reloc->wrt && reloc->is_GOT_sym && reloc->valsize == 32 && offset != 0)
+ {
+ yasm_intnum *off_intn = yasm_intnum_create_uint(offset);
+ yasm_intnum_calc(intn, YASM_EXPR_ADD, off_intn);
+ yasm_intnum_destroy(off_intn);
+ }
+ return; /* .rel: Leave addend in intn */
+}
+
+static unsigned int
+elf_x86_x86_map_reloc_info_to_type(elf_reloc_entry *reloc)
+{
+ if (reloc->wrt) {
+ const elf_machine_ssym *ssym = (elf_machine_ssym *)
+ yasm_symrec_get_data(reloc->wrt, &elf_ssym_symrec_data);
+ if (!ssym || reloc->valsize != ssym->size)
+ yasm_internal_error(N_("Unsupported WRT"));
+
+ /* Force TLS type; this is required by the linker. */
+ if (ssym->sym_rel & ELF_SSYM_THREAD_LOCAL) {
+ elf_symtab_entry *esym;
+
+ esym = yasm_symrec_get_data(reloc->reloc.sym, &elf_symrec_data);
+ if (esym)
+ esym->type = STT_TLS;
+ }
+ return (unsigned char) ssym->reloc;
+ } else if (reloc->is_GOT_sym && reloc->valsize == 32) {
+ return (unsigned char) R_386_GOTPC;
+ } else if (reloc->rtype_rel) {
+ switch (reloc->valsize) {
+ case 8: return (unsigned char) R_386_PC8;
+ case 16: return (unsigned char) R_386_PC16;
+ case 32: return (unsigned char) R_386_PC32;
+ default: yasm_internal_error(N_("Unsupported relocation size"));
+ }
+ } else {
+ switch (reloc->valsize) {
+ case 8: return (unsigned char) R_386_8;
+ case 16: return (unsigned char) R_386_16;
+ case 32: return (unsigned char) R_386_32;
+ default: yasm_internal_error(N_("Unsupported relocation size"));
+ }
+ }
+ return 0;
+}
+
+static void
+elf_x86_x86_write_reloc(unsigned char *bufp, elf_reloc_entry *reloc,
+ unsigned int r_type, unsigned int r_sym)
+{
+ YASM_WRITE_32I_L(bufp, reloc->reloc.addr);
+ YASM_WRITE_32_L(bufp, ELF32_R_INFO((unsigned long)r_sym, (unsigned char)r_type));
+}
+
+static void
+elf_x86_x86_write_proghead(unsigned char **bufpp,
+ elf_offset secthead_addr,
+ unsigned long secthead_count,
+ elf_section_index shstrtab_index)
+{
+ unsigned char *bufp = *bufpp;
+ unsigned char *buf = bufp-4;
+ YASM_WRITE_8(bufp, ELFCLASS32); /* elf class */
+ YASM_WRITE_8(bufp, ELFDATA2LSB); /* data encoding :: MSB? */
+ YASM_WRITE_8(bufp, EV_CURRENT); /* elf version */
+ while (bufp-buf < EI_NIDENT) /* e_ident padding */
+ YASM_WRITE_8(bufp, 0);
+
+ YASM_WRITE_16_L(bufp, ET_REL); /* e_type - object file */
+ YASM_WRITE_16_L(bufp, EM_386); /* e_machine - or others */
+ YASM_WRITE_32_L(bufp, EV_CURRENT); /* elf version */
+ YASM_WRITE_32_L(bufp, 0); /* e_entry exection startaddr */
+ YASM_WRITE_32_L(bufp, 0); /* e_phoff program header off */
+ YASM_WRITE_32_L(bufp, secthead_addr); /* e_shoff section header off */
+ YASM_WRITE_32_L(bufp, 0); /* e_flags also by arch */
+ YASM_WRITE_16_L(bufp, EHDR32_SIZE); /* e_ehsize */
+ YASM_WRITE_16_L(bufp, 0); /* e_phentsize */
+ YASM_WRITE_16_L(bufp, 0); /* e_phnum */
+ YASM_WRITE_16_L(bufp, SHDR32_SIZE); /* e_shentsize */
+ YASM_WRITE_16_L(bufp, secthead_count); /* e_shnum */
+ YASM_WRITE_16_L(bufp, shstrtab_index); /* e_shstrndx */
+ *bufpp = bufp;
+}
+
+const elf_machine_handler
+elf_machine_handler_x86_x86 = {
+ "x86", "x86", ".rel",
+ SYMTAB32_SIZE, SYMTAB32_ALIGN, RELOC32_SIZE, SHDR32_SIZE, EHDR32_SIZE,
+ elf_x86_x86_accepts_reloc,
+ elf_x86_x86_write_symtab_entry,
+ elf_x86_x86_write_secthead,
+ elf_x86_x86_write_secthead_rel,
+ elf_x86_x86_handle_reloc_addend,
+ elf_x86_x86_map_reloc_info_to_type,
+ elf_x86_x86_write_reloc,
+ elf_x86_x86_write_proghead,
+ elf_x86_x86_ssyms,
+ sizeof(elf_x86_x86_ssyms)/sizeof(elf_x86_x86_ssyms[0]),
+ 32
+};
diff --git a/contrib/tools/yasm/modules/objfmts/elf/elf.c b/contrib/tools/yasm/modules/objfmts/elf/elf.c
index 2486bba8df..04f3fe661a 100644
--- a/contrib/tools/yasm/modules/objfmts/elf/elf.c
+++ b/contrib/tools/yasm/modules/objfmts/elf/elf.c
@@ -1,960 +1,960 @@
-/*
- * ELF object format helpers
- *
- * Copyright (C) 2003-2007 Michael Urman
- *
- * 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>
-
-#include <libyasm.h>
-#define YASM_OBJFMT_ELF_INTERNAL
-#include "elf.h"
-#include "elf-machine.h"
-
-static void elf_section_data_destroy(void *data);
-static void elf_secthead_print(void *data, FILE *f, int indent_level);
-
-const yasm_assoc_data_callback elf_section_data = {
- elf_section_data_destroy,
- elf_secthead_print
-};
-
-static void elf_symrec_data_destroy(/*@only@*/ void *d);
-static void elf_symtab_entry_print(void *data, FILE *f, int indent_level);
-static void elf_ssym_symtab_entry_print(void *data, FILE *f, int indent_level);
-
-const yasm_assoc_data_callback elf_symrec_data = {
- elf_symrec_data_destroy,
- elf_symtab_entry_print
-};
-
-const yasm_assoc_data_callback elf_ssym_symrec_data = {
- elf_symrec_data_destroy,
- elf_ssym_symtab_entry_print
-};
-
-extern elf_machine_handler
- elf_machine_handler_x86_x86,
- elf_machine_handler_x86_amd64,
- elf_machine_handler_x86_x32;
-
-static const elf_machine_handler *elf_machine_handlers[] =
-{
- &elf_machine_handler_x86_x86,
- &elf_machine_handler_x86_amd64,
- &elf_machine_handler_x86_x32,
- NULL
-};
-static const elf_machine_handler elf_null_machine = {0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0};
-static elf_machine_handler const *elf_march = &elf_null_machine;
-static yasm_symrec **elf_ssyms;
-
-const elf_machine_handler *
-elf_set_arch(yasm_arch *arch, yasm_symtab *symtab, int bits_pref)
-{
- const char *machine = yasm_arch_get_machine(arch);
- int i;
-
- for (i=0, elf_march = elf_machine_handlers[0];
- elf_march != NULL;
- elf_march = elf_machine_handlers[++i])
- {
- if (yasm__strcasecmp(yasm_arch_keyword(arch), elf_march->arch)==0) {
- if (yasm__strcasecmp(machine, elf_march->machine)==0) {
- if (bits_pref == 0 || bits_pref == elf_march->bits)
- break;
- } else if (bits_pref == elf_march->bits
- && yasm__strcasecmp(machine, "amd64") == 0
- && yasm__strcasecmp(elf_march->machine, "x32") == 0)
- break;
- }
- }
-
- if (elf_march && elf_march->num_ssyms > 0)
- {
- /* Allocate "special" syms */
- elf_ssyms =
- yasm_xmalloc(elf_march->num_ssyms * sizeof(yasm_symrec *));
- for (i=0; (unsigned int)i<elf_march->num_ssyms; i++)
- {
- /* FIXME: misuse of NULL bytecode */
- elf_ssyms[i] = yasm_symtab_define_label(symtab,
- elf_march->ssyms[i].name,
- NULL, 0, 0);
- yasm_symrec_add_data(elf_ssyms[i], &elf_ssym_symrec_data,
- (void*)&elf_march->ssyms[i]);
- }
- }
-
- return elf_march;
-}
-
-yasm_symrec *
-elf_get_special_sym(const char *name, const char *parser)
-{
- int i;
- for (i=0; (unsigned int)i<elf_march->num_ssyms; i++) {
- if (yasm__strcasecmp(name, elf_march->ssyms[i].name) == 0)
- return elf_ssyms[i];
- }
- return NULL;
-}
-
-/* reloc functions */
-int elf_ssym_has_flag(yasm_symrec *wrt, int flag);
-
-int
-elf_is_wrt_sym_relative(yasm_symrec *wrt)
-{
- return elf_ssym_has_flag(wrt, ELF_SSYM_SYM_RELATIVE);
-}
-
-int
-elf_is_wrt_pos_adjusted(yasm_symrec *wrt)
-{
- return elf_ssym_has_flag(wrt, ELF_SSYM_CURPOS_ADJUST);
-}
-
-int
-elf_ssym_has_flag(yasm_symrec *wrt, int flag)
-{
- int i;
- for (i=0; (unsigned int)i<elf_march->num_ssyms; i++) {
- if (elf_ssyms[i] == wrt)
- return (elf_march->ssyms[i].sym_rel & flag) != 0;
- }
- return 0;
-}
-
-/* takes ownership of addr */
-elf_reloc_entry *
-elf_reloc_entry_create(yasm_symrec *sym,
- yasm_symrec *wrt,
- yasm_intnum *addr,
- int rel,
- size_t valsize,
- int is_GOT_sym)
-{
- elf_reloc_entry *entry;
-
- if (!elf_march->accepts_reloc)
- yasm_internal_error(N_("Unsupported machine for ELF output"));
-
- if (!elf_march->accepts_reloc(valsize, wrt))
- {
- if (addr)
- yasm_intnum_destroy(addr);
- return NULL;
- }
-
- if (sym == NULL)
- yasm_internal_error("sym is null");
-
- entry = yasm_xmalloc(sizeof(elf_reloc_entry));
- entry->reloc.sym = sym;
- entry->reloc.addr = addr;
- entry->rtype_rel = rel;
- entry->valsize = valsize;
- entry->addend = NULL;
- entry->wrt = wrt;
- entry->is_GOT_sym = is_GOT_sym;
-
- return entry;
-}
-
-void
-elf_reloc_entry_destroy(void *entry)
-{
- if (((elf_reloc_entry*)entry)->addend)
- yasm_intnum_destroy(((elf_reloc_entry*)entry)->addend);
- yasm_xfree(entry);
-}
-
-/* strtab functions */
-elf_strtab_entry *
-elf_strtab_entry_create(const char *str)
-{
- elf_strtab_entry *entry = yasm_xmalloc(sizeof(elf_strtab_entry));
- entry->str = yasm__xstrdup(str);
- entry->index = 0;
- return entry;
-}
-
-void
-elf_strtab_entry_set_str(elf_strtab_entry *entry, const char *str)
-{
- elf_strtab_entry *last;
- if (entry->str)
- yasm_xfree(entry->str);
- entry->str = yasm__xstrdup(str);
-
- /* Update all following indices since string length probably changes */
- last = entry;
- entry = STAILQ_NEXT(last, qlink);
- while (entry) {
- entry->index = last->index + (unsigned long)strlen(last->str) + 1;
- last = entry;
- entry = STAILQ_NEXT(last, qlink);
- }
-}
-
-elf_strtab_head *
-elf_strtab_create()
-{
- elf_strtab_head *strtab = yasm_xmalloc(sizeof(elf_strtab_head));
- elf_strtab_entry *entry = yasm_xmalloc(sizeof(elf_strtab_entry));
-
- STAILQ_INIT(strtab);
- entry->index = 0;
- entry->str = yasm__xstrdup("");
-
- STAILQ_INSERT_TAIL(strtab, entry, qlink);
- return strtab;
-}
-
-elf_strtab_entry *
-elf_strtab_append_str(elf_strtab_head *strtab, const char *str)
-{
- elf_strtab_entry *last, *entry;
-
- if (strtab == NULL)
- yasm_internal_error("strtab is null");
- if (STAILQ_EMPTY(strtab))
- yasm_internal_error("strtab is missing initial dummy entry");
-
- last = STAILQ_LAST(strtab, elf_strtab_entry, qlink);
-
- entry = elf_strtab_entry_create(str);
- entry->index = last->index + (unsigned long)strlen(last->str) + 1;
-
- STAILQ_INSERT_TAIL(strtab, entry, qlink);
- return entry;
-}
-
-void
-elf_strtab_destroy(elf_strtab_head *strtab)
-{
- elf_strtab_entry *s1, *s2;
-
- if (strtab == NULL)
- yasm_internal_error("strtab is null");
- if (STAILQ_EMPTY(strtab))
- yasm_internal_error("strtab is missing initial dummy entry");
-
- s1 = STAILQ_FIRST(strtab);
- while (s1 != NULL) {
- s2 = STAILQ_NEXT(s1, qlink);
- yasm_xfree(s1->str);
- yasm_xfree(s1);
- s1 = s2;
- }
- yasm_xfree(strtab);
-}
-
-unsigned long
-elf_strtab_output_to_file(FILE *f, elf_strtab_head *strtab)
-{
- unsigned long size = 0;
- elf_strtab_entry *entry;
-
- if (strtab == NULL)
- yasm_internal_error("strtab is null");
-
- /* consider optimizing tables here */
- STAILQ_FOREACH(entry, strtab, qlink) {
- size_t len = 1 + strlen(entry->str);
- fwrite(entry->str, len, 1, f);
- size += (unsigned long)len;
- }
- return size;
-}
-
-
-
-/* symtab functions */
-elf_symtab_entry *
-elf_symtab_entry_create(elf_strtab_entry *name,
- yasm_symrec *sym)
-{
- elf_symtab_entry *entry = yasm_xmalloc(sizeof(elf_symtab_entry));
- entry->in_table = 0;
- entry->sym = sym;
- entry->sect = NULL;
- entry->name = name;
- entry->value = 0;
-
- entry->xsize = NULL;
- entry->size = 0;
- entry->index = 0;
- entry->bind = 0;
- entry->type = STT_NOTYPE;
- entry->vis = STV_DEFAULT;
-
- return entry;
-}
-
-static void
-elf_symtab_entry_destroy(elf_symtab_entry *entry)
-{
- if (entry == NULL)
- yasm_internal_error("symtab entry is null");
-
- yasm_xfree(entry);
-}
-
-static void
-elf_symrec_data_destroy(void *data)
-{
- /* do nothing, as this stuff is in the symtab anyway... this speaks of bad
- * design/use or this stuff, i fear */
-
- /* watch for double-free here ... */
- /*elf_symtab_entry_destroy((elf_symtab_entry *)data);*/
-}
-
-static void
-elf_symtab_entry_print(void *data, FILE *f, int indent_level)
-{
- elf_symtab_entry *entry = data;
- if (entry == NULL)
- yasm_internal_error("symtab entry is null");
-
- fprintf(f, "%*sbind=", indent_level, "");
- switch (entry->bind) {
- case STB_LOCAL: fprintf(f, "local\n"); break;
- case STB_GLOBAL: fprintf(f, "global\n"); break;
- case STB_WEAK: fprintf(f, "weak\n"); break;
- default: fprintf(f, "undef\n"); break;
- }
- fprintf(f, "%*stype=", indent_level, "");
- switch (entry->type) {
- case STT_NOTYPE: fprintf(f, "notype\n"); break;
- case STT_OBJECT: fprintf(f, "object\n"); break;
- case STT_FUNC: fprintf(f, "func\n"); break;
- case STT_SECTION: fprintf(f, "section\n");break;
- case STT_FILE: fprintf(f, "file\n"); break;
- default: fprintf(f, "undef\n"); break;
- }
- fprintf(f, "%*ssize=", indent_level, "");
- if (entry->xsize)
- yasm_expr_print(entry->xsize, f);
- else
- fprintf(f, "%ld", entry->size);
- fprintf(f, "\n");
-}
-
-static void
-elf_ssym_symtab_entry_print(void *data, FILE *f, int indent_level)
-{
- /* TODO */
-}
-
-elf_symtab_head *
-elf_symtab_create()
-{
- elf_symtab_head *symtab = yasm_xmalloc(sizeof(elf_symtab_head));
- elf_symtab_entry *entry = yasm_xmalloc(sizeof(elf_symtab_entry));
-
- STAILQ_INIT(symtab);
- entry->in_table = 1;
- entry->sym = NULL;
- entry->sect = NULL;
- entry->name = NULL;
- entry->value = 0;
- entry->xsize = NULL;
- entry->size = 0;
- entry->index = SHN_UNDEF;
- entry->bind = STB_LOCAL;
- entry->type = STT_NOTYPE;
- entry->vis = STV_DEFAULT;
- entry->symindex = 0;
- STAILQ_INSERT_TAIL(symtab, entry, qlink);
- return symtab;
-}
-
-void
-elf_symtab_append_entry(elf_symtab_head *symtab, elf_symtab_entry *entry)
-{
- if (symtab == NULL)
- yasm_internal_error("symtab is null");
- if (entry == NULL)
- yasm_internal_error("symtab entry is null");
- if (STAILQ_EMPTY(symtab))
- yasm_internal_error(N_("symtab is missing initial dummy entry"));
-
- STAILQ_INSERT_TAIL(symtab, entry, qlink);
- entry->in_table = 1;
-}
-
-void
-elf_symtab_insert_local_sym(elf_symtab_head *symtab, elf_symtab_entry *entry)
-{
- elf_symtab_entry *after = STAILQ_FIRST(symtab);
- elf_symtab_entry *before = NULL;
-
- while (after && (after->bind == STB_LOCAL)) {
- before = after;
- if (before->type == STT_FILE) break;
- after = STAILQ_NEXT(after, qlink);
- }
- STAILQ_INSERT_AFTER(symtab, before, entry, qlink);
- entry->in_table = 1;
-}
-
-void
-elf_symtab_destroy(elf_symtab_head *symtab)
-{
- elf_symtab_entry *s1, *s2;
-
- if (symtab == NULL)
- yasm_internal_error("symtab is null");
- if (STAILQ_EMPTY(symtab))
- yasm_internal_error(N_("symtab is missing initial dummy entry"));
-
- s1 = STAILQ_FIRST(symtab);
- while (s1 != NULL) {
- s2 = STAILQ_NEXT(s1, qlink);
- elf_symtab_entry_destroy(s1);
- s1 = s2;
- }
- yasm_xfree(symtab);
-}
-
-unsigned long
-elf_symtab_assign_indices(elf_symtab_head *symtab)
-{
- elf_symtab_entry *entry, *prev=NULL;
- unsigned long last_local=0;
-
- if (symtab == NULL)
- yasm_internal_error("symtab is null");
- if (STAILQ_EMPTY(symtab))
- yasm_internal_error(N_("symtab is missing initial dummy entry"));
-
- STAILQ_FOREACH(entry, symtab, qlink) {
- if (prev)
- entry->symindex = prev->symindex + 1;
- if (entry->bind == STB_LOCAL)
- last_local = entry->symindex;
- prev = entry;
- }
- return last_local + 1;
-}
-
-unsigned long
-elf_symtab_write_to_file(FILE *f, elf_symtab_head *symtab,
- yasm_errwarns *errwarns)
-{
- unsigned char buf[SYMTAB_MAXSIZE], *bufp;
- elf_symtab_entry *entry;
- unsigned long size = 0;
-
- if (!symtab)
- yasm_internal_error(N_("symtab is null"));
-
- STAILQ_FOREACH(entry, symtab, qlink) {
-
- yasm_intnum *size_intn=NULL, *value_intn=NULL;
- bufp = buf;
-
- /* get size (if specified); expr overrides stored integer */
- if (entry->xsize) {
- size_intn = yasm_intnum_copy(
- yasm_expr_get_intnum(&entry->xsize, 1));
- if (!size_intn) {
- yasm_error_set(YASM_ERROR_VALUE,
- N_("size specifier not an integer expression"));
- yasm_errwarn_propagate(errwarns, entry->xsize->line);
- }
- }
- else
- size_intn = yasm_intnum_create_uint(entry->size);
-
- /* get EQU value for constants */
- if (entry->sym) {
- const yasm_expr *equ_expr_c;
- equ_expr_c = yasm_symrec_get_equ(entry->sym);
-
- if (equ_expr_c != NULL) {
- const yasm_intnum *equ_intn;
- yasm_expr *equ_expr = yasm_expr_copy(equ_expr_c);
- equ_intn = yasm_expr_get_intnum(&equ_expr, 1);
-
- if (equ_intn == NULL) {
- yasm_error_set(YASM_ERROR_VALUE,
- N_("EQU value not an integer expression"));
- yasm_errwarn_propagate(errwarns, equ_expr->line);
- } else
- value_intn = yasm_intnum_copy(equ_intn);
- entry->index = SHN_ABS;
- yasm_expr_destroy(equ_expr);
- }
- }
- if (value_intn == NULL)
- value_intn = yasm_intnum_create_uint(entry->value);
-
- /* If symbol is in a TLS section, force its type to TLS. */
- if (entry->sym) {
- yasm_bytecode *precbc;
- yasm_section *sect;
- elf_secthead *shead;
- if (yasm_symrec_get_label(entry->sym, &precbc) &&
- (sect = yasm_bc_get_section(precbc)) &&
- (shead = yasm_section_get_data(sect, &elf_section_data)) &&
- shead->flags & SHF_TLS) {
- entry->type = STT_TLS;
- }
- }
-
- if (!elf_march->write_symtab_entry || !elf_march->symtab_entry_size)
- yasm_internal_error(N_("Unsupported machine for ELF output"));
- elf_march->write_symtab_entry(bufp, entry, value_intn, size_intn);
- fwrite(buf, elf_march->symtab_entry_size, 1, f);
- size += elf_march->symtab_entry_size;
-
- yasm_intnum_destroy(size_intn);
- yasm_intnum_destroy(value_intn);
- }
- return size;
-}
-
-void elf_symtab_set_nonzero(elf_symtab_entry *entry,
- yasm_section *sect,
- elf_section_index sectidx,
- elf_symbol_binding bind,
- elf_symbol_type type,
- yasm_expr *xsize,
- elf_address *value)
-{
- if (!entry)
- yasm_internal_error("NULL entry");
- if (sect) entry->sect = sect;
- if (sectidx) entry->index = sectidx;
- if (bind) entry->bind = bind;
- if (type) entry->type = type;
- if (xsize) entry->xsize = xsize;
- if (value) entry->value = *value;
-}
-
-void
-elf_sym_set_visibility(elf_symtab_entry *entry,
- elf_symbol_vis vis)
-{
- entry->vis = ELF_ST_VISIBILITY(vis);
-}
-
-void
-elf_sym_set_type(elf_symtab_entry *entry,
- elf_symbol_type type)
-{
- entry->type = type;
-}
-
-void
-elf_sym_set_size(elf_symtab_entry *entry,
- struct yasm_expr *size)
-{
- if (entry->xsize)
- yasm_expr_destroy(entry->xsize);
- entry->xsize = size;
-}
-
-int
-elf_sym_in_table(elf_symtab_entry *entry)
-{
- return entry->in_table;
-}
-
-elf_secthead *
-elf_secthead_create(elf_strtab_entry *name,
- elf_section_type type,
- elf_section_flags flags,
- elf_address offset,
- elf_size size)
-{
- elf_secthead *esd = yasm_xmalloc(sizeof(elf_secthead));
-
- esd->type = type;
- esd->flags = flags;
- esd->offset = offset;
- esd->size = yasm_intnum_create_uint(size);
- esd->link = 0;
- esd->info = 0;
- esd->align = 0;
- esd->entsize = 0;
- esd->index = 0;
-
- esd->sym = NULL;
- esd->name = name;
- esd->index = 0;
- esd->rel_name = NULL;
- esd->rel_index = 0;
- esd->rel_offset = 0;
- esd->nreloc = 0;
-
- if (name && (strcmp(name->str, ".symtab") == 0)) {
- if (!elf_march->symtab_entry_size || !elf_march->symtab_entry_align)
- yasm_internal_error(N_("unsupported ELF format"));
- esd->entsize = elf_march->symtab_entry_size;
- esd->align = elf_march->symtab_entry_align;
- }
-
- return esd;
-}
-
-void
-elf_secthead_destroy(elf_secthead *shead)
-{
- if (shead == NULL)
- yasm_internal_error(N_("shead is null"));
-
- yasm_intnum_destroy(shead->size);
-
- yasm_xfree(shead);
-}
-
-static void
-elf_section_data_destroy(void *data)
-{
- elf_secthead_destroy((elf_secthead *)data);
-}
-
-static void
-elf_secthead_print(void *data, FILE *f, int indent_level)
-{
- elf_secthead *sect = data;
- fprintf(f, "%*sname=%s\n", indent_level, "",
- sect->name ? sect->name->str : "<undef>");
- fprintf(f, "%*ssym=\n", indent_level, "");
- yasm_symrec_print(sect->sym, f, indent_level+1);
- fprintf(f, "%*sindex=0x%x\n", indent_level, "", sect->index);
- fprintf(f, "%*sflags=", indent_level, "");
- if (sect->flags & SHF_WRITE)
- fprintf(f, "WRITE ");
- if (sect->flags & SHF_ALLOC)
- fprintf(f, "ALLOC ");
- if (sect->flags & SHF_EXECINSTR)
- fprintf(f, "EXEC ");
- /*if (sect->flags & SHF_MASKPROC)
- fprintf(f, "PROC-SPECIFIC"); */
- fprintf(f, "%*soffset=0x%lx\n", indent_level, "", sect->offset);
- fprintf(f, "%*ssize=0x%lx\n", indent_level, "",
- yasm_intnum_get_uint(sect->size));
- fprintf(f, "%*slink=0x%x\n", indent_level, "", sect->link);
- fprintf(f, "%*salign=%lu\n", indent_level, "", sect->align);
- fprintf(f, "%*snreloc=%ld\n", indent_level, "", sect->nreloc);
-}
-
-unsigned long
-elf_secthead_write_to_file(FILE *f, elf_secthead *shead,
- elf_section_index sindex)
-{
- unsigned char buf[SHDR_MAXSIZE], *bufp = buf;
- shead->index = sindex;
-
- if (shead == NULL)
- yasm_internal_error("shead is null");
-
- if (!elf_march->write_secthead || !elf_march->secthead_size)
- yasm_internal_error(N_("Unsupported machine for ELF output"));
- elf_march->write_secthead(bufp, shead);
- if (fwrite(buf, elf_march->secthead_size, 1, f))
- return elf_march->secthead_size;
- yasm_internal_error(N_("Failed to write an elf section header"));
- return 0;
-}
-
-void
-elf_secthead_append_reloc(yasm_section *sect, elf_secthead *shead,
- elf_reloc_entry *reloc)
-{
- if (sect == NULL)
- yasm_internal_error("sect is null");
- if (shead == NULL)
- yasm_internal_error("shead is null");
- if (reloc == NULL)
- yasm_internal_error("reloc is null");
-
- shead->nreloc++;
- yasm_section_add_reloc(sect, (yasm_reloc *)reloc, elf_reloc_entry_destroy);
-}
-
-char *
-elf_secthead_name_reloc_section(const char *basesect)
-{
- if (!elf_march->reloc_section_prefix)
- {
- yasm_internal_error(N_("Unsupported machine for ELF output"));
- return NULL;
- }
- else
- {
- size_t prepend_length = strlen(elf_march->reloc_section_prefix);
- char *sectname = yasm_xmalloc(prepend_length + strlen(basesect) + 1);
- strcpy(sectname, elf_march->reloc_section_prefix);
- strcat(sectname, basesect);
- return sectname;
- }
-}
-
-void
-elf_handle_reloc_addend(yasm_intnum *intn,
- elf_reloc_entry *reloc,
- unsigned long offset)
-{
- if (!elf_march->handle_reloc_addend)
- yasm_internal_error(N_("Unsupported machine for ELF output"));
- elf_march->handle_reloc_addend(intn, reloc, offset);
-}
-
-unsigned long
-elf_secthead_write_rel_to_file(FILE *f, elf_section_index symtab_idx,
- yasm_section *sect, elf_secthead *shead,
- elf_section_index sindex)
-{
- unsigned char buf[SHDR_MAXSIZE], *bufp = buf;
-
- if (shead == NULL)
- yasm_internal_error("shead is null");
-
- if (!yasm_section_relocs_first(sect))
- return 0; /* no relocations, no .rel.* section header */
-
- shead->rel_index = sindex;
-
- if (!elf_march->write_secthead_rel || !elf_march->secthead_size)
- yasm_internal_error(N_("Unsupported machine for ELF output"));
- elf_march->write_secthead_rel(bufp, shead, symtab_idx, sindex);
- if (fwrite(buf, elf_march->secthead_size, 1, f))
- return elf_march->secthead_size;
- yasm_internal_error(N_("Failed to write an elf section header"));
- return 0;
-}
-
-unsigned long
-elf_secthead_write_relocs_to_file(FILE *f, yasm_section *sect,
- elf_secthead *shead, yasm_errwarns *errwarns)
-{
- elf_reloc_entry *reloc;
- unsigned char buf[RELOC_MAXSIZE], *bufp;
- unsigned long size = 0;
- long pos;
-
- if (shead == NULL)
- yasm_internal_error("shead is null");
-
- reloc = (elf_reloc_entry *)yasm_section_relocs_first(sect);
- if (!reloc)
- return 0;
-
- /* first align section to multiple of 4 */
- pos = ftell(f);
- if (pos == -1) {
- yasm_error_set(YASM_ERROR_IO,
- N_("couldn't read position on output stream"));
- yasm_errwarn_propagate(errwarns, 0);
- }
- pos = (pos + 3) & ~3;
- if (fseek(f, pos, SEEK_SET) < 0) {
- yasm_error_set(YASM_ERROR_IO, N_("couldn't seek on output stream"));
- yasm_errwarn_propagate(errwarns, 0);
- }
- shead->rel_offset = (unsigned long)pos;
-
-
- while (reloc) {
- unsigned int r_type=0, r_sym;
- elf_symtab_entry *esym;
-
- esym = yasm_symrec_get_data(reloc->reloc.sym, &elf_symrec_data);
- if (esym)
- r_sym = esym->symindex;
- else
- r_sym = STN_UNDEF;
-
- if (!elf_march->map_reloc_info_to_type)
- yasm_internal_error(N_("Unsupported arch/machine for elf output"));
- r_type = elf_march->map_reloc_info_to_type(reloc);
-
- bufp = buf;
- if (!elf_march->write_reloc || !elf_march->reloc_entry_size)
- yasm_internal_error(N_("Unsupported arch/machine for elf output"));
- elf_march->write_reloc(bufp, reloc, r_type, r_sym);
- fwrite(buf, elf_march->reloc_entry_size, 1, f);
- size += elf_march->reloc_entry_size;
-
- reloc = (elf_reloc_entry *)
- yasm_section_reloc_next((yasm_reloc *)reloc);
- }
- return size;
-}
-
-elf_section_type
-elf_secthead_get_type(elf_secthead *shead)
-{
- return shead->type;
-}
-
-void
-elf_secthead_set_typeflags(elf_secthead *shead, elf_section_type type,
- elf_section_flags flags)
-{
- shead->type = type;
- shead->flags = flags;
-}
-
-int
-elf_secthead_is_empty(elf_secthead *shead)
-{
- return yasm_intnum_is_zero(shead->size);
-}
-
-yasm_symrec *
-elf_secthead_get_sym(elf_secthead *shead)
-{
- return shead->sym;
-}
-
-elf_section_index
-elf_secthead_get_index(elf_secthead *shead)
-{
- return shead->index;
-}
-
-unsigned long
-elf_secthead_get_align(const elf_secthead *shead)
-{
- return shead->align;
-}
-
-unsigned long
-elf_secthead_set_align(elf_secthead *shead, unsigned long align)
-{
- return shead->align = align;
-}
-
-elf_section_info
-elf_secthead_set_info(elf_secthead *shead, elf_section_info info)
-{
- return shead->info = info;
-}
-
-elf_section_index
-elf_secthead_set_index(elf_secthead *shead, elf_section_index sectidx)
-{
- return shead->index = sectidx;
-}
-
-elf_section_index
-elf_secthead_set_link(elf_secthead *shead, elf_section_index link)
-{
- return shead->link = link;
-}
-
-elf_section_index
-elf_secthead_set_rel_index(elf_secthead *shead, elf_section_index sectidx)
-{
- return shead->rel_index = sectidx;
-}
-
-elf_strtab_entry *
-elf_secthead_set_rel_name(elf_secthead *shead, elf_strtab_entry *entry)
-{
- return shead->rel_name = entry;
-}
-
-elf_size
-elf_secthead_set_entsize(elf_secthead *shead, elf_size size)
-{
- return shead->entsize = size;
-}
-
-yasm_symrec *
-elf_secthead_set_sym(elf_secthead *shead, yasm_symrec *sym)
-{
- return shead->sym = sym;
-}
-
-void
-elf_secthead_add_size(elf_secthead *shead, yasm_intnum *size)
-{
- if (size) {
- yasm_intnum_calc(shead->size, YASM_EXPR_ADD, size);
- }
-}
-
-long
-elf_secthead_set_file_offset(elf_secthead *shead, long pos)
-{
- unsigned long align = shead->align;
-
- if (align == 0 || align == 1) {
- shead->offset = (unsigned long)pos;
- return pos;
- }
- else if (align & (align - 1))
- yasm_internal_error(
- N_("alignment %d for section `%s' is not a power of 2"));
- /*, align, sect->name->str);*/
-
- shead->offset = (unsigned long)((pos + align - 1) & ~(align - 1));
- return (long)shead->offset;
-}
-
-unsigned long
-elf_proghead_get_size(void)
-{
- if (!elf_march->proghead_size)
- yasm_internal_error(N_("Unsupported ELF format for output"));
- return elf_march->proghead_size;
-}
-
-unsigned long
-elf_proghead_write_to_file(FILE *f,
- elf_offset secthead_addr,
- unsigned long secthead_count,
- elf_section_index shstrtab_index)
-{
- unsigned char buf[EHDR_MAXSIZE], *bufp = buf;
-
- YASM_WRITE_8(bufp, ELFMAG0); /* ELF magic number */
- YASM_WRITE_8(bufp, ELFMAG1);
- YASM_WRITE_8(bufp, ELFMAG2);
- YASM_WRITE_8(bufp, ELFMAG3);
-
- if (!elf_march->write_proghead || !elf_march->proghead_size)
- yasm_internal_error(N_("Unsupported ELF format for output"));
- elf_march->write_proghead(&bufp, secthead_addr, secthead_count, shstrtab_index);
-
- if (((unsigned)(bufp - buf)) != elf_march->proghead_size)
- yasm_internal_error(N_("ELF program header is not proper length"));
-
- if (fwrite(buf, elf_march->proghead_size, 1, f))
- return elf_march->proghead_size;
-
- yasm_internal_error(N_("Failed to write ELF program header"));
- return 0;
-}
+/*
+ * ELF object format helpers
+ *
+ * Copyright (C) 2003-2007 Michael Urman
+ *
+ * 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>
+
+#include <libyasm.h>
+#define YASM_OBJFMT_ELF_INTERNAL
+#include "elf.h"
+#include "elf-machine.h"
+
+static void elf_section_data_destroy(void *data);
+static void elf_secthead_print(void *data, FILE *f, int indent_level);
+
+const yasm_assoc_data_callback elf_section_data = {
+ elf_section_data_destroy,
+ elf_secthead_print
+};
+
+static void elf_symrec_data_destroy(/*@only@*/ void *d);
+static void elf_symtab_entry_print(void *data, FILE *f, int indent_level);
+static void elf_ssym_symtab_entry_print(void *data, FILE *f, int indent_level);
+
+const yasm_assoc_data_callback elf_symrec_data = {
+ elf_symrec_data_destroy,
+ elf_symtab_entry_print
+};
+
+const yasm_assoc_data_callback elf_ssym_symrec_data = {
+ elf_symrec_data_destroy,
+ elf_ssym_symtab_entry_print
+};
+
+extern elf_machine_handler
+ elf_machine_handler_x86_x86,
+ elf_machine_handler_x86_amd64,
+ elf_machine_handler_x86_x32;
+
+static const elf_machine_handler *elf_machine_handlers[] =
+{
+ &elf_machine_handler_x86_x86,
+ &elf_machine_handler_x86_amd64,
+ &elf_machine_handler_x86_x32,
+ NULL
+};
+static const elf_machine_handler elf_null_machine = {0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0};
+static elf_machine_handler const *elf_march = &elf_null_machine;
+static yasm_symrec **elf_ssyms;
+
+const elf_machine_handler *
+elf_set_arch(yasm_arch *arch, yasm_symtab *symtab, int bits_pref)
+{
+ const char *machine = yasm_arch_get_machine(arch);
+ int i;
+
+ for (i=0, elf_march = elf_machine_handlers[0];
+ elf_march != NULL;
+ elf_march = elf_machine_handlers[++i])
+ {
+ if (yasm__strcasecmp(yasm_arch_keyword(arch), elf_march->arch)==0) {
+ if (yasm__strcasecmp(machine, elf_march->machine)==0) {
+ if (bits_pref == 0 || bits_pref == elf_march->bits)
+ break;
+ } else if (bits_pref == elf_march->bits
+ && yasm__strcasecmp(machine, "amd64") == 0
+ && yasm__strcasecmp(elf_march->machine, "x32") == 0)
+ break;
+ }
+ }
+
+ if (elf_march && elf_march->num_ssyms > 0)
+ {
+ /* Allocate "special" syms */
+ elf_ssyms =
+ yasm_xmalloc(elf_march->num_ssyms * sizeof(yasm_symrec *));
+ for (i=0; (unsigned int)i<elf_march->num_ssyms; i++)
+ {
+ /* FIXME: misuse of NULL bytecode */
+ elf_ssyms[i] = yasm_symtab_define_label(symtab,
+ elf_march->ssyms[i].name,
+ NULL, 0, 0);
+ yasm_symrec_add_data(elf_ssyms[i], &elf_ssym_symrec_data,
+ (void*)&elf_march->ssyms[i]);
+ }
+ }
+
+ return elf_march;
+}
+
+yasm_symrec *
+elf_get_special_sym(const char *name, const char *parser)
+{
+ int i;
+ for (i=0; (unsigned int)i<elf_march->num_ssyms; i++) {
+ if (yasm__strcasecmp(name, elf_march->ssyms[i].name) == 0)
+ return elf_ssyms[i];
+ }
+ return NULL;
+}
+
+/* reloc functions */
+int elf_ssym_has_flag(yasm_symrec *wrt, int flag);
+
+int
+elf_is_wrt_sym_relative(yasm_symrec *wrt)
+{
+ return elf_ssym_has_flag(wrt, ELF_SSYM_SYM_RELATIVE);
+}
+
+int
+elf_is_wrt_pos_adjusted(yasm_symrec *wrt)
+{
+ return elf_ssym_has_flag(wrt, ELF_SSYM_CURPOS_ADJUST);
+}
+
+int
+elf_ssym_has_flag(yasm_symrec *wrt, int flag)
+{
+ int i;
+ for (i=0; (unsigned int)i<elf_march->num_ssyms; i++) {
+ if (elf_ssyms[i] == wrt)
+ return (elf_march->ssyms[i].sym_rel & flag) != 0;
+ }
+ return 0;
+}
+
+/* takes ownership of addr */
+elf_reloc_entry *
+elf_reloc_entry_create(yasm_symrec *sym,
+ yasm_symrec *wrt,
+ yasm_intnum *addr,
+ int rel,
+ size_t valsize,
+ int is_GOT_sym)
+{
+ elf_reloc_entry *entry;
+
+ if (!elf_march->accepts_reloc)
+ yasm_internal_error(N_("Unsupported machine for ELF output"));
+
+ if (!elf_march->accepts_reloc(valsize, wrt))
+ {
+ if (addr)
+ yasm_intnum_destroy(addr);
+ return NULL;
+ }
+
+ if (sym == NULL)
+ yasm_internal_error("sym is null");
+
+ entry = yasm_xmalloc(sizeof(elf_reloc_entry));
+ entry->reloc.sym = sym;
+ entry->reloc.addr = addr;
+ entry->rtype_rel = rel;
+ entry->valsize = valsize;
+ entry->addend = NULL;
+ entry->wrt = wrt;
+ entry->is_GOT_sym = is_GOT_sym;
+
+ return entry;
+}
+
+void
+elf_reloc_entry_destroy(void *entry)
+{
+ if (((elf_reloc_entry*)entry)->addend)
+ yasm_intnum_destroy(((elf_reloc_entry*)entry)->addend);
+ yasm_xfree(entry);
+}
+
+/* strtab functions */
+elf_strtab_entry *
+elf_strtab_entry_create(const char *str)
+{
+ elf_strtab_entry *entry = yasm_xmalloc(sizeof(elf_strtab_entry));
+ entry->str = yasm__xstrdup(str);
+ entry->index = 0;
+ return entry;
+}
+
+void
+elf_strtab_entry_set_str(elf_strtab_entry *entry, const char *str)
+{
+ elf_strtab_entry *last;
+ if (entry->str)
+ yasm_xfree(entry->str);
+ entry->str = yasm__xstrdup(str);
+
+ /* Update all following indices since string length probably changes */
+ last = entry;
+ entry = STAILQ_NEXT(last, qlink);
+ while (entry) {
+ entry->index = last->index + (unsigned long)strlen(last->str) + 1;
+ last = entry;
+ entry = STAILQ_NEXT(last, qlink);
+ }
+}
+
+elf_strtab_head *
+elf_strtab_create()
+{
+ elf_strtab_head *strtab = yasm_xmalloc(sizeof(elf_strtab_head));
+ elf_strtab_entry *entry = yasm_xmalloc(sizeof(elf_strtab_entry));
+
+ STAILQ_INIT(strtab);
+ entry->index = 0;
+ entry->str = yasm__xstrdup("");
+
+ STAILQ_INSERT_TAIL(strtab, entry, qlink);
+ return strtab;
+}
+
+elf_strtab_entry *
+elf_strtab_append_str(elf_strtab_head *strtab, const char *str)
+{
+ elf_strtab_entry *last, *entry;
+
+ if (strtab == NULL)
+ yasm_internal_error("strtab is null");
+ if (STAILQ_EMPTY(strtab))
+ yasm_internal_error("strtab is missing initial dummy entry");
+
+ last = STAILQ_LAST(strtab, elf_strtab_entry, qlink);
+
+ entry = elf_strtab_entry_create(str);
+ entry->index = last->index + (unsigned long)strlen(last->str) + 1;
+
+ STAILQ_INSERT_TAIL(strtab, entry, qlink);
+ return entry;
+}
+
+void
+elf_strtab_destroy(elf_strtab_head *strtab)
+{
+ elf_strtab_entry *s1, *s2;
+
+ if (strtab == NULL)
+ yasm_internal_error("strtab is null");
+ if (STAILQ_EMPTY(strtab))
+ yasm_internal_error("strtab is missing initial dummy entry");
+
+ s1 = STAILQ_FIRST(strtab);
+ while (s1 != NULL) {
+ s2 = STAILQ_NEXT(s1, qlink);
+ yasm_xfree(s1->str);
+ yasm_xfree(s1);
+ s1 = s2;
+ }
+ yasm_xfree(strtab);
+}
+
+unsigned long
+elf_strtab_output_to_file(FILE *f, elf_strtab_head *strtab)
+{
+ unsigned long size = 0;
+ elf_strtab_entry *entry;
+
+ if (strtab == NULL)
+ yasm_internal_error("strtab is null");
+
+ /* consider optimizing tables here */
+ STAILQ_FOREACH(entry, strtab, qlink) {
+ size_t len = 1 + strlen(entry->str);
+ fwrite(entry->str, len, 1, f);
+ size += (unsigned long)len;
+ }
+ return size;
+}
+
+
+
+/* symtab functions */
+elf_symtab_entry *
+elf_symtab_entry_create(elf_strtab_entry *name,
+ yasm_symrec *sym)
+{
+ elf_symtab_entry *entry = yasm_xmalloc(sizeof(elf_symtab_entry));
+ entry->in_table = 0;
+ entry->sym = sym;
+ entry->sect = NULL;
+ entry->name = name;
+ entry->value = 0;
+
+ entry->xsize = NULL;
+ entry->size = 0;
+ entry->index = 0;
+ entry->bind = 0;
+ entry->type = STT_NOTYPE;
+ entry->vis = STV_DEFAULT;
+
+ return entry;
+}
+
+static void
+elf_symtab_entry_destroy(elf_symtab_entry *entry)
+{
+ if (entry == NULL)
+ yasm_internal_error("symtab entry is null");
+
+ yasm_xfree(entry);
+}
+
+static void
+elf_symrec_data_destroy(void *data)
+{
+ /* do nothing, as this stuff is in the symtab anyway... this speaks of bad
+ * design/use or this stuff, i fear */
+
+ /* watch for double-free here ... */
+ /*elf_symtab_entry_destroy((elf_symtab_entry *)data);*/
+}
+
+static void
+elf_symtab_entry_print(void *data, FILE *f, int indent_level)
+{
+ elf_symtab_entry *entry = data;
+ if (entry == NULL)
+ yasm_internal_error("symtab entry is null");
+
+ fprintf(f, "%*sbind=", indent_level, "");
+ switch (entry->bind) {
+ case STB_LOCAL: fprintf(f, "local\n"); break;
+ case STB_GLOBAL: fprintf(f, "global\n"); break;
+ case STB_WEAK: fprintf(f, "weak\n"); break;
+ default: fprintf(f, "undef\n"); break;
+ }
+ fprintf(f, "%*stype=", indent_level, "");
+ switch (entry->type) {
+ case STT_NOTYPE: fprintf(f, "notype\n"); break;
+ case STT_OBJECT: fprintf(f, "object\n"); break;
+ case STT_FUNC: fprintf(f, "func\n"); break;
+ case STT_SECTION: fprintf(f, "section\n");break;
+ case STT_FILE: fprintf(f, "file\n"); break;
+ default: fprintf(f, "undef\n"); break;
+ }
+ fprintf(f, "%*ssize=", indent_level, "");
+ if (entry->xsize)
+ yasm_expr_print(entry->xsize, f);
+ else
+ fprintf(f, "%ld", entry->size);
+ fprintf(f, "\n");
+}
+
+static void
+elf_ssym_symtab_entry_print(void *data, FILE *f, int indent_level)
+{
+ /* TODO */
+}
+
+elf_symtab_head *
+elf_symtab_create()
+{
+ elf_symtab_head *symtab = yasm_xmalloc(sizeof(elf_symtab_head));
+ elf_symtab_entry *entry = yasm_xmalloc(sizeof(elf_symtab_entry));
+
+ STAILQ_INIT(symtab);
+ entry->in_table = 1;
+ entry->sym = NULL;
+ entry->sect = NULL;
+ entry->name = NULL;
+ entry->value = 0;
+ entry->xsize = NULL;
+ entry->size = 0;
+ entry->index = SHN_UNDEF;
+ entry->bind = STB_LOCAL;
+ entry->type = STT_NOTYPE;
+ entry->vis = STV_DEFAULT;
+ entry->symindex = 0;
+ STAILQ_INSERT_TAIL(symtab, entry, qlink);
+ return symtab;
+}
+
+void
+elf_symtab_append_entry(elf_symtab_head *symtab, elf_symtab_entry *entry)
+{
+ if (symtab == NULL)
+ yasm_internal_error("symtab is null");
+ if (entry == NULL)
+ yasm_internal_error("symtab entry is null");
+ if (STAILQ_EMPTY(symtab))
+ yasm_internal_error(N_("symtab is missing initial dummy entry"));
+
+ STAILQ_INSERT_TAIL(symtab, entry, qlink);
+ entry->in_table = 1;
+}
+
+void
+elf_symtab_insert_local_sym(elf_symtab_head *symtab, elf_symtab_entry *entry)
+{
+ elf_symtab_entry *after = STAILQ_FIRST(symtab);
+ elf_symtab_entry *before = NULL;
+
+ while (after && (after->bind == STB_LOCAL)) {
+ before = after;
+ if (before->type == STT_FILE) break;
+ after = STAILQ_NEXT(after, qlink);
+ }
+ STAILQ_INSERT_AFTER(symtab, before, entry, qlink);
+ entry->in_table = 1;
+}
+
+void
+elf_symtab_destroy(elf_symtab_head *symtab)
+{
+ elf_symtab_entry *s1, *s2;
+
+ if (symtab == NULL)
+ yasm_internal_error("symtab is null");
+ if (STAILQ_EMPTY(symtab))
+ yasm_internal_error(N_("symtab is missing initial dummy entry"));
+
+ s1 = STAILQ_FIRST(symtab);
+ while (s1 != NULL) {
+ s2 = STAILQ_NEXT(s1, qlink);
+ elf_symtab_entry_destroy(s1);
+ s1 = s2;
+ }
+ yasm_xfree(symtab);
+}
+
+unsigned long
+elf_symtab_assign_indices(elf_symtab_head *symtab)
+{
+ elf_symtab_entry *entry, *prev=NULL;
+ unsigned long last_local=0;
+
+ if (symtab == NULL)
+ yasm_internal_error("symtab is null");
+ if (STAILQ_EMPTY(symtab))
+ yasm_internal_error(N_("symtab is missing initial dummy entry"));
+
+ STAILQ_FOREACH(entry, symtab, qlink) {
+ if (prev)
+ entry->symindex = prev->symindex + 1;
+ if (entry->bind == STB_LOCAL)
+ last_local = entry->symindex;
+ prev = entry;
+ }
+ return last_local + 1;
+}
+
+unsigned long
+elf_symtab_write_to_file(FILE *f, elf_symtab_head *symtab,
+ yasm_errwarns *errwarns)
+{
+ unsigned char buf[SYMTAB_MAXSIZE], *bufp;
+ elf_symtab_entry *entry;
+ unsigned long size = 0;
+
+ if (!symtab)
+ yasm_internal_error(N_("symtab is null"));
+
+ STAILQ_FOREACH(entry, symtab, qlink) {
+
+ yasm_intnum *size_intn=NULL, *value_intn=NULL;
+ bufp = buf;
+
+ /* get size (if specified); expr overrides stored integer */
+ if (entry->xsize) {
+ size_intn = yasm_intnum_copy(
+ yasm_expr_get_intnum(&entry->xsize, 1));
+ if (!size_intn) {
+ yasm_error_set(YASM_ERROR_VALUE,
+ N_("size specifier not an integer expression"));
+ yasm_errwarn_propagate(errwarns, entry->xsize->line);
+ }
+ }
+ else
+ size_intn = yasm_intnum_create_uint(entry->size);
+
+ /* get EQU value for constants */
+ if (entry->sym) {
+ const yasm_expr *equ_expr_c;
+ equ_expr_c = yasm_symrec_get_equ(entry->sym);
+
+ if (equ_expr_c != NULL) {
+ const yasm_intnum *equ_intn;
+ yasm_expr *equ_expr = yasm_expr_copy(equ_expr_c);
+ equ_intn = yasm_expr_get_intnum(&equ_expr, 1);
+
+ if (equ_intn == NULL) {
+ yasm_error_set(YASM_ERROR_VALUE,
+ N_("EQU value not an integer expression"));
+ yasm_errwarn_propagate(errwarns, equ_expr->line);
+ } else
+ value_intn = yasm_intnum_copy(equ_intn);
+ entry->index = SHN_ABS;
+ yasm_expr_destroy(equ_expr);
+ }
+ }
+ if (value_intn == NULL)
+ value_intn = yasm_intnum_create_uint(entry->value);
+
+ /* If symbol is in a TLS section, force its type to TLS. */
+ if (entry->sym) {
+ yasm_bytecode *precbc;
+ yasm_section *sect;
+ elf_secthead *shead;
+ if (yasm_symrec_get_label(entry->sym, &precbc) &&
+ (sect = yasm_bc_get_section(precbc)) &&
+ (shead = yasm_section_get_data(sect, &elf_section_data)) &&
+ shead->flags & SHF_TLS) {
+ entry->type = STT_TLS;
+ }
+ }
+
+ if (!elf_march->write_symtab_entry || !elf_march->symtab_entry_size)
+ yasm_internal_error(N_("Unsupported machine for ELF output"));
+ elf_march->write_symtab_entry(bufp, entry, value_intn, size_intn);
+ fwrite(buf, elf_march->symtab_entry_size, 1, f);
+ size += elf_march->symtab_entry_size;
+
+ yasm_intnum_destroy(size_intn);
+ yasm_intnum_destroy(value_intn);
+ }
+ return size;
+}
+
+void elf_symtab_set_nonzero(elf_symtab_entry *entry,
+ yasm_section *sect,
+ elf_section_index sectidx,
+ elf_symbol_binding bind,
+ elf_symbol_type type,
+ yasm_expr *xsize,
+ elf_address *value)
+{
+ if (!entry)
+ yasm_internal_error("NULL entry");
+ if (sect) entry->sect = sect;
+ if (sectidx) entry->index = sectidx;
+ if (bind) entry->bind = bind;
+ if (type) entry->type = type;
+ if (xsize) entry->xsize = xsize;
+ if (value) entry->value = *value;
+}
+
+void
+elf_sym_set_visibility(elf_symtab_entry *entry,
+ elf_symbol_vis vis)
+{
+ entry->vis = ELF_ST_VISIBILITY(vis);
+}
+
+void
+elf_sym_set_type(elf_symtab_entry *entry,
+ elf_symbol_type type)
+{
+ entry->type = type;
+}
+
+void
+elf_sym_set_size(elf_symtab_entry *entry,
+ struct yasm_expr *size)
+{
+ if (entry->xsize)
+ yasm_expr_destroy(entry->xsize);
+ entry->xsize = size;
+}
+
+int
+elf_sym_in_table(elf_symtab_entry *entry)
+{
+ return entry->in_table;
+}
+
+elf_secthead *
+elf_secthead_create(elf_strtab_entry *name,
+ elf_section_type type,
+ elf_section_flags flags,
+ elf_address offset,
+ elf_size size)
+{
+ elf_secthead *esd = yasm_xmalloc(sizeof(elf_secthead));
+
+ esd->type = type;
+ esd->flags = flags;
+ esd->offset = offset;
+ esd->size = yasm_intnum_create_uint(size);
+ esd->link = 0;
+ esd->info = 0;
+ esd->align = 0;
+ esd->entsize = 0;
+ esd->index = 0;
+
+ esd->sym = NULL;
+ esd->name = name;
+ esd->index = 0;
+ esd->rel_name = NULL;
+ esd->rel_index = 0;
+ esd->rel_offset = 0;
+ esd->nreloc = 0;
+
+ if (name && (strcmp(name->str, ".symtab") == 0)) {
+ if (!elf_march->symtab_entry_size || !elf_march->symtab_entry_align)
+ yasm_internal_error(N_("unsupported ELF format"));
+ esd->entsize = elf_march->symtab_entry_size;
+ esd->align = elf_march->symtab_entry_align;
+ }
+
+ return esd;
+}
+
+void
+elf_secthead_destroy(elf_secthead *shead)
+{
+ if (shead == NULL)
+ yasm_internal_error(N_("shead is null"));
+
+ yasm_intnum_destroy(shead->size);
+
+ yasm_xfree(shead);
+}
+
+static void
+elf_section_data_destroy(void *data)
+{
+ elf_secthead_destroy((elf_secthead *)data);
+}
+
+static void
+elf_secthead_print(void *data, FILE *f, int indent_level)
+{
+ elf_secthead *sect = data;
+ fprintf(f, "%*sname=%s\n", indent_level, "",
+ sect->name ? sect->name->str : "<undef>");
+ fprintf(f, "%*ssym=\n", indent_level, "");
+ yasm_symrec_print(sect->sym, f, indent_level+1);
+ fprintf(f, "%*sindex=0x%x\n", indent_level, "", sect->index);
+ fprintf(f, "%*sflags=", indent_level, "");
+ if (sect->flags & SHF_WRITE)
+ fprintf(f, "WRITE ");
+ if (sect->flags & SHF_ALLOC)
+ fprintf(f, "ALLOC ");
+ if (sect->flags & SHF_EXECINSTR)
+ fprintf(f, "EXEC ");
+ /*if (sect->flags & SHF_MASKPROC)
+ fprintf(f, "PROC-SPECIFIC"); */
+ fprintf(f, "%*soffset=0x%lx\n", indent_level, "", sect->offset);
+ fprintf(f, "%*ssize=0x%lx\n", indent_level, "",
+ yasm_intnum_get_uint(sect->size));
+ fprintf(f, "%*slink=0x%x\n", indent_level, "", sect->link);
+ fprintf(f, "%*salign=%lu\n", indent_level, "", sect->align);
+ fprintf(f, "%*snreloc=%ld\n", indent_level, "", sect->nreloc);
+}
+
+unsigned long
+elf_secthead_write_to_file(FILE *f, elf_secthead *shead,
+ elf_section_index sindex)
+{
+ unsigned char buf[SHDR_MAXSIZE], *bufp = buf;
+ shead->index = sindex;
+
+ if (shead == NULL)
+ yasm_internal_error("shead is null");
+
+ if (!elf_march->write_secthead || !elf_march->secthead_size)
+ yasm_internal_error(N_("Unsupported machine for ELF output"));
+ elf_march->write_secthead(bufp, shead);
+ if (fwrite(buf, elf_march->secthead_size, 1, f))
+ return elf_march->secthead_size;
+ yasm_internal_error(N_("Failed to write an elf section header"));
+ return 0;
+}
+
+void
+elf_secthead_append_reloc(yasm_section *sect, elf_secthead *shead,
+ elf_reloc_entry *reloc)
+{
+ if (sect == NULL)
+ yasm_internal_error("sect is null");
+ if (shead == NULL)
+ yasm_internal_error("shead is null");
+ if (reloc == NULL)
+ yasm_internal_error("reloc is null");
+
+ shead->nreloc++;
+ yasm_section_add_reloc(sect, (yasm_reloc *)reloc, elf_reloc_entry_destroy);
+}
+
+char *
+elf_secthead_name_reloc_section(const char *basesect)
+{
+ if (!elf_march->reloc_section_prefix)
+ {
+ yasm_internal_error(N_("Unsupported machine for ELF output"));
+ return NULL;
+ }
+ else
+ {
+ size_t prepend_length = strlen(elf_march->reloc_section_prefix);
+ char *sectname = yasm_xmalloc(prepend_length + strlen(basesect) + 1);
+ strcpy(sectname, elf_march->reloc_section_prefix);
+ strcat(sectname, basesect);
+ return sectname;
+ }
+}
+
+void
+elf_handle_reloc_addend(yasm_intnum *intn,
+ elf_reloc_entry *reloc,
+ unsigned long offset)
+{
+ if (!elf_march->handle_reloc_addend)
+ yasm_internal_error(N_("Unsupported machine for ELF output"));
+ elf_march->handle_reloc_addend(intn, reloc, offset);
+}
+
+unsigned long
+elf_secthead_write_rel_to_file(FILE *f, elf_section_index symtab_idx,
+ yasm_section *sect, elf_secthead *shead,
+ elf_section_index sindex)
+{
+ unsigned char buf[SHDR_MAXSIZE], *bufp = buf;
+
+ if (shead == NULL)
+ yasm_internal_error("shead is null");
+
+ if (!yasm_section_relocs_first(sect))
+ return 0; /* no relocations, no .rel.* section header */
+
+ shead->rel_index = sindex;
+
+ if (!elf_march->write_secthead_rel || !elf_march->secthead_size)
+ yasm_internal_error(N_("Unsupported machine for ELF output"));
+ elf_march->write_secthead_rel(bufp, shead, symtab_idx, sindex);
+ if (fwrite(buf, elf_march->secthead_size, 1, f))
+ return elf_march->secthead_size;
+ yasm_internal_error(N_("Failed to write an elf section header"));
+ return 0;
+}
+
+unsigned long
+elf_secthead_write_relocs_to_file(FILE *f, yasm_section *sect,
+ elf_secthead *shead, yasm_errwarns *errwarns)
+{
+ elf_reloc_entry *reloc;
+ unsigned char buf[RELOC_MAXSIZE], *bufp;
+ unsigned long size = 0;
+ long pos;
+
+ if (shead == NULL)
+ yasm_internal_error("shead is null");
+
+ reloc = (elf_reloc_entry *)yasm_section_relocs_first(sect);
+ if (!reloc)
+ return 0;
+
+ /* first align section to multiple of 4 */
+ pos = ftell(f);
+ if (pos == -1) {
+ yasm_error_set(YASM_ERROR_IO,
+ N_("couldn't read position on output stream"));
+ yasm_errwarn_propagate(errwarns, 0);
+ }
+ pos = (pos + 3) & ~3;
+ if (fseek(f, pos, SEEK_SET) < 0) {
+ yasm_error_set(YASM_ERROR_IO, N_("couldn't seek on output stream"));
+ yasm_errwarn_propagate(errwarns, 0);
+ }
+ shead->rel_offset = (unsigned long)pos;
+
+
+ while (reloc) {
+ unsigned int r_type=0, r_sym;
+ elf_symtab_entry *esym;
+
+ esym = yasm_symrec_get_data(reloc->reloc.sym, &elf_symrec_data);
+ if (esym)
+ r_sym = esym->symindex;
+ else
+ r_sym = STN_UNDEF;
+
+ if (!elf_march->map_reloc_info_to_type)
+ yasm_internal_error(N_("Unsupported arch/machine for elf output"));
+ r_type = elf_march->map_reloc_info_to_type(reloc);
+
+ bufp = buf;
+ if (!elf_march->write_reloc || !elf_march->reloc_entry_size)
+ yasm_internal_error(N_("Unsupported arch/machine for elf output"));
+ elf_march->write_reloc(bufp, reloc, r_type, r_sym);
+ fwrite(buf, elf_march->reloc_entry_size, 1, f);
+ size += elf_march->reloc_entry_size;
+
+ reloc = (elf_reloc_entry *)
+ yasm_section_reloc_next((yasm_reloc *)reloc);
+ }
+ return size;
+}
+
+elf_section_type
+elf_secthead_get_type(elf_secthead *shead)
+{
+ return shead->type;
+}
+
+void
+elf_secthead_set_typeflags(elf_secthead *shead, elf_section_type type,
+ elf_section_flags flags)
+{
+ shead->type = type;
+ shead->flags = flags;
+}
+
+int
+elf_secthead_is_empty(elf_secthead *shead)
+{
+ return yasm_intnum_is_zero(shead->size);
+}
+
+yasm_symrec *
+elf_secthead_get_sym(elf_secthead *shead)
+{
+ return shead->sym;
+}
+
+elf_section_index
+elf_secthead_get_index(elf_secthead *shead)
+{
+ return shead->index;
+}
+
+unsigned long
+elf_secthead_get_align(const elf_secthead *shead)
+{
+ return shead->align;
+}
+
+unsigned long
+elf_secthead_set_align(elf_secthead *shead, unsigned long align)
+{
+ return shead->align = align;
+}
+
+elf_section_info
+elf_secthead_set_info(elf_secthead *shead, elf_section_info info)
+{
+ return shead->info = info;
+}
+
+elf_section_index
+elf_secthead_set_index(elf_secthead *shead, elf_section_index sectidx)
+{
+ return shead->index = sectidx;
+}
+
+elf_section_index
+elf_secthead_set_link(elf_secthead *shead, elf_section_index link)
+{
+ return shead->link = link;
+}
+
+elf_section_index
+elf_secthead_set_rel_index(elf_secthead *shead, elf_section_index sectidx)
+{
+ return shead->rel_index = sectidx;
+}
+
+elf_strtab_entry *
+elf_secthead_set_rel_name(elf_secthead *shead, elf_strtab_entry *entry)
+{
+ return shead->rel_name = entry;
+}
+
+elf_size
+elf_secthead_set_entsize(elf_secthead *shead, elf_size size)
+{
+ return shead->entsize = size;
+}
+
+yasm_symrec *
+elf_secthead_set_sym(elf_secthead *shead, yasm_symrec *sym)
+{
+ return shead->sym = sym;
+}
+
+void
+elf_secthead_add_size(elf_secthead *shead, yasm_intnum *size)
+{
+ if (size) {
+ yasm_intnum_calc(shead->size, YASM_EXPR_ADD, size);
+ }
+}
+
+long
+elf_secthead_set_file_offset(elf_secthead *shead, long pos)
+{
+ unsigned long align = shead->align;
+
+ if (align == 0 || align == 1) {
+ shead->offset = (unsigned long)pos;
+ return pos;
+ }
+ else if (align & (align - 1))
+ yasm_internal_error(
+ N_("alignment %d for section `%s' is not a power of 2"));
+ /*, align, sect->name->str);*/
+
+ shead->offset = (unsigned long)((pos + align - 1) & ~(align - 1));
+ return (long)shead->offset;
+}
+
+unsigned long
+elf_proghead_get_size(void)
+{
+ if (!elf_march->proghead_size)
+ yasm_internal_error(N_("Unsupported ELF format for output"));
+ return elf_march->proghead_size;
+}
+
+unsigned long
+elf_proghead_write_to_file(FILE *f,
+ elf_offset secthead_addr,
+ unsigned long secthead_count,
+ elf_section_index shstrtab_index)
+{
+ unsigned char buf[EHDR_MAXSIZE], *bufp = buf;
+
+ YASM_WRITE_8(bufp, ELFMAG0); /* ELF magic number */
+ YASM_WRITE_8(bufp, ELFMAG1);
+ YASM_WRITE_8(bufp, ELFMAG2);
+ YASM_WRITE_8(bufp, ELFMAG3);
+
+ if (!elf_march->write_proghead || !elf_march->proghead_size)
+ yasm_internal_error(N_("Unsupported ELF format for output"));
+ elf_march->write_proghead(&bufp, secthead_addr, secthead_count, shstrtab_index);
+
+ if (((unsigned)(bufp - buf)) != elf_march->proghead_size)
+ yasm_internal_error(N_("ELF program header is not proper length"));
+
+ if (fwrite(buf, elf_march->proghead_size, 1, f))
+ return elf_march->proghead_size;
+
+ yasm_internal_error(N_("Failed to write ELF program header"));
+ return 0;
+}
diff --git a/contrib/tools/yasm/modules/objfmts/elf/elf.h b/contrib/tools/yasm/modules/objfmts/elf/elf.h
index fce629ae45..73498477e8 100644
--- a/contrib/tools/yasm/modules/objfmts/elf/elf.h
+++ b/contrib/tools/yasm/modules/objfmts/elf/elf.h
@@ -1,532 +1,532 @@
-/*
- * ELF object format helpers
- *
- * Copyright (C) 2003-2007 Michael Urman
- *
- * 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.
- */
-
-#ifndef ELF_H_INCLUDED
-#define ELF_H_INCLUDED
-
-typedef struct elf_reloc_entry elf_reloc_entry;
-typedef struct elf_reloc_head elf_reloc_head;
-typedef struct elf_secthead elf_secthead;
-typedef struct elf_strtab_entry elf_strtab_entry;
-typedef struct elf_strtab_head elf_strtab_head;
-typedef struct elf_symtab_entry elf_symtab_entry;
-typedef struct elf_symtab_head elf_symtab_head;
-
-typedef struct elf_machine_handler elf_machine_handler;
-
-typedef unsigned long elf_address;
-typedef unsigned long elf_offset;
-typedef unsigned long elf_size;
-typedef unsigned long elf_section_info;
-
-typedef enum {
- ET_NONE = 0,
- ET_REL = 1, /* Relocatable */
- ET_EXEC = 2, /* Executable */
- ET_DYN = 3, /* Shared object */
- ET_CORE = 4, /* Core */
- ET_LOOS = 0xfe00, /* Environment specific */
- ET_HIOS = 0xfeff,
- ET_LOPROC = 0xff00, /* Processor specific */
- ET_HIPROC = 0xffff
-} elf_file_type;
-
-typedef enum {
- EM_NONE = 0,
- EM_M32 = 1, /* AT&T WE 32100 */
- EM_SPARC = 2, /* SPARC */
- EM_386 = 3, /* Intel 80386 */
- EM_68K = 4, /* Motorola 68000 */
- EM_88K = 5, /* Motorola 88000 */
- EM_860 = 7, /* Intel 80860 */
- EM_MIPS = 8, /* MIPS RS3000 */
-
- EM_S370 = 9, /* IBM System/370 */
- EM_MIPS_RS4_BE = 10, /* MIPS R4000 Big-Endian (dep)*/
- EM_PARISC = 15, /* HPPA */
- EM_SPARC32PLUS = 18, /* SPARC v8plus */
- EM_PPC = 20, /* PowerPC 32-bit */
- EM_PPC64 = 21, /* PowerPC 64-bit */
- EM_ARM = 40, /* ARM */
- EM_SPARCV9 = 43, /* SPARC v9 64-bit */
- EM_IA_64 = 50, /* Intel IA-64 */
- EM_X86_64 = 62, /* AMD x86-64 */
- EM_ALPHA = 0x9026 /* Alpha (no ABI) */
-} elf_machine;
-
-typedef enum {
- ELFMAG0 = 0x7f,
- ELFMAG1 = 0x45,
- ELFMAG2 = 0x4c,
- ELFMAG3 = 0x46
-} elf_magic;
-
-typedef enum {
- EV_NONE = 0, /* invalid */
- EV_CURRENT = 1 /* current */
-} elf_version;
-
-typedef enum {
- EI_MAG0 = 0, /* File id */
- EI_MAG1 = 1,
- EI_MAG2 = 2,
- EI_MAG3 = 3,
- EI_CLASS = 4, /* File class */
- EI_DATA = 5, /* Data encoding */
- EI_VERSION = 6, /* File version */
- EI_OSABI = 7, /* OS and ABI */
- EI_ABIVERSION = 8, /* version of ABI */
-
- EI_PAD = 9, /* Pad to end; start here */
- EI_NIDENT = 16 /* Sizeof e_ident[] */
-} elf_identification_index;
-
-typedef enum {
- ELFOSABI_SYSV = 0, /* System V ABI */
- ELFOSABI_HPUX = 1, /* HP-UX os */
- ELFOSABI_STANDALONE = 255 /* Standalone / embedded app */
-} elf_osabi_index;
-
-typedef enum {
- ELFCLASSNONE = 0, /* invalid */
- ELFCLASS32 = 1, /* 32-bit */
- ELFCLASS64 = 2 /* 64-bit */
-} elf_class;
-
-typedef enum {
- ELFDATANONE = 0,
- ELFDATA2LSB = 1,
- ELFDATA2MSB = 2
-} elf_data_encoding;
-
-/* elf section types - index of semantics */
-typedef enum {
- SHT_NULL = 0, /* inactive section - no associated data */
- SHT_PROGBITS = 1, /* defined by program for its own meaning */
- SHT_SYMTAB = 2, /* symbol table (primarily) for linking */
- SHT_STRTAB = 3, /* string table - symbols need names */
- SHT_RELA = 4, /* relocation entries w/ explicit addends */
- SHT_HASH = 5, /* symbol hash table - for dynamic linking */
- SHT_DYNAMIC = 6, /* information for dynamic linking */
- SHT_NOTE = 7, /* extra data marking the file somehow */
- SHT_NOBITS = 8, /* no stored data, but occupies runtime space */
- SHT_REL = 9, /* relocations entries w/o explicit addends */
- SHT_SHLIB = 10, /* reserved; unspecified semantics */
- SHT_DYNSYM = 11, /* like symtab, but more for dynamic linking */
-
- SHT_LOOS = 0x60000000, /* reserved for environment specific use */
- SHT_HIOS = 0x6fffffff,
- SHT_LOPROC = 0x70000000, /* reserved for processor specific semantics */
- SHT_HIPROC = 0x7fffffff/*,
- SHT_LOUSER = 0x80000000,*/ /* reserved for applications; safe */
- /*SHT_HIUSER = 0xffffffff*/
-} elf_section_type;
-
-/* elf section flags - bitfield of attributes */
-typedef enum {
- SHF_WRITE = 0x1, /* data should be writable at runtime */
- SHF_ALLOC = 0x2, /* occupies memory at runtime */
- SHF_EXECINSTR = 0x4, /* contains machine instructions */
- SHF_MERGE = 0x10, /* data can be merged */
- SHF_STRINGS = 0x20, /* contains 0-terminated strings */
- SHF_GROUP = 0x200, /* member of a section group */
- SHF_TLS = 0x400, /* thread local storage */
- SHF_MASKOS = 0x0f000000/*,*//* environment specific use */
- /*SHF_MASKPROC = 0xf0000000*/ /* bits reserved for processor specific needs */
-} elf_section_flags;
-
-/* elf section index - just the special ones */
-typedef enum {
- SHN_UNDEF = 0, /* undefined symbol; requires other global */
- SHN_LORESERVE = 0xff00, /* reserved for various semantics */
- SHN_LOPROC = 0xff00, /* reserved for processor specific semantics */
- SHN_HIPROC = 0xff1f,
- SHN_LOOS = 0xff20, /* reserved for environment specific use */
- SHN_HIOS = 0xff3f,
- SHN_ABS = 0xfff1, /* associated symbols don't change on reloc */
- SHN_COMMON = 0xfff2, /* associated symbols refer to unallocated */
- SHN_HIRESERVE = 0xffff
-} elf_section_index;
-
-/* elf symbol binding - index of visibility/behavior */
-typedef enum {
- STB_LOCAL = 0, /* invisible outside defining file */
- STB_GLOBAL = 1, /* visible to all combined object files */
- STB_WEAK = 2, /* global but lower precedence */
-
- STB_LOOS = 10, /* Environment specific use */
- STB_HIOS = 12,
- STB_LOPROC = 13, /* reserved for processor specific semantics */
- STB_HIPROC = 15
-} elf_symbol_binding;
-
-/* elf symbol type - index of classifications */
-typedef enum {
- STT_NOTYPE = 0, /* type not specified */
- STT_OBJECT = 1, /* data object such as a variable, array, etc */
- STT_FUNC = 2, /* a function or executable code */
- STT_SECTION = 3, /* a section: often for relocation, STB_LOCAL */
- STT_FILE = 4, /* often source filename: STB_LOCAL, SHN_ABS */
- STT_COMMON = 5, /* Uninitialized common block. */
- STT_TLS = 6, /* TLS object. */
- STT_NUM = 7,
-
- STT_LOOS = 10, /* Environment specific use */
- STT_HIOS = 12,
- STT_LOPROC = 13, /* reserved for processor specific semantics */
- STT_HIPROC = 15
-} elf_symbol_type;
-
-typedef enum {
- STN_UNDEF = 0
-} elf_symbol_index;
-
-/* elf symbol visibility - lower two bits of OTHER field */
-typedef enum {
- STV_DEFAULT = 0, /* Default symbol visibility rules */
- STV_INTERNAL = 1, /* Processor specific hidden class */
- STV_HIDDEN = 2, /* Sym unavailable in other modules */
- STV_PROTECTED = 3 /* Not preemptable, not exported */
-} elf_symbol_vis;
-
-
-/* internal only object definitions */
-#ifdef YASM_OBJFMT_ELF_INTERNAL
-
-#define ELF_VISIBILITY_MASK 0x03
-#define ELF_ST_VISIBILITY(v) ((v) & ELF_VISIBILITY_MASK)
-
-#define ELF32_ST_INFO(bind, type) (((bind) << 4) + ((type) & 0xf))
-#define ELF32_R_INFO(s,t) (((s)<<8)+(unsigned char)(t))
-#define ELF32_ST_OTHER(vis) ELF_ST_VISIBILITY(vis)
-
-#define ELF64_ST_INFO(bind, type) (((bind) << 4) + ((type) & 0xf))
-#define ELF64_R_INFO(s,t) (((s)<<32) + ((t) & 0xffffffffL))
-#define ELF64_ST_OTHER(vis) ELF_ST_VISIBILITY(vis)
-
-#define EHDR32_SIZE 52
-#define EHDR64_SIZE 64
-#define EHDR_MAXSIZE 64
-
-#define SHDR32_SIZE 40
-#define SHDR64_SIZE 64
-#define SHDR_MAXSIZE 64
-
-#define SYMTAB32_SIZE 16
-#define SYMTAB64_SIZE 24
-#define SYMTAB_MAXSIZE 24
-
-#define SYMTAB32_ALIGN 4
-#define SYMTAB64_ALIGN 8
-
-#define RELOC32_SIZE 8
-#define RELOC32A_SIZE 12
-#define RELOC64_SIZE 16
-#define RELOC64A_SIZE 24
-#define RELOC_MAXSIZE 24
-
-#define RELOC32_ALIGN 4
-#define RELOC64_ALIGN 8
-
-
-/* elf relocation type - index of semantics
- *
- * A = Addend (r_addend for RELA, value at location for REL)
- * B = Base address
- * G = Offset into global offset table (GOT)
- * GOT = Address of the global offset table (GOT)
- * L = Location of procedure linkage table (PLT)
- * P = Location of location being relocated (r_offset)
- * S = Value of symbol
- */
-typedef enum {
- R_386_NONE = 0, /* none */
- R_386_32 = 1, /* word32, S + A */
- R_386_PC32 = 2, /* word32, S + A - P */
- R_386_GOT32 = 3, /* word32, G + A - P */
- R_386_PLT32 = 4, /* word32, L + A - P */
- R_386_COPY = 5, /* none */
- R_386_GLOB_DAT = 6, /* word32, S */
- R_386_JMP_SLOT = 7, /* word32, S */
- R_386_RELATIVE = 8, /* word32, B + A */
- R_386_GOTOFF = 9, /* word32, S + A - GOT */
- R_386_GOTPC = 10, /* word32, GOT + A - P */
- R_386_TLS_TPOFF = 14, /* Negative offset in static TLS block (GNU
- version) */
- R_386_TLS_IE = 15, /* Absolute address of GOT entry for negative
- static TLS block offset */
- R_386_TLS_GOTIE = 16, /* GOT entry for negative static TLS block
- offset */
- R_386_TLS_LE = 17, /* Negative offset relative to static TLS
- (GNU version) */
- R_386_TLS_GD = 18, /* Direct 32 bit for GNU version of GD TLS */
- R_386_TLS_LDM = 19, /* Direct 32 bit for GNU version of LD TLS
- in LE code */
- R_386_16 = 20, /* word16, S + A (GNU extension) */
- R_386_PC16 = 21, /* word16, S + A - P (GNU extension) */
- R_386_8 = 22, /* word8, S + A (GNU extension) */
- R_386_PC8 = 23, /* word8, S + A - P (GNU extension) */
- R_386_TLS_GD_32 = 24, /* Direct 32 bit for GD TLS */
- R_386_TLS_GD_PUSH = 25, /* Tag for pushl in GD TLS code */
- R_386_TLS_GD_CALL = 26, /* Relocation for call to */
- R_386_TLS_GD_POP = 27, /* Tag for popl in GD TLS code */
- R_386_TLS_LDM_32 = 28, /* Direct 32 bit for local dynamic code */
- R_386_TLS_LDM_PUSH = 29, /* Tag for pushl in LDM TLS code */
- R_386_TLS_LDM_CALL = 30, /* Relocation for call to */
- R_386_TLS_LDM_POP = 31, /* Tag for popl in LDM TLS code */
- R_386_TLS_LDO_32 = 32, /* Offset relative to TLS block */
- R_386_TLS_IE_32 = 33, /* GOT entry for static TLS block */
- R_386_TLS_LE_32 = 34, /* Offset relative to static TLS block */
- R_386_TLS_DTPMOD32 = 35, /* ID of module containing symbol */
- R_386_TLS_DTPOFF32 = 36, /* Offset in TLS block */
- R_386_TLS_TPOFF32 = 37, /* Offset in static TLS block */
- R_386_TLS_GOTDESC = 39,
- R_386_TLS_DESC_CALL = 40,
- R_386_TLS_DESC = 41
-} elf_386_relocation_type;
-
-typedef enum {
- R_X86_64_NONE = 0, /* none */
- R_X86_64_64 = 1, /* word64, S + A */
- R_X86_64_PC32 = 2, /* word32, S + A - P */
- R_X86_64_GOT32 = 3, /* word32, G + A */
- R_X86_64_PLT32 = 4, /* word32, L + A - P */
- R_X86_64_COPY = 5, /* none */
- R_X86_64_GLOB_DAT = 6, /* word64, S, set GOT entry to data address */
- R_X86_64_JMP_SLOT = 7, /* word64, S, set GOT entry to code address */
- R_X86_64_RELATIVE = 8, /* word64, B + A */
- R_X86_64_GOTPCREL = 9, /* word32, G + GOT + A - P */
- R_X86_64_32 = 10, /* word32 (zero extend), S + A */
- R_X86_64_32S = 11, /* word32 (sign extend), S + A */
- R_X86_64_16 = 12, /* word16, S + A */
- R_X86_64_PC16 = 13, /* word16, S + A - P */
- R_X86_64_8 = 14, /* word8, S + A */
- R_X86_64_PC8 = 15, /* word8, S + A - P */
- R_X86_64_DPTMOD64 = 16, /* word64, ID of module containing symbol */
- R_X86_64_DTPOFF64 = 17, /* word64, offset in TLS block */
- R_X86_64_TPOFF64 = 18, /* word64, offset in initial TLS block */
- R_X86_64_TLSGD = 19, /* word32, PC-rel offset to GD GOT block */
- R_X86_64_TLSLD = 20, /* word32, PC-rel offset to LD GOT block */
- R_X86_64_DTPOFF32 = 21, /* word32, offset to TLS block */
- R_X86_64_GOTTPOFF = 22, /* word32, PC-rel offset to IE GOT entry */
- R_X86_64_TPOFF32 = 23, /* word32, offset in initial TLS block */
- R_X86_64_PC64 = 24, /* word64, PC relative */
- R_X86_64_GOTOFF64 = 25, /* word64, offset to GOT */
- R_X86_64_GOTPC32 = 26, /* word32, signed pc relative to GOT */
- R_X86_64_GOT64 = 27, /* word64, GOT entry offset */
- R_X86_64_GOTPCREL64 = 28, /* word64, signed pc relative to GOT entry */
- R_X86_64_GOTPC64 = 29, /* word64, signed pc relative to GOT */
- R_X86_64_GOTPLT64 = 30, /* like GOT64, but indicates PLT entry needed */
- R_X86_64_PLTOFF64 = 31, /* word64, GOT relative offset to PLT entry */
- R_X86_64_GOTPC32_TLSDESC = 34, /* GOT offset for TLS descriptor */
- R_X86_64_TLSDESC_CALL = 35, /* Marker for call through TLS descriptor */
- R_X86_64_TLSDESC = 36 /* TLS descriptor */
-} elf_x86_64_relocation_type;
-
-struct elf_secthead {
- elf_section_type type;
- elf_section_flags flags;
- elf_address offset;
- yasm_intnum *size;
- elf_section_index link;
- elf_section_info info; /* see note ESD1 */
- unsigned long align;
- elf_size entsize;
-
- yasm_symrec *sym;
- elf_strtab_entry *name;
- elf_section_index index;
-
- elf_strtab_entry *rel_name;
- elf_section_index rel_index;
- elf_address rel_offset;
- unsigned long nreloc;
-};
-
-/* Note ESD1:
- * for section types SHT_REL, SHT_RELA:
- * link -> index of associated symbol table
- * info -> index of relocated section
- * for section types SHT_SYMTAB, SHT_DYNSYM:
- * link -> index of associated string table
- * info -> 1+index of last "local symbol" (bind == STB_LOCAL)
- * (for section type SHT_DNAMIC:
- * link -> index of string table
- * info -> 0 )
- * (for section type SHT_HASH:
- * link -> index of symbol table to which hash applies
- * info -> 0 )
- * for all others:
- * link -> SHN_UNDEF
- * info -> 0
- */
-
-struct elf_reloc_entry {
- yasm_reloc reloc;
- int rtype_rel;
- size_t valsize;
- yasm_intnum *addend;
- /*@null@*/ yasm_symrec *wrt;
- int is_GOT_sym;
-};
-
-STAILQ_HEAD(elf_strtab_head, elf_strtab_entry);
-struct elf_strtab_entry {
- STAILQ_ENTRY(elf_strtab_entry) qlink;
- unsigned long index;
- char *str;
-};
-
-STAILQ_HEAD(elf_symtab_head, elf_symtab_entry);
-struct elf_symtab_entry {
- STAILQ_ENTRY(elf_symtab_entry) qlink;
- int in_table;
- yasm_symrec *sym;
- yasm_section *sect;
- elf_strtab_entry *name;
- elf_address value;
- /*@dependent@*/ yasm_expr *xsize;
- elf_size size;
- elf_section_index index;
- elf_symbol_binding bind;
- elf_symbol_type type;
- elf_symbol_vis vis;
- elf_symbol_index symindex;
-};
-
-#endif /* defined(YASM_OBJFMT_ELF_INTERNAL) */
-
-extern const yasm_assoc_data_callback elf_section_data;
-extern const yasm_assoc_data_callback elf_symrec_data;
-extern const yasm_assoc_data_callback elf_ssym_symrec_data;
-
-
-const elf_machine_handler *elf_set_arch(struct yasm_arch *arch,
- yasm_symtab *symtab,
- int bits_pref);
-
-yasm_symrec *elf_get_special_sym(const char *name, const char *parser);
-
-/* reloc functions */
-int elf_is_wrt_sym_relative(yasm_symrec *wrt);
-int elf_is_wrt_pos_adjusted(yasm_symrec *wrt);
-elf_reloc_entry *elf_reloc_entry_create(yasm_symrec *sym,
- /*@null@*/ yasm_symrec *wrt,
- yasm_intnum *addr,
- int rel,
- size_t valsize,
- int is_GOT_sym);
-void elf_reloc_entry_destroy(void *entry);
-
-/* strtab functions */
-elf_strtab_entry *elf_strtab_entry_create(const char *str);
-void elf_strtab_entry_set_str(elf_strtab_entry *entry, const char *str);
-elf_strtab_head *elf_strtab_create(void);
-elf_strtab_entry *elf_strtab_append_str(elf_strtab_head *head, const char *str);
-void elf_strtab_destroy(elf_strtab_head *head);
-unsigned long elf_strtab_output_to_file(FILE *f, elf_strtab_head *head);
-
-/* symtab functions */
-elf_symtab_entry *elf_symtab_entry_create(elf_strtab_entry *name,
- struct yasm_symrec *sym);
-elf_symtab_head *elf_symtab_create(void);
-void elf_symtab_append_entry(elf_symtab_head *symtab, elf_symtab_entry *entry);
-void elf_symtab_insert_local_sym(elf_symtab_head *symtab,
- elf_symtab_entry *entry);
-void elf_symtab_destroy(elf_symtab_head *head);
-unsigned long elf_symtab_assign_indices(elf_symtab_head *symtab);
-unsigned long elf_symtab_write_to_file(FILE *f, elf_symtab_head *symtab,
- yasm_errwarns *errwarns);
-void elf_symtab_set_nonzero(elf_symtab_entry *entry,
- struct yasm_section *sect,
- elf_section_index sectidx,
- elf_symbol_binding bind,
- elf_symbol_type type,
- struct yasm_expr *size,
- elf_address *value);
-void elf_sym_set_visibility(elf_symtab_entry *entry,
- elf_symbol_vis vis);
-void elf_sym_set_type(elf_symtab_entry *entry, elf_symbol_type type);
-void elf_sym_set_size(elf_symtab_entry *entry, struct yasm_expr *size);
-int elf_sym_in_table(elf_symtab_entry *entry);
-
-/* section header functions */
-elf_secthead *elf_secthead_create(elf_strtab_entry *name,
- elf_section_type type,
- elf_section_flags flags,
- elf_address offset,
- elf_size size);
-void elf_secthead_destroy(elf_secthead *esd);
-unsigned long elf_secthead_write_to_file(FILE *f, elf_secthead *esd,
- elf_section_index sindex);
-void elf_secthead_append_reloc(yasm_section *sect, elf_secthead *shead,
- elf_reloc_entry *reloc);
-elf_section_type elf_secthead_get_type(elf_secthead *shead);
-void elf_secthead_set_typeflags(elf_secthead *shead, elf_section_type type,
- elf_section_flags flags);
-int elf_secthead_is_empty(elf_secthead *shead);
-struct yasm_symrec *elf_secthead_get_sym(elf_secthead *shead);
-unsigned long elf_secthead_get_align(const elf_secthead *shead);
-unsigned long elf_secthead_set_align(elf_secthead *shead, unsigned long align);
-elf_section_index elf_secthead_get_index(elf_secthead *shead);
-elf_section_info elf_secthead_set_info(elf_secthead *shead,
- elf_section_info info);
-elf_section_index elf_secthead_set_index(elf_secthead *shead,
- elf_section_index sectidx);
-elf_section_index elf_secthead_set_link(elf_secthead *shead,
- elf_section_index link);
-elf_section_index elf_secthead_set_rel_index(elf_secthead *shead,
- elf_section_index sectidx);
-elf_strtab_entry *elf_secthead_set_rel_name(elf_secthead *shead,
- elf_strtab_entry *entry);
-elf_size elf_secthead_set_entsize(elf_secthead *shead, elf_size size);
-struct yasm_symrec *elf_secthead_set_sym(elf_secthead *shead,
- struct yasm_symrec *sym);
-void elf_secthead_add_size(elf_secthead *shead, yasm_intnum *size);
-char *elf_secthead_name_reloc_section(const char *basesect);
-void elf_handle_reloc_addend(yasm_intnum *intn,
- elf_reloc_entry *reloc,
- unsigned long offset);
-unsigned long elf_secthead_write_rel_to_file(FILE *f, elf_section_index symtab,
- yasm_section *sect,
- elf_secthead *esd,
- elf_section_index sindex);
-unsigned long elf_secthead_write_relocs_to_file(FILE *f, yasm_section *sect,
- elf_secthead *shead,
- yasm_errwarns *errwarns);
-long elf_secthead_set_file_offset(elf_secthead *shead, long pos);
-
-/* program header function */
-unsigned long
-elf_proghead_get_size(void);
-unsigned long
-elf_proghead_write_to_file(FILE *f,
- elf_offset secthead_addr,
- unsigned long secthead_count,
- elf_section_index shstrtab_index);
-
-#endif /* ELF_H_INCLUDED */
+/*
+ * ELF object format helpers
+ *
+ * Copyright (C) 2003-2007 Michael Urman
+ *
+ * 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.
+ */
+
+#ifndef ELF_H_INCLUDED
+#define ELF_H_INCLUDED
+
+typedef struct elf_reloc_entry elf_reloc_entry;
+typedef struct elf_reloc_head elf_reloc_head;
+typedef struct elf_secthead elf_secthead;
+typedef struct elf_strtab_entry elf_strtab_entry;
+typedef struct elf_strtab_head elf_strtab_head;
+typedef struct elf_symtab_entry elf_symtab_entry;
+typedef struct elf_symtab_head elf_symtab_head;
+
+typedef struct elf_machine_handler elf_machine_handler;
+
+typedef unsigned long elf_address;
+typedef unsigned long elf_offset;
+typedef unsigned long elf_size;
+typedef unsigned long elf_section_info;
+
+typedef enum {
+ ET_NONE = 0,
+ ET_REL = 1, /* Relocatable */
+ ET_EXEC = 2, /* Executable */
+ ET_DYN = 3, /* Shared object */
+ ET_CORE = 4, /* Core */
+ ET_LOOS = 0xfe00, /* Environment specific */
+ ET_HIOS = 0xfeff,
+ ET_LOPROC = 0xff00, /* Processor specific */
+ ET_HIPROC = 0xffff
+} elf_file_type;
+
+typedef enum {
+ EM_NONE = 0,
+ EM_M32 = 1, /* AT&T WE 32100 */
+ EM_SPARC = 2, /* SPARC */
+ EM_386 = 3, /* Intel 80386 */
+ EM_68K = 4, /* Motorola 68000 */
+ EM_88K = 5, /* Motorola 88000 */
+ EM_860 = 7, /* Intel 80860 */
+ EM_MIPS = 8, /* MIPS RS3000 */
+
+ EM_S370 = 9, /* IBM System/370 */
+ EM_MIPS_RS4_BE = 10, /* MIPS R4000 Big-Endian (dep)*/
+ EM_PARISC = 15, /* HPPA */
+ EM_SPARC32PLUS = 18, /* SPARC v8plus */
+ EM_PPC = 20, /* PowerPC 32-bit */
+ EM_PPC64 = 21, /* PowerPC 64-bit */
+ EM_ARM = 40, /* ARM */
+ EM_SPARCV9 = 43, /* SPARC v9 64-bit */
+ EM_IA_64 = 50, /* Intel IA-64 */
+ EM_X86_64 = 62, /* AMD x86-64 */
+ EM_ALPHA = 0x9026 /* Alpha (no ABI) */
+} elf_machine;
+
+typedef enum {
+ ELFMAG0 = 0x7f,
+ ELFMAG1 = 0x45,
+ ELFMAG2 = 0x4c,
+ ELFMAG3 = 0x46
+} elf_magic;
+
+typedef enum {
+ EV_NONE = 0, /* invalid */
+ EV_CURRENT = 1 /* current */
+} elf_version;
+
+typedef enum {
+ EI_MAG0 = 0, /* File id */
+ EI_MAG1 = 1,
+ EI_MAG2 = 2,
+ EI_MAG3 = 3,
+ EI_CLASS = 4, /* File class */
+ EI_DATA = 5, /* Data encoding */
+ EI_VERSION = 6, /* File version */
+ EI_OSABI = 7, /* OS and ABI */
+ EI_ABIVERSION = 8, /* version of ABI */
+
+ EI_PAD = 9, /* Pad to end; start here */
+ EI_NIDENT = 16 /* Sizeof e_ident[] */
+} elf_identification_index;
+
+typedef enum {
+ ELFOSABI_SYSV = 0, /* System V ABI */
+ ELFOSABI_HPUX = 1, /* HP-UX os */
+ ELFOSABI_STANDALONE = 255 /* Standalone / embedded app */
+} elf_osabi_index;
+
+typedef enum {
+ ELFCLASSNONE = 0, /* invalid */
+ ELFCLASS32 = 1, /* 32-bit */
+ ELFCLASS64 = 2 /* 64-bit */
+} elf_class;
+
+typedef enum {
+ ELFDATANONE = 0,
+ ELFDATA2LSB = 1,
+ ELFDATA2MSB = 2
+} elf_data_encoding;
+
+/* elf section types - index of semantics */
+typedef enum {
+ SHT_NULL = 0, /* inactive section - no associated data */
+ SHT_PROGBITS = 1, /* defined by program for its own meaning */
+ SHT_SYMTAB = 2, /* symbol table (primarily) for linking */
+ SHT_STRTAB = 3, /* string table - symbols need names */
+ SHT_RELA = 4, /* relocation entries w/ explicit addends */
+ SHT_HASH = 5, /* symbol hash table - for dynamic linking */
+ SHT_DYNAMIC = 6, /* information for dynamic linking */
+ SHT_NOTE = 7, /* extra data marking the file somehow */
+ SHT_NOBITS = 8, /* no stored data, but occupies runtime space */
+ SHT_REL = 9, /* relocations entries w/o explicit addends */
+ SHT_SHLIB = 10, /* reserved; unspecified semantics */
+ SHT_DYNSYM = 11, /* like symtab, but more for dynamic linking */
+
+ SHT_LOOS = 0x60000000, /* reserved for environment specific use */
+ SHT_HIOS = 0x6fffffff,
+ SHT_LOPROC = 0x70000000, /* reserved for processor specific semantics */
+ SHT_HIPROC = 0x7fffffff/*,
+ SHT_LOUSER = 0x80000000,*/ /* reserved for applications; safe */
+ /*SHT_HIUSER = 0xffffffff*/
+} elf_section_type;
+
+/* elf section flags - bitfield of attributes */
+typedef enum {
+ SHF_WRITE = 0x1, /* data should be writable at runtime */
+ SHF_ALLOC = 0x2, /* occupies memory at runtime */
+ SHF_EXECINSTR = 0x4, /* contains machine instructions */
+ SHF_MERGE = 0x10, /* data can be merged */
+ SHF_STRINGS = 0x20, /* contains 0-terminated strings */
+ SHF_GROUP = 0x200, /* member of a section group */
+ SHF_TLS = 0x400, /* thread local storage */
+ SHF_MASKOS = 0x0f000000/*,*//* environment specific use */
+ /*SHF_MASKPROC = 0xf0000000*/ /* bits reserved for processor specific needs */
+} elf_section_flags;
+
+/* elf section index - just the special ones */
+typedef enum {
+ SHN_UNDEF = 0, /* undefined symbol; requires other global */
+ SHN_LORESERVE = 0xff00, /* reserved for various semantics */
+ SHN_LOPROC = 0xff00, /* reserved for processor specific semantics */
+ SHN_HIPROC = 0xff1f,
+ SHN_LOOS = 0xff20, /* reserved for environment specific use */
+ SHN_HIOS = 0xff3f,
+ SHN_ABS = 0xfff1, /* associated symbols don't change on reloc */
+ SHN_COMMON = 0xfff2, /* associated symbols refer to unallocated */
+ SHN_HIRESERVE = 0xffff
+} elf_section_index;
+
+/* elf symbol binding - index of visibility/behavior */
+typedef enum {
+ STB_LOCAL = 0, /* invisible outside defining file */
+ STB_GLOBAL = 1, /* visible to all combined object files */
+ STB_WEAK = 2, /* global but lower precedence */
+
+ STB_LOOS = 10, /* Environment specific use */
+ STB_HIOS = 12,
+ STB_LOPROC = 13, /* reserved for processor specific semantics */
+ STB_HIPROC = 15
+} elf_symbol_binding;
+
+/* elf symbol type - index of classifications */
+typedef enum {
+ STT_NOTYPE = 0, /* type not specified */
+ STT_OBJECT = 1, /* data object such as a variable, array, etc */
+ STT_FUNC = 2, /* a function or executable code */
+ STT_SECTION = 3, /* a section: often for relocation, STB_LOCAL */
+ STT_FILE = 4, /* often source filename: STB_LOCAL, SHN_ABS */
+ STT_COMMON = 5, /* Uninitialized common block. */
+ STT_TLS = 6, /* TLS object. */
+ STT_NUM = 7,
+
+ STT_LOOS = 10, /* Environment specific use */
+ STT_HIOS = 12,
+ STT_LOPROC = 13, /* reserved for processor specific semantics */
+ STT_HIPROC = 15
+} elf_symbol_type;
+
+typedef enum {
+ STN_UNDEF = 0
+} elf_symbol_index;
+
+/* elf symbol visibility - lower two bits of OTHER field */
+typedef enum {
+ STV_DEFAULT = 0, /* Default symbol visibility rules */
+ STV_INTERNAL = 1, /* Processor specific hidden class */
+ STV_HIDDEN = 2, /* Sym unavailable in other modules */
+ STV_PROTECTED = 3 /* Not preemptable, not exported */
+} elf_symbol_vis;
+
+
+/* internal only object definitions */
+#ifdef YASM_OBJFMT_ELF_INTERNAL
+
+#define ELF_VISIBILITY_MASK 0x03
+#define ELF_ST_VISIBILITY(v) ((v) & ELF_VISIBILITY_MASK)
+
+#define ELF32_ST_INFO(bind, type) (((bind) << 4) + ((type) & 0xf))
+#define ELF32_R_INFO(s,t) (((s)<<8)+(unsigned char)(t))
+#define ELF32_ST_OTHER(vis) ELF_ST_VISIBILITY(vis)
+
+#define ELF64_ST_INFO(bind, type) (((bind) << 4) + ((type) & 0xf))
+#define ELF64_R_INFO(s,t) (((s)<<32) + ((t) & 0xffffffffL))
+#define ELF64_ST_OTHER(vis) ELF_ST_VISIBILITY(vis)
+
+#define EHDR32_SIZE 52
+#define EHDR64_SIZE 64
+#define EHDR_MAXSIZE 64
+
+#define SHDR32_SIZE 40
+#define SHDR64_SIZE 64
+#define SHDR_MAXSIZE 64
+
+#define SYMTAB32_SIZE 16
+#define SYMTAB64_SIZE 24
+#define SYMTAB_MAXSIZE 24
+
+#define SYMTAB32_ALIGN 4
+#define SYMTAB64_ALIGN 8
+
+#define RELOC32_SIZE 8
+#define RELOC32A_SIZE 12
+#define RELOC64_SIZE 16
+#define RELOC64A_SIZE 24
+#define RELOC_MAXSIZE 24
+
+#define RELOC32_ALIGN 4
+#define RELOC64_ALIGN 8
+
+
+/* elf relocation type - index of semantics
+ *
+ * A = Addend (r_addend for RELA, value at location for REL)
+ * B = Base address
+ * G = Offset into global offset table (GOT)
+ * GOT = Address of the global offset table (GOT)
+ * L = Location of procedure linkage table (PLT)
+ * P = Location of location being relocated (r_offset)
+ * S = Value of symbol
+ */
+typedef enum {
+ R_386_NONE = 0, /* none */
+ R_386_32 = 1, /* word32, S + A */
+ R_386_PC32 = 2, /* word32, S + A - P */
+ R_386_GOT32 = 3, /* word32, G + A - P */
+ R_386_PLT32 = 4, /* word32, L + A - P */
+ R_386_COPY = 5, /* none */
+ R_386_GLOB_DAT = 6, /* word32, S */
+ R_386_JMP_SLOT = 7, /* word32, S */
+ R_386_RELATIVE = 8, /* word32, B + A */
+ R_386_GOTOFF = 9, /* word32, S + A - GOT */
+ R_386_GOTPC = 10, /* word32, GOT + A - P */
+ R_386_TLS_TPOFF = 14, /* Negative offset in static TLS block (GNU
+ version) */
+ R_386_TLS_IE = 15, /* Absolute address of GOT entry for negative
+ static TLS block offset */
+ R_386_TLS_GOTIE = 16, /* GOT entry for negative static TLS block
+ offset */
+ R_386_TLS_LE = 17, /* Negative offset relative to static TLS
+ (GNU version) */
+ R_386_TLS_GD = 18, /* Direct 32 bit for GNU version of GD TLS */
+ R_386_TLS_LDM = 19, /* Direct 32 bit for GNU version of LD TLS
+ in LE code */
+ R_386_16 = 20, /* word16, S + A (GNU extension) */
+ R_386_PC16 = 21, /* word16, S + A - P (GNU extension) */
+ R_386_8 = 22, /* word8, S + A (GNU extension) */
+ R_386_PC8 = 23, /* word8, S + A - P (GNU extension) */
+ R_386_TLS_GD_32 = 24, /* Direct 32 bit for GD TLS */
+ R_386_TLS_GD_PUSH = 25, /* Tag for pushl in GD TLS code */
+ R_386_TLS_GD_CALL = 26, /* Relocation for call to */
+ R_386_TLS_GD_POP = 27, /* Tag for popl in GD TLS code */
+ R_386_TLS_LDM_32 = 28, /* Direct 32 bit for local dynamic code */
+ R_386_TLS_LDM_PUSH = 29, /* Tag for pushl in LDM TLS code */
+ R_386_TLS_LDM_CALL = 30, /* Relocation for call to */
+ R_386_TLS_LDM_POP = 31, /* Tag for popl in LDM TLS code */
+ R_386_TLS_LDO_32 = 32, /* Offset relative to TLS block */
+ R_386_TLS_IE_32 = 33, /* GOT entry for static TLS block */
+ R_386_TLS_LE_32 = 34, /* Offset relative to static TLS block */
+ R_386_TLS_DTPMOD32 = 35, /* ID of module containing symbol */
+ R_386_TLS_DTPOFF32 = 36, /* Offset in TLS block */
+ R_386_TLS_TPOFF32 = 37, /* Offset in static TLS block */
+ R_386_TLS_GOTDESC = 39,
+ R_386_TLS_DESC_CALL = 40,
+ R_386_TLS_DESC = 41
+} elf_386_relocation_type;
+
+typedef enum {
+ R_X86_64_NONE = 0, /* none */
+ R_X86_64_64 = 1, /* word64, S + A */
+ R_X86_64_PC32 = 2, /* word32, S + A - P */
+ R_X86_64_GOT32 = 3, /* word32, G + A */
+ R_X86_64_PLT32 = 4, /* word32, L + A - P */
+ R_X86_64_COPY = 5, /* none */
+ R_X86_64_GLOB_DAT = 6, /* word64, S, set GOT entry to data address */
+ R_X86_64_JMP_SLOT = 7, /* word64, S, set GOT entry to code address */
+ R_X86_64_RELATIVE = 8, /* word64, B + A */
+ R_X86_64_GOTPCREL = 9, /* word32, G + GOT + A - P */
+ R_X86_64_32 = 10, /* word32 (zero extend), S + A */
+ R_X86_64_32S = 11, /* word32 (sign extend), S + A */
+ R_X86_64_16 = 12, /* word16, S + A */
+ R_X86_64_PC16 = 13, /* word16, S + A - P */
+ R_X86_64_8 = 14, /* word8, S + A */
+ R_X86_64_PC8 = 15, /* word8, S + A - P */
+ R_X86_64_DPTMOD64 = 16, /* word64, ID of module containing symbol */
+ R_X86_64_DTPOFF64 = 17, /* word64, offset in TLS block */
+ R_X86_64_TPOFF64 = 18, /* word64, offset in initial TLS block */
+ R_X86_64_TLSGD = 19, /* word32, PC-rel offset to GD GOT block */
+ R_X86_64_TLSLD = 20, /* word32, PC-rel offset to LD GOT block */
+ R_X86_64_DTPOFF32 = 21, /* word32, offset to TLS block */
+ R_X86_64_GOTTPOFF = 22, /* word32, PC-rel offset to IE GOT entry */
+ R_X86_64_TPOFF32 = 23, /* word32, offset in initial TLS block */
+ R_X86_64_PC64 = 24, /* word64, PC relative */
+ R_X86_64_GOTOFF64 = 25, /* word64, offset to GOT */
+ R_X86_64_GOTPC32 = 26, /* word32, signed pc relative to GOT */
+ R_X86_64_GOT64 = 27, /* word64, GOT entry offset */
+ R_X86_64_GOTPCREL64 = 28, /* word64, signed pc relative to GOT entry */
+ R_X86_64_GOTPC64 = 29, /* word64, signed pc relative to GOT */
+ R_X86_64_GOTPLT64 = 30, /* like GOT64, but indicates PLT entry needed */
+ R_X86_64_PLTOFF64 = 31, /* word64, GOT relative offset to PLT entry */
+ R_X86_64_GOTPC32_TLSDESC = 34, /* GOT offset for TLS descriptor */
+ R_X86_64_TLSDESC_CALL = 35, /* Marker for call through TLS descriptor */
+ R_X86_64_TLSDESC = 36 /* TLS descriptor */
+} elf_x86_64_relocation_type;
+
+struct elf_secthead {
+ elf_section_type type;
+ elf_section_flags flags;
+ elf_address offset;
+ yasm_intnum *size;
+ elf_section_index link;
+ elf_section_info info; /* see note ESD1 */
+ unsigned long align;
+ elf_size entsize;
+
+ yasm_symrec *sym;
+ elf_strtab_entry *name;
+ elf_section_index index;
+
+ elf_strtab_entry *rel_name;
+ elf_section_index rel_index;
+ elf_address rel_offset;
+ unsigned long nreloc;
+};
+
+/* Note ESD1:
+ * for section types SHT_REL, SHT_RELA:
+ * link -> index of associated symbol table
+ * info -> index of relocated section
+ * for section types SHT_SYMTAB, SHT_DYNSYM:
+ * link -> index of associated string table
+ * info -> 1+index of last "local symbol" (bind == STB_LOCAL)
+ * (for section type SHT_DNAMIC:
+ * link -> index of string table
+ * info -> 0 )
+ * (for section type SHT_HASH:
+ * link -> index of symbol table to which hash applies
+ * info -> 0 )
+ * for all others:
+ * link -> SHN_UNDEF
+ * info -> 0
+ */
+
+struct elf_reloc_entry {
+ yasm_reloc reloc;
+ int rtype_rel;
+ size_t valsize;
+ yasm_intnum *addend;
+ /*@null@*/ yasm_symrec *wrt;
+ int is_GOT_sym;
+};
+
+STAILQ_HEAD(elf_strtab_head, elf_strtab_entry);
+struct elf_strtab_entry {
+ STAILQ_ENTRY(elf_strtab_entry) qlink;
+ unsigned long index;
+ char *str;
+};
+
+STAILQ_HEAD(elf_symtab_head, elf_symtab_entry);
+struct elf_symtab_entry {
+ STAILQ_ENTRY(elf_symtab_entry) qlink;
+ int in_table;
+ yasm_symrec *sym;
+ yasm_section *sect;
+ elf_strtab_entry *name;
+ elf_address value;
+ /*@dependent@*/ yasm_expr *xsize;
+ elf_size size;
+ elf_section_index index;
+ elf_symbol_binding bind;
+ elf_symbol_type type;
+ elf_symbol_vis vis;
+ elf_symbol_index symindex;
+};
+
+#endif /* defined(YASM_OBJFMT_ELF_INTERNAL) */
+
+extern const yasm_assoc_data_callback elf_section_data;
+extern const yasm_assoc_data_callback elf_symrec_data;
+extern const yasm_assoc_data_callback elf_ssym_symrec_data;
+
+
+const elf_machine_handler *elf_set_arch(struct yasm_arch *arch,
+ yasm_symtab *symtab,
+ int bits_pref);
+
+yasm_symrec *elf_get_special_sym(const char *name, const char *parser);
+
+/* reloc functions */
+int elf_is_wrt_sym_relative(yasm_symrec *wrt);
+int elf_is_wrt_pos_adjusted(yasm_symrec *wrt);
+elf_reloc_entry *elf_reloc_entry_create(yasm_symrec *sym,
+ /*@null@*/ yasm_symrec *wrt,
+ yasm_intnum *addr,
+ int rel,
+ size_t valsize,
+ int is_GOT_sym);
+void elf_reloc_entry_destroy(void *entry);
+
+/* strtab functions */
+elf_strtab_entry *elf_strtab_entry_create(const char *str);
+void elf_strtab_entry_set_str(elf_strtab_entry *entry, const char *str);
+elf_strtab_head *elf_strtab_create(void);
+elf_strtab_entry *elf_strtab_append_str(elf_strtab_head *head, const char *str);
+void elf_strtab_destroy(elf_strtab_head *head);
+unsigned long elf_strtab_output_to_file(FILE *f, elf_strtab_head *head);
+
+/* symtab functions */
+elf_symtab_entry *elf_symtab_entry_create(elf_strtab_entry *name,
+ struct yasm_symrec *sym);
+elf_symtab_head *elf_symtab_create(void);
+void elf_symtab_append_entry(elf_symtab_head *symtab, elf_symtab_entry *entry);
+void elf_symtab_insert_local_sym(elf_symtab_head *symtab,
+ elf_symtab_entry *entry);
+void elf_symtab_destroy(elf_symtab_head *head);
+unsigned long elf_symtab_assign_indices(elf_symtab_head *symtab);
+unsigned long elf_symtab_write_to_file(FILE *f, elf_symtab_head *symtab,
+ yasm_errwarns *errwarns);
+void elf_symtab_set_nonzero(elf_symtab_entry *entry,
+ struct yasm_section *sect,
+ elf_section_index sectidx,
+ elf_symbol_binding bind,
+ elf_symbol_type type,
+ struct yasm_expr *size,
+ elf_address *value);
+void elf_sym_set_visibility(elf_symtab_entry *entry,
+ elf_symbol_vis vis);
+void elf_sym_set_type(elf_symtab_entry *entry, elf_symbol_type type);
+void elf_sym_set_size(elf_symtab_entry *entry, struct yasm_expr *size);
+int elf_sym_in_table(elf_symtab_entry *entry);
+
+/* section header functions */
+elf_secthead *elf_secthead_create(elf_strtab_entry *name,
+ elf_section_type type,
+ elf_section_flags flags,
+ elf_address offset,
+ elf_size size);
+void elf_secthead_destroy(elf_secthead *esd);
+unsigned long elf_secthead_write_to_file(FILE *f, elf_secthead *esd,
+ elf_section_index sindex);
+void elf_secthead_append_reloc(yasm_section *sect, elf_secthead *shead,
+ elf_reloc_entry *reloc);
+elf_section_type elf_secthead_get_type(elf_secthead *shead);
+void elf_secthead_set_typeflags(elf_secthead *shead, elf_section_type type,
+ elf_section_flags flags);
+int elf_secthead_is_empty(elf_secthead *shead);
+struct yasm_symrec *elf_secthead_get_sym(elf_secthead *shead);
+unsigned long elf_secthead_get_align(const elf_secthead *shead);
+unsigned long elf_secthead_set_align(elf_secthead *shead, unsigned long align);
+elf_section_index elf_secthead_get_index(elf_secthead *shead);
+elf_section_info elf_secthead_set_info(elf_secthead *shead,
+ elf_section_info info);
+elf_section_index elf_secthead_set_index(elf_secthead *shead,
+ elf_section_index sectidx);
+elf_section_index elf_secthead_set_link(elf_secthead *shead,
+ elf_section_index link);
+elf_section_index elf_secthead_set_rel_index(elf_secthead *shead,
+ elf_section_index sectidx);
+elf_strtab_entry *elf_secthead_set_rel_name(elf_secthead *shead,
+ elf_strtab_entry *entry);
+elf_size elf_secthead_set_entsize(elf_secthead *shead, elf_size size);
+struct yasm_symrec *elf_secthead_set_sym(elf_secthead *shead,
+ struct yasm_symrec *sym);
+void elf_secthead_add_size(elf_secthead *shead, yasm_intnum *size);
+char *elf_secthead_name_reloc_section(const char *basesect);
+void elf_handle_reloc_addend(yasm_intnum *intn,
+ elf_reloc_entry *reloc,
+ unsigned long offset);
+unsigned long elf_secthead_write_rel_to_file(FILE *f, elf_section_index symtab,
+ yasm_section *sect,
+ elf_secthead *esd,
+ elf_section_index sindex);
+unsigned long elf_secthead_write_relocs_to_file(FILE *f, yasm_section *sect,
+ elf_secthead *shead,
+ yasm_errwarns *errwarns);
+long elf_secthead_set_file_offset(elf_secthead *shead, long pos);
+
+/* program header function */
+unsigned long
+elf_proghead_get_size(void);
+unsigned long
+elf_proghead_write_to_file(FILE *f,
+ elf_offset secthead_addr,
+ unsigned long secthead_count,
+ elf_section_index shstrtab_index);
+
+#endif /* ELF_H_INCLUDED */
diff --git a/contrib/tools/yasm/modules/objfmts/macho/macho-objfmt.c b/contrib/tools/yasm/modules/objfmts/macho/macho-objfmt.c
index 0a48d9b905..ad0215cff3 100644
--- a/contrib/tools/yasm/modules/objfmts/macho/macho-objfmt.c
+++ b/contrib/tools/yasm/modules/objfmts/macho/macho-objfmt.c
@@ -1,1620 +1,1620 @@
-/*
- * Mac OS X ABI Mach-O File Format
- *
- * Copyright (C) 2007 Henryk Richter, built upon xdf objfmt (C) 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.
- */
-/*
- notes: This implementation is rather basic. There are several implementation
- issues to be sorted out for full compliance and error resilience.
- Some examples are given below (nasm syntax).
-
- 1) section placement
- Mach-O requires BSS sections to be placed last in object files. This
- has to be done manually.
- Example:
-
- section .text
- mov rax,[qword foo]
- section .data
- dw 0
- section .bss
- foo dw 0
-
- 2) addressing issues
-
- 2.1) symbol relative relocation (i.e. mov eax,[foo wrt bar])
- Not implemented yet.
-
- 2.2) data referencing in 64 bit mode
- While ELF allows 32 bit absolute relocations in 64 bit mode, Mach-O
- does not. Therefore code like
- lea rbx,[_foo] ;48 8d 1c 25 00 00 00 00
- mov rcx,[_bar] ;48 8b 0c 25 00 00 00 00
- with a 32 bit address field cannot be relocated into an address >= 0x100000000 (OSX actually
- uses that).
-
- Actually, the only register where a 64 bit displacement is allowed in x86-64, is rax
- as in the example 1).
-
- A plausible workaround is either classic PIC (like in C), which is in turn
- not implemented in this object format. The recommended was is PC relative
- code (called RIP-relative in x86-64). So instead of the lines above, just write:
- lea rbx,[_foo wrt rip]
- mov rcx,[_bar wrt rip]
-
- 2.3) section/data alignment
- Normally, you specify sections with a specific alignment
- and get your data layed out as desired. Unfortunately, the
- linker in MacOS X seems to ignore the section alignment requests.
- The workaround is an explicit alignment at the end of the text section.
-
- section .text
- movdqa xmm0,[_foo wrt rip]
-
- align 16
- section .data align=16
- _foo dw 32,32,32,32,32,32,32,32
-
- FIXME: perform that operation implicitly!
-
- 2.4) cross section symbol differences unsupported in current implementation
- [extern foo]
- [extern bar]
- section .data
- dq bar-foo
-
- Will currently produce an error though the necessary means are provided
- by the Mach-O specification.
-
-*/
-
-#include <util.h>
-
-#include <libyasm.h>
-
-/* MACH-O DEFINES */
-/* Mach-O in-file header structure sizes (32 BIT, see below for 64 bit defs) */
-#define MACHO_HEADER_SIZE 28
-#define MACHO_SEGCMD_SIZE 56
-#define MACHO_SECTCMD_SIZE 68
-#define MACHO_SYMCMD_SIZE 24
-#define MACHO_NLIST_SIZE 12
-#define MACHO_RELINFO_SIZE 8
-
-/* 64 bit sizes */
-#define MACHO_HEADER64_SIZE 32
-#define MACHO_SEGCMD64_SIZE 72
-#define MACHO_SECTCMD64_SIZE 80
-#define MACHO_NLIST64_SIZE 16
-#define MACHO_RELINFO64_SIZE 8
-
-
-/* Mach-O file header values */
-#define MH_MAGIC 0xfeedface
-#define MH_MAGIC_64 0xfeedfacf
-
-/* CPU machine type */
-#define CPU_TYPE_I386 7 /* x86 platform */
-#define CPU_TYPE_X86_64 (CPU_TYPE_I386|CPU_ARCH_ABI64)
-#define CPU_ARCH_ABI64 0x01000000 /* 64 bit ABI */
-
-/* CPU machine subtype, e.g. processor */
-#define CPU_SUBTYPE_I386_ALL 3 /* all-x86 compatible */
-#define CPU_SUBTYPE_X86_64_ALL CPU_SUBTYPE_I386_ALL
-#define CPU_SUBTYPE_386 3
-#define CPU_SUBTYPE_486 4
-#define CPU_SUBTYPE_486SX (4 + 128)
-#define CPU_SUBTYPE_586 5
-#define CPU_SUBTYPE_INTEL(f, m) ((f) + ((m) << 4))
-#define CPU_SUBTYPE_PENT CPU_SUBTYPE_INTEL(5, 0)
-#define CPU_SUBTYPE_PENTPRO CPU_SUBTYPE_INTEL(6, 1)
-#define CPU_SUBTYPE_PENTII_M3 CPU_SUBTYPE_INTEL(6, 3)
-#define CPU_SUBTYPE_PENTII_M5 CPU_SUBTYPE_INTEL(6, 5)
-#define CPU_SUBTYPE_PENTIUM_4 CPU_SUBTYPE_INTEL(10, 0)
-
-#define CPU_SUBTYPE_INTEL_FAMILY(x) ((x) & 15)
-#define CPU_SUBTYPE_INTEL_FAMILY_MAX 15
-
-#define CPU_SUBTYPE_INTEL_MODEL(x) ((x) >> 4)
-#define CPU_SUBTYPE_INTEL_MODEL_ALL 0
-
-#define MH_OBJECT 0x1 /* object file */
-
-#define LC_SEGMENT 0x1 /* segment load command */
-#define LC_SYMTAB 0x2 /* symbol table load command */
-#define LC_SEGMENT_64 0x19 /* segment load command */
-
-
-#define VM_PROT_NONE 0x00
-#define VM_PROT_READ 0x01
-#define VM_PROT_WRITE 0x02
-#define VM_PROT_EXECUTE 0x04
-
-#define VM_PROT_DEFAULT (VM_PROT_READ | VM_PROT_WRITE | VM_PROT_EXECUTE)
-#define VM_PROT_ALL (VM_PROT_READ | VM_PROT_WRITE | VM_PROT_EXECUTE)
-
-#define SECTION_TYPE 0x000000ff /* section type mask */
-#define SECTION_ATTRIBUTES 0xffffff00UL/* section attributes mask */
-
-#define S_REGULAR 0x0 /* standard section */
-#define S_ZEROFILL 0x1 /* zerofill, in-memory only */
-#define S_CSTRING_LITERALS 0x2 /* literal C strings */
-#define S_4BYTE_LITERALS 0x3 /* only 4-byte literals */
-#define S_8BYTE_LITERALS 0x4 /* only 8-byte literals */
-#define S_LITERAL_POINTERS 0x5 /* only pointers to literals */
-#define S_NON_LAZY_SYMBOL_POINTERS 0x6 /* only non-lazy symbol pointers */
-#define S_LAZY_SYMBOL_POINTERS 0x7 /* only lazy symbol pointers */
-#define S_SYMBOL_STUBS 0x8 /* only symbol stubs; byte size of
- * stub in the reserved2 field */
-#define S_MOD_INIT_FUNC_POINTERS 0x9 /* only function pointers for init */
-#define S_MOD_TERM_FUNC_POINTERS 0xa /* only function pointers for term */
-#define S_COALESCED 0xb /* symbols that are to be coalesced */
-#define S_GB_ZEROFILL 0xc /* >4GB zero fill on demand section */
-#define S_INTERPOSING 0xd /* only pairs of function pointers for
- * interposing */
-#define S_16BYTE_LITERALS 0xe /* only 16 byte literals */
-
-#define S_ATTR_DEBUG 0x02000000 /* a debug section */
-#define SECTION_ATTRIBUTES_SYS 0x00ffff00 /* system setable attributes */
-#define S_ATTR_SOME_INSTRUCTIONS 0x00000400 /* section contains some
- * machine instructions */
-#define S_ATTR_EXT_RELOC 0x00000200 /* section has external
- * relocation entries */
-#define S_ATTR_LOC_RELOC 0x00000100 /* section has local
- * relocation entries */
-
-#define SECTION_ATTRIBUTES_USR 0xff000000UL /* User setable attributes */
-#define S_ATTR_PURE_INSTRUCTIONS 0x80000000UL /* only true machine insns */
-#define S_ATTR_NO_TOC 0x40000000UL /* coalesced symbols that are
- * not to be in a ranlib table
- * of contents */
-#define S_ATTR_STRIP_STATIC_SYMS 0x20000000UL /* ok to strip static symbols
- * in this section in files
- * with the MH_DYLDLINK flag */
-#define S_ATTR_NO_DEAD_STRIP 0x10000000UL /* no dead stripping */
-#define S_ATTR_LIVE_SUPPORT 0x08000000UL /* blocks are live if they
- * reference live blocks */
-#define S_ATTR_SELF_MODIFYING_CODE 0x04000000UL /* Used with i386 code stubs
- * written on by dyld */
-
-/* macho references symbols in different ways whether they are linked at
- * runtime (LAZY, read library functions) or at link time (NON_LAZY, mostly
- * data)
- *
- * TODO: proper support for dynamically linkable modules would require the
- * __import sections as well as the dsymtab command
- */
-#define REFERENCE_FLAG_UNDEFINED_NON_LAZY 0x0
-#define REFERENCE_FLAG_UNDEFINED_LAZY 0x1
-
-#define align(x, y) \
- (((x) + (y) - 1) & ~((y) - 1)) /* align x to multiple of y */
-
-#define align32(x) \
- align(x, 4) /* align x to 32 bit boundary */
-
-#define macho_MAGIC 0x87654322
-
-/* Symbol table type field bit masks */
-#define N_STAB 0xe0 /* mask indicating stab entry */
-#define N_PEXT 0x10 /* private external bit */
-#define N_TYPE 0x0e /* mask for all the type bits */
-#define N_EXT 0x01 /* external (global) bit */
-
-/* Symbol table type field values */
-#define N_UNDF 0x00 /* undefined */
-#define N_ABS 0x02 /* absolute address */
-#define N_SECT 0x0e /* symbol is defined in a section */
-
-#define NO_SECT 0 /* no section for symbol in nlist */
-
-#define REGULAR_OUTBUF_SIZE 1024
-
-
-typedef struct macho_reloc {
- yasm_reloc reloc;
- int pcrel;
- int length;
- int ext;
- enum reloc_type_x86_64 {
- /* x86 relocations */
- GENERIC_RELOC_VANILLA = 0, /* generic relocation */
- GENERIC_RELOC_PAIR = 1, /* Only follows a GENERIC_RELOC_SECTDIFF */
- GENERIC_RELOC_SECTDIFF = 2,
- GENERIC_RELOC_PB_LA_PTR = 3, /* prebound lazy pointer */
- GENERIC_RELOC_LOCAL_SECTDIFF = 4,
-
- /* x86-64 relocations */
- X86_64_RELOC_UNSIGNED = 0, /* for absolute addresses */
- X86_64_RELOC_SIGNED = 1, /* for signed 32-bit displacement */
- X86_64_RELOC_BRANCH = 2, /* a CALL/JMP insn with 32-bit disp */
- X86_64_RELOC_GOT_LOAD = 3, /* a MOVQ load of a GOT entry */
- X86_64_RELOC_GOT = 4, /* other GOT references */
- X86_64_RELOC_SUBTRACTOR = 5, /* must be followed by a X86_64_RELOC_UNSIGNED */
- X86_64_RELOC_SIGNED_1 = 6, /* signed 32-bit disp, -1 addend */
- X86_64_RELOC_SIGNED_2 = 7, /* signed 32-bit disp, -2 addend */
- X86_64_RELOC_SIGNED_4 = 8 /* signed 32-bit disp, -4 addend */
- } type;
-} macho_reloc;
-
-typedef struct macho_section_data {
- /*@dependent@*/ yasm_symrec *sym; /* symbol created for this section */
- long scnum; /* section number (0=first section) */
- /*@only@*/ char *segname; /* segment name in file */
- /*@only@*/ char *sectname; /* section name in file */
- unsigned long flags; /* S_* flags */
- unsigned long size; /* size of raw data (section data) in bytes */
- unsigned long offset; /* offset in raw data within file in bytes */
- unsigned long vmoff; /* memory offset */
- unsigned long nreloc; /* number of relocation entries */
- unsigned int extreloc; /* external relocations present (0/1) */
-} macho_section_data;
-
-
-typedef struct macho_symrec_data {
- unsigned long index; /* index in output order */
- yasm_intnum *value; /* valid after writing symtable to file */
- unsigned long length; /* length + 1 (plus auto underscore) */
-} macho_symrec_data;
-
-
-typedef struct yasm_objfmt_macho {
- yasm_objfmt_base objfmt; /* base structure */
-
- long parse_scnum; /* sect numbering in parser */
- int bits; /* 32 / 64 */
-
- yasm_symrec *gotpcrel_sym; /* ..gotpcrel */
-} yasm_objfmt_macho;
-
-
-typedef struct macho_objfmt_output_info {
- yasm_object *object;
- yasm_objfmt_macho *objfmt_macho;
- yasm_errwarns *errwarns;
- /*@dependent@ */ FILE *f;
- /*@only@ */ unsigned char *buf;
- yasm_section *sect;
- /*@dependent@ */ macho_section_data *msd;
-
- unsigned int is_64; /* write object in 64 bit mode */
-
- /* vmsize and filesize available after traversing section count routine */
- unsigned long vmsize; /* raw size of all sections (including BSS) */
- unsigned long filesize; /* size of sections in file (excluding BSS) */
- unsigned long offset; /* offset within file */
-
- /* forward offset tracking */
- unsigned long rel_base; /* first relocation in file */
- unsigned long s_reloff; /* in-file offset to relocations */
-
- unsigned long indx; /* current symbol size in bytes (name length+1) */
- unsigned long symindex; /* current symbol index in output order */
- int all_syms; /* outputting all symbols? */
- unsigned long strlength; /* length of all strings */
-} macho_objfmt_output_info;
-
-
-static void macho_section_data_destroy(/*@only@*/ void *d);
-static void macho_section_data_print(void *data, FILE *f, int indent_level);
-
-static const yasm_assoc_data_callback macho_section_data_cb = {
- macho_section_data_destroy,
- macho_section_data_print
-};
-
-static void macho_symrec_data_destroy(/*@only@*/ void *d);
-static void macho_symrec_data_print(void *data, FILE *f, int indent_level);
-
-static const yasm_assoc_data_callback macho_symrec_data_cb = {
- macho_symrec_data_destroy,
- macho_symrec_data_print
-};
-
-yasm_objfmt_module yasm_macho_LTX_objfmt;
-yasm_objfmt_module yasm_macho32_LTX_objfmt;
-yasm_objfmt_module yasm_macho64_LTX_objfmt;
-
-static yasm_objfmt *
-macho_objfmt_create_common(yasm_object *object, yasm_objfmt_module *module,
- int bits_pref)
-{
- yasm_objfmt_macho *objfmt_macho = yasm_xmalloc(sizeof(yasm_objfmt_macho));
-
- objfmt_macho->objfmt.module = module;
-
- /* Only support x86 arch for now */
- if (yasm__strcasecmp(yasm_arch_keyword(object->arch), "x86") != 0) {
- yasm_xfree(objfmt_macho);
- return NULL;
- }
-
- /* Support x86 and amd64 machines of x86 arch */
- if (yasm__strcasecmp(yasm_arch_get_machine(object->arch), "x86") == 0 &&
- (bits_pref == 0 || bits_pref == 32)) {
- objfmt_macho->bits = 32;
- objfmt_macho->gotpcrel_sym = NULL;
- } else if (yasm__strcasecmp(yasm_arch_get_machine(object->arch),
- "amd64") == 0 &&
- (bits_pref == 0 || bits_pref == 64)) {
- objfmt_macho->bits = 64;
- /* FIXME: misuse of NULL bytecode */
- objfmt_macho->gotpcrel_sym =
- yasm_symtab_define_label(object->symtab, "..gotpcrel", NULL, 0, 0);
- } else {
- yasm_xfree(objfmt_macho);
- return NULL;
- }
-
- objfmt_macho->parse_scnum = 0; /* section numbering starts at 0 */
- return (yasm_objfmt *)objfmt_macho;
-}
-
-static yasm_objfmt *
-macho_objfmt_create(yasm_object *object)
-{
- yasm_objfmt *objfmt;
- yasm_objfmt_macho *objfmt_macho;
-
- objfmt = macho_objfmt_create_common(object, &yasm_macho_LTX_objfmt, 0);
- if (objfmt) {
- objfmt_macho = (yasm_objfmt_macho *)objfmt;
- /* Figure out which bitness of object format to use */
- if (objfmt_macho->bits == 32)
- objfmt_macho->objfmt.module = &yasm_macho32_LTX_objfmt;
- else if (objfmt_macho->bits == 64)
- objfmt_macho->objfmt.module = &yasm_macho64_LTX_objfmt;
- }
- return objfmt;
-}
-
-static yasm_objfmt *
-macho32_objfmt_create(yasm_object *object)
-{
- return macho_objfmt_create_common(object, &yasm_macho32_LTX_objfmt, 32);
-}
-
-static yasm_objfmt *
-macho64_objfmt_create(yasm_object *object)
-{
- return macho_objfmt_create_common(object, &yasm_macho64_LTX_objfmt, 64);
-}
-
-static int
-macho_objfmt_output_value(yasm_value *value, unsigned char *buf,
- unsigned int destsize, unsigned long offset,
- yasm_bytecode *bc, int warn, /*@null@*/ void *d)
-{
- /*@null@*/ macho_objfmt_output_info *info = (macho_objfmt_output_info *)d;
- yasm_objfmt_macho *objfmt_macho;
- /*@dependent@*/ /*@null@*/ yasm_intnum *intn;
- unsigned long intn_minus = 0, intn_plus = 0;
- int retval;
- unsigned int valsize = value->size;
- macho_reloc *reloc = NULL;
-
- assert(info != NULL);
- objfmt_macho = info->objfmt_macho;
-
- if (value->abs)
- value->abs = yasm_expr_simplify(value->abs, 1);
-
- /* Try to output constant and PC-relative section-local first.
- * Note this does NOT output any value with a SEG, WRT, external,
- * cross-section, or non-PC-relative reference (those are handled below).
- */
- switch (yasm_value_output_basic(value, buf, destsize, bc, warn,
- info->object->arch)) {
- case -1:
- return 1;
- case 0:
- break;
- default:
- return 0;
- }
-
- if (value->section_rel) {
- yasm_error_set(YASM_ERROR_TOO_COMPLEX,
- N_("macho: relocation too complex for current implementation"));
- return 1;
- }
-
- if (value->rel) {
- yasm_sym_vis vis = yasm_symrec_get_visibility(value->rel);
-
- reloc = yasm_xcalloc(sizeof(macho_reloc), 1);
- reloc->reloc.addr = yasm_intnum_create_uint(bc->offset + offset);
- reloc->reloc.sym = value->rel;
- switch (valsize) {
- case 64:
- reloc->length = 3;
- break;
- case 32:
- reloc->length = 2;
- break;
- case 16:
- reloc->length = 1;
- break;
- case 8:
- reloc->length = 0;
- break;
- default:
- yasm_error_set(YASM_ERROR_TOO_COMPLEX,
- N_("macho: relocation size unsupported"));
- yasm_xfree(reloc);
- return 1;
- }
- reloc->pcrel = 0;
- reloc->ext = 0;
- reloc->type = GENERIC_RELOC_VANILLA;
- /* R_ABS */
-
- if (value->rshift > 0) {
- yasm_error_set(YASM_ERROR_TOO_COMPLEX,
- N_("macho: shifted relocations not supported"));
- yasm_xfree(reloc);
- return 1;
- }
-
- if (value->seg_of) {
- yasm_error_set(YASM_ERROR_TOO_COMPLEX,
- N_("macho: SEG not supported"));
- yasm_xfree(reloc);
- return 1;
- }
-
- if (value->curpos_rel && objfmt_macho->gotpcrel_sym &&
- value->wrt == objfmt_macho->gotpcrel_sym) {
- reloc->type = X86_64_RELOC_GOT;
- value->wrt = NULL;
- } else if (value->wrt) {
- yasm_error_set(YASM_ERROR_TOO_COMPLEX,
- N_("macho: invalid WRT"));
- yasm_xfree(reloc);
- return 1;
- }
-
- if (value->curpos_rel) {
- reloc->pcrel = 1;
- if (!info->is_64) {
- /* Adjust to start of section, so subtract out the bytecode
- * offset.
- */
- intn_minus = bc->offset;
- } else {
- /* Add in the offset plus value size to end up with 0. */
- intn_plus = offset+destsize;
- if (reloc->type == X86_64_RELOC_GOT) {
- /* XXX: This is a hack */
- if (offset >= 2 && buf[-2] == 0x8B)
- reloc->type = X86_64_RELOC_GOT_LOAD;
- } else if (value->jump_target)
- reloc->type = X86_64_RELOC_BRANCH;
- else
- reloc->type = X86_64_RELOC_SIGNED;
- }
- } else if (info->is_64) {
- if (valsize == 32) {
- yasm_error_set(YASM_ERROR_NOT_CONSTANT,
- N_("macho: sorry, cannot apply 32 bit absolute relocations in 64 bit mode, consider \"[_symbol wrt rip]\" for mem access, \"qword\" and \"dq _foo\" for pointers."));
- return 1;
- }
- reloc->type = X86_64_RELOC_UNSIGNED;
- }
-
- /* It seems that x86-64 objects need to have all extern relocs? */
- if (info->is_64)
- reloc->ext = 1;
-
- if ((vis & YASM_SYM_EXTERN) || (vis & YASM_SYM_COMMON)) {
- reloc->ext = 1;
- info->msd->extreloc = 1; /* section has external relocations */
- } else if (!info->is_64) {
- /*@dependent@*/ /*@null@*/ yasm_bytecode *sym_precbc;
-
- /* Local symbols need valued to their actual address */
- if (yasm_symrec_get_label(value->rel, &sym_precbc)) {
- yasm_section *sym_sect = yasm_bc_get_section(sym_precbc);
- /*@null@*/ macho_section_data *msd;
- msd = yasm_section_get_data(sym_sect, &macho_section_data_cb);
- assert(msd != NULL);
- intn_plus += msd->vmoff + yasm_bc_next_offset(sym_precbc);
- }
- }
-
- info->msd->nreloc++;
- /*printf("reloc %s type %d ",yasm_symrec_get_name(reloc->reloc.sym),reloc->type);*/
- yasm_section_add_reloc(info->sect, (yasm_reloc *)reloc, yasm_xfree);
- }
-
- if (intn_minus <= intn_plus)
- intn = yasm_intnum_create_uint(intn_plus-intn_minus);
- else {
- intn = yasm_intnum_create_uint(intn_minus-intn_plus);
- yasm_intnum_calc(intn, YASM_EXPR_NEG, NULL);
- }
-
- if (value->abs) {
- yasm_intnum *intn2 = yasm_expr_get_intnum(&value->abs, 0);
-
- if (!intn2) {
- yasm_error_set(YASM_ERROR_TOO_COMPLEX,
- N_("macho: relocation too complex"));
- yasm_intnum_destroy(intn);
- return 1;
- }
- yasm_intnum_calc(intn, YASM_EXPR_ADD, intn2);
- }
-
- retval = yasm_arch_intnum_tobytes(info->object->arch, intn, buf, destsize,
- valsize, 0, bc, warn);
- /*printf("val %ld\n",yasm_intnum_get_int(intn));*/
- yasm_intnum_destroy(intn);
- return retval;
-}
-
-static int
-macho_objfmt_output_bytecode(yasm_bytecode *bc, /*@null@*/ void *d)
-{
- /*@null@*/ macho_objfmt_output_info *info = (macho_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,
- macho_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: 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;
-}
-
-static int
-macho_objfmt_output_section(yasm_section *sect, /*@null@ */ void *d)
-{
- /*@null@ */ macho_objfmt_output_info *info =
- (macho_objfmt_output_info *) d;
- /*@dependent@ *//*@null@ */ macho_section_data *msd;
-
- assert(info != NULL);
- msd = yasm_section_get_data(sect, &macho_section_data_cb);
- assert(msd != NULL);
-
- if (!(msd->flags & S_ZEROFILL)) {
- /* Output non-BSS sections */
- info->sect = sect;
- info->msd = msd;
- yasm_section_bcs_traverse(sect, info->errwarns, info,
- macho_objfmt_output_bytecode);
- }
- return 0;
-}
-
-static int
-macho_objfmt_output_relocs(yasm_section *sect, /*@null@*/ void *d)
-{
- /*@null@*/ macho_objfmt_output_info *info = (macho_objfmt_output_info *)d;
- /*@dependent@*/ /*@null@*/ macho_section_data *msd;
- macho_reloc *reloc;
-
- reloc = (macho_reloc *)yasm_section_relocs_first(sect);
- while (reloc) {
- unsigned char *localbuf = info->buf;
- /*@null@*/ macho_symrec_data *xsymd;
- unsigned long symnum;
-
- xsymd = yasm_symrec_get_data(reloc->reloc.sym, &macho_symrec_data_cb);
- yasm_intnum_get_sized(reloc->reloc.addr, localbuf, 4, 32, 0, 0, 0);
- localbuf += 4; /* address of relocation */
-
- if (reloc->ext)
- symnum = xsymd->index;
- else {
- /* find section where the symbol relates to */
- /*@dependent@*/ /*@null@*/ yasm_section *dsect;
- /*@dependent@*/ /*@null@*/ yasm_bytecode *precbc;
- symnum = 0; /* default to absolute */
- if (yasm_symrec_get_label(reloc->reloc.sym, &precbc) &&
- (dsect = yasm_bc_get_section(precbc)) &&
- (msd = yasm_section_get_data(dsect, &macho_section_data_cb)))
- symnum = msd->scnum+1;
- }
- YASM_WRITE_32_L(localbuf,
- (symnum & 0x00ffffff) |
- (((unsigned long)reloc->pcrel & 1) << 24) |
- (((unsigned long)reloc->length & 3) << 25) |
- (((unsigned long)reloc->ext & 1) << 27) |
- (((unsigned long)reloc->type & 0xf) << 28));
- fwrite(info->buf, 8, 1, info->f);
- reloc = (macho_reloc *)yasm_section_reloc_next((yasm_reloc *)reloc);
- }
-
- return 0;
-}
-
-static int
-exp2_to_bits(unsigned long val)
-{
- int ret = 0;
-
- while (val) {
- val >>= 1;
- ret++;
- }
- ret = (ret > 0) ? ret - 1 : 0;
-
- return ret;
-}
-
-static int
-macho_objfmt_is_section_label(yasm_symrec *sym)
-{
- /*@dependent@*/ /*@null@*/ yasm_section *sect;
- /*@dependent@*/ /*@null@*/ yasm_bytecode *precbc;
-
- /* Look at symrec for value/scnum/etc. */
- if (yasm_symrec_get_label(sym, &precbc)) {
- if (precbc)
- sect = yasm_bc_get_section(precbc);
- else
- sect = NULL;
- /* it's a label: get value and offset.
- * If there is not a section, leave as debugging symbol.
- */
- if (sect) {
- /*@dependent@*/ /*@null@*/ macho_section_data *msd;
-
- msd = yasm_section_get_data(sect, &macho_section_data_cb);
- if (msd) {
- if (msd->sym == sym)
- return 1; /* don't store section names */
- }
- }
- }
- return 0;
-}
-
-static int
-macho_objfmt_output_secthead(yasm_section *sect, /*@null@*/ void *d)
-{
- /*@null@*/ macho_objfmt_output_info *info = (macho_objfmt_output_info *)d;
- /*@dependent@*/ /*@null@*/ macho_section_data *msd;
- unsigned char *localbuf;
-
- assert(info != NULL);
- msd = yasm_section_get_data(sect, &macho_section_data_cb);
- assert(msd != NULL);
-
- localbuf = info->buf;
-
- memset(localbuf, 0, 16);
- strncpy((char *)localbuf, msd->sectname, 16);
- localbuf += 16;
- memset(localbuf, 0, 16);
- strncpy((char *)localbuf, msd->segname, 16);
- localbuf += 16;
- /* section address, size depend on 32/64 bit mode */
- YASM_WRITE_32_L(localbuf, msd->vmoff); /* address in memory */
- if (info->is_64)
- YASM_WRITE_32_L(localbuf, 0); /* 64-bit mode: upper 32 bits = 0 */
- YASM_WRITE_32_L(localbuf, msd->size); /* size in memory */
- if (info->is_64)
- YASM_WRITE_32_L(localbuf, 0); /* 64-bit mode: upper 32 bits = 0 */
-
- /* offset,align,reloff,nreloc,flags,reserved1,reserved2 are 32 bit */
- if ((msd->flags & SECTION_TYPE) != S_ZEROFILL) {
- YASM_WRITE_32_L(localbuf, msd->offset);
- YASM_WRITE_32_L(localbuf, exp2_to_bits(yasm_section_get_align(sect)));
- if (msd->nreloc) {
- msd->flags |= S_ATTR_LOC_RELOC;
- if (msd->extreloc)
- msd->flags |= S_ATTR_EXT_RELOC;
- YASM_WRITE_32_L(localbuf,
- align32((long)(info->rel_base + info->s_reloff)));
- YASM_WRITE_32_L(localbuf, msd->nreloc); /* nreloc */
- } else {
- YASM_WRITE_32_L(localbuf, 0);
- YASM_WRITE_32_L(localbuf, 0);
- }
-
- info->s_reloff += msd->nreloc * MACHO_RELINFO_SIZE; /* nreloc */
- } else {
- YASM_WRITE_32_L(localbuf, 0); /* these are zero in BSS */
- YASM_WRITE_32_L(localbuf, 0);
- YASM_WRITE_32_L(localbuf, 0);
- YASM_WRITE_32_L(localbuf, 0);
- }
-
- YASM_WRITE_32_L(localbuf, msd->flags); /* flags */
- YASM_WRITE_32_L(localbuf, 0); /* reserved 1 */
- YASM_WRITE_32_L(localbuf, 0); /* reserved 2 */
-
- if (info->is_64)
- fwrite(info->buf, MACHO_SECTCMD64_SIZE, 1, info->f);
- else
- fwrite(info->buf, MACHO_SECTCMD_SIZE, 1, info->f);
-
- return 0;
-}
-
-
-static int
-macho_objfmt_count_sym(yasm_symrec *sym, /*@null@*/ void *d)
-{
- /*@null@*/ macho_objfmt_output_info *info = (macho_objfmt_output_info *)d;
- /*@only@*/ char *name;
- yasm_sym_vis vis = yasm_symrec_get_visibility(sym);
-
- assert(info != NULL);
- if (info->all_syms ||
- vis & (YASM_SYM_GLOBAL | YASM_SYM_COMMON | YASM_SYM_EXTERN)) {
- if (0 == macho_objfmt_is_section_label(sym)) {
- /* Save index in symrec data */
- macho_symrec_data *sym_data =
- yasm_symrec_get_data(sym, &macho_symrec_data_cb);
- if (!sym_data) {
- sym_data = yasm_xcalloc(sizeof(macho_symrec_data), 1);
- yasm_symrec_add_data(sym, &macho_symrec_data_cb, sym_data);
- }
- sym_data->index = info->symindex;
- info->symindex++;
-
- name = yasm_symrec_get_global_name(sym, info->object);
- /*printf("%s\n",name); */
- /* name length + delimiter */
- sym_data->length = (unsigned long)strlen(name) + 1;
- info->strlength += sym_data->length;
- info->indx++;
- yasm_xfree(name);
- }
- }
- return 0;
-}
-
-
-static int
-macho_objfmt_output_symtable(yasm_symrec *sym, /*@null@*/ void *d)
-{
- /*@null@*/ macho_objfmt_output_info *info = (macho_objfmt_output_info *)d;
- yasm_sym_vis vis = yasm_symrec_get_visibility(sym);
-
- assert(info != NULL);
-
- if (info->all_syms ||
- vis & (YASM_SYM_GLOBAL | YASM_SYM_COMMON | YASM_SYM_EXTERN)) {
- const yasm_expr *equ_val;
- const yasm_intnum *intn;
- unsigned long value = 0;
- long scnum = -3; /* -3 = debugging symbol */
- /*@dependent@*/ /*@null@*/ yasm_section *sect;
- /*@dependent@*/ /*@null@*/ yasm_bytecode *precbc;
- unsigned char *localbuf;
- yasm_intnum *val;
- unsigned int long_int_bytes = (info->is_64) ? 8 : 4;
- unsigned int n_type = 0, n_sect = 0, n_desc = 0;
- macho_symrec_data *symd;
-
- val = yasm_intnum_create_uint(0);
-
- symd = yasm_symrec_get_data(sym, &macho_symrec_data_cb);
-
- /* Look at symrec for value/scnum/etc. */
- if (yasm_symrec_get_label(sym, &precbc)) {
- if (precbc)
- sect = yasm_bc_get_section(precbc);
- else
- sect = NULL;
- /* it's a label: get value and offset.
- * If there is not a section, leave as debugging symbol.
- */
- if (sect) {
- /*@dependent@*/ /*@null@*/ macho_section_data *msd;
-
- msd = yasm_section_get_data(sect, &macho_section_data_cb);
- if (msd) {
- if (msd->sym == sym) {
- /* don't store section names */
- yasm_intnum_destroy(val);
- return 0;
- }
- scnum = msd->scnum;
- n_type = N_SECT;
- } else
- yasm_internal_error(N_("didn't understand section"));
- if (precbc)
- value += yasm_bc_next_offset(precbc);
- /* all values are subject to correction: base offset is first
- * raw section, therefore add section offset
- */
- if (msd)
- value += msd->vmoff;
- yasm_intnum_set_uint(val, value);
- /*printf("%s offset %lx\n",name,value);*/
- }
- } else if ((equ_val = yasm_symrec_get_equ(sym))) {
- yasm_expr *equ_val_copy = yasm_expr_copy(equ_val);
-
- intn = yasm_expr_get_intnum(&equ_val_copy, 1);
- if (!intn) {
- if (vis & YASM_SYM_GLOBAL) {
- yasm_error_set(YASM_ERROR_NOT_CONSTANT,
- N_("global EQU value not an integer expression"));
- yasm_errwarn_propagate(info->errwarns, equ_val->line);
- }
- } else
- value = yasm_intnum_get_uint(intn);
- yasm_expr_destroy(equ_val_copy);
- yasm_intnum_set_uint(val, value);
- n_type = N_ABS;
- scnum = -2; /* -2 = absolute symbol */
- }
-
- if (vis & YASM_SYM_EXTERN) {
- n_type = N_EXT;
- scnum = -1;
- /*n_desc = REFERENCE_FLAG_UNDEFINED_LAZY; * FIXME: see definition of REFERENCE_FLAG_* above */
- } else if (vis & YASM_SYM_COMMON) {
- yasm_expr **csize = yasm_symrec_get_common_size(sym);
- n_type = N_UNDF | N_EXT;
- if (csize) {
- intn = yasm_expr_get_intnum(csize, 1);
- if (!intn) {
- yasm_error_set(YASM_ERROR_NOT_CONSTANT,
- N_("COMMON data size not an integer expression"));
- yasm_errwarn_propagate(info->errwarns, (*csize)->line);
- } else
- yasm_intnum_set_uint(val, yasm_intnum_get_uint(intn));
- }
- /*printf("common symbol %s val %lu\n", name, yasm_intnum_get_uint(val));*/
- } else if (vis & YASM_SYM_GLOBAL) {
- yasm_valparamhead *valparams =
- yasm_symrec_get_objext_valparams(sym);
-
- struct macho_global_data {
- unsigned long flag; /* N_PEXT */
- } data;
-
- data.flag = 0;
-
- if (valparams) {
- static const yasm_dir_help help[] = {
- { "private_extern", 0, yasm_dir_helper_flag_set,
- offsetof(struct macho_global_data, flag), N_PEXT },
- };
- yasm_dir_helper(sym, yasm_vps_first(valparams),
- yasm_symrec_get_decl_line(sym), help, NELEMS(help),
- &data, yasm_dir_helper_valparam_warn);
- }
-
- n_type |= N_EXT | data.flag;
- }
-
- localbuf = info->buf;
- YASM_WRITE_32_L(localbuf, info->indx); /* offset in string table */
- YASM_WRITE_8(localbuf, n_type); /* type of symbol entry */
- n_sect = (scnum >= 0) ? scnum + 1 : NO_SECT;
- YASM_WRITE_8(localbuf, n_sect); /* referring section where symbol is found */
- YASM_WRITE_16_L(localbuf, n_desc); /* extra description */
- yasm_intnum_get_sized(val, localbuf, long_int_bytes, ((long_int_bytes) << 3), 0, 0, 0); /* value/argument */
- localbuf += long_int_bytes;
- if (symd)
- symd->value = val;
- else
- yasm_intnum_destroy(val);
-
- info->indx += symd->length;
-
- fwrite(info->buf, 8 + long_int_bytes, 1, info->f);
- }
-
- return 0;
-}
-
-
-static int
-macho_objfmt_output_str(yasm_symrec *sym, /*@null@*/ void *d)
-{
- /*@null@*/ macho_objfmt_output_info *info = (macho_objfmt_output_info *)d;
- yasm_sym_vis vis = yasm_symrec_get_visibility(sym);
-
- assert(info != NULL);
-
- if (info->all_syms ||
- vis & (YASM_SYM_GLOBAL | YASM_SYM_COMMON | YASM_SYM_EXTERN)) {
- if (0 == macho_objfmt_is_section_label(sym)) {
- /*@only@*/ char *name =
- yasm_symrec_get_global_name(sym, info->object);
- size_t len = strlen(name);
-
- fwrite(name, len + 1, 1, info->f);
- yasm_xfree(name);
- }
- }
- return 0;
-}
-
-static int
-macho_objfmt_calc_sectsize(yasm_section *sect, /*@null@ */ void *d)
-{
- /*@null@ */ macho_objfmt_output_info *info =
- (macho_objfmt_output_info *) d;
- /*@dependent@ *//*@null@ */ macho_section_data *msd;
- unsigned long align;
-
- assert(info != NULL);
- msd = yasm_section_get_data(sect, &macho_section_data_cb);
- assert(msd != NULL);
-
- msd->size = yasm_bc_next_offset(yasm_section_bcs_last(sect));
- if (!(msd->flags & S_ZEROFILL)) {
- msd->offset = info->offset;
- info->offset += msd->size;
- info->filesize += msd->size;
- }
-
- /* accumulate size in memory */
- msd->vmoff = info->vmsize;
- info->vmsize += msd->size;
-
- /* align both start and end of section */
- align = yasm_section_get_align(sect);
- if (align != 0) {
- unsigned long delta = msd->vmoff % align;
- if (delta > 0) {
- msd->vmoff += align - delta;
- info->vmsize += align - delta;
- }
- }
-
- return 0;
-}
-
-/* write object */
-static void
-macho_objfmt_output(yasm_object *object, FILE *f, int all_syms,
- yasm_errwarns *errwarns)
-{
- yasm_objfmt_macho *objfmt_macho = (yasm_objfmt_macho *)object->objfmt;
- macho_objfmt_output_info info;
- unsigned char *localbuf;
- unsigned long symtab_count = 0;
- unsigned long headsize;
- unsigned int macho_segcmdsize, macho_sectcmdsize, macho_nlistsize;
- unsigned int macho_segcmd;
- unsigned int head_ncmds, head_sizeofcmds;
- unsigned long fileoffset, fileoff_sections;
- yasm_intnum *val;
- unsigned long long_int_bytes;
- const char pad_data[3] = "\0\0\0";
-
- info.object = object;
- info.objfmt_macho = objfmt_macho;
- info.errwarns = errwarns;
- info.f = f;
- info.buf = yasm_xmalloc(REGULAR_OUTBUF_SIZE);
-
- if (objfmt_macho->parse_scnum == 0) {
- yasm_internal_error(N_("no sections defined"));
- /*@notreached@*/
- return;
- }
-
- val = yasm_intnum_create_uint(0);
-
- /*
- * MACH-O Header, Seg CMD, Sect CMDs, Sym Tab, Reloc Data
- */
- info.is_64 = (objfmt_macho->bits == 32) ? 0 : 1;
- if (info.is_64) {
- /* this works only when SYMBOLS and SECTIONS present */
- headsize =
- MACHO_HEADER64_SIZE + MACHO_SEGCMD64_SIZE +
- (MACHO_SECTCMD64_SIZE * (objfmt_macho->parse_scnum)) +
- MACHO_SYMCMD_SIZE;
- macho_segcmd = LC_SEGMENT_64;
- macho_segcmdsize = MACHO_SEGCMD64_SIZE;
- macho_sectcmdsize = MACHO_SECTCMD64_SIZE;
- macho_nlistsize = MACHO_NLIST64_SIZE;
- long_int_bytes = 8;
- } else {
- headsize =
- MACHO_HEADER_SIZE + MACHO_SEGCMD_SIZE +
- (MACHO_SECTCMD_SIZE * (objfmt_macho->parse_scnum)) +
- MACHO_SYMCMD_SIZE;
- macho_segcmd = LC_SEGMENT;
- macho_segcmdsize = MACHO_SEGCMD_SIZE;
- macho_sectcmdsize = MACHO_SECTCMD_SIZE;
- macho_nlistsize = MACHO_NLIST_SIZE;
- long_int_bytes = 4;
- }
-
- /* Get number of symbols */
- info.symindex = 0;
- info.indx = 0;
- info.strlength = 1; /* string table starts with a zero byte */
- info.all_syms = all_syms || info.is_64;
- /*info.all_syms = 1; * force all syms into symbol table */
- yasm_symtab_traverse(object->symtab, &info, macho_objfmt_count_sym);
- symtab_count = info.indx;
-
- /* write raw section data first */
- if (fseek(f, (long)headsize, SEEK_SET) < 0) {
- yasm__fatal(N_("could not seek on output file"));
- /*@notreached@ */
- return;
- }
-
- /* get size of sections in memory (including BSS) and size of sections
- * in file (without BSS)
- */
- info.vmsize = 0;
- info.filesize = 0;
- info.offset = headsize;
- yasm_object_sections_traverse(object, &info, macho_objfmt_calc_sectsize);
-
- /* output sections to file */
- yasm_object_sections_traverse(object, &info, macho_objfmt_output_section);
-
- fileoff_sections = ftell(f);
-
- /* Write headers */
- if (fseek(f, 0, SEEK_SET) < 0) {
- yasm__fatal(N_("could not seek on output file"));
- /*@notreached@*/
- return;
- }
-
- localbuf = info.buf;
-
- /* header size is common to 32 bit and 64 bit variants */
- if (info.is_64) {
- YASM_WRITE_32_L(localbuf, MH_MAGIC_64); /* magic number */
- /* i386 64-bit ABI */
- YASM_WRITE_32_L(localbuf, CPU_ARCH_ABI64 | CPU_TYPE_I386);
- } else {
- YASM_WRITE_32_L(localbuf, MH_MAGIC); /* magic number */
- YASM_WRITE_32_L(localbuf, CPU_TYPE_I386); /* i386 32-bit ABI */
- }
- /* i386 all cpu subtype compatible */
- YASM_WRITE_32_L(localbuf, CPU_SUBTYPE_I386_ALL);
- YASM_WRITE_32_L(localbuf, MH_OBJECT); /* MACH file type */
-
- /* calculate number of commands and their size, put to stream */
- head_ncmds = 0;
- head_sizeofcmds = 0;
- if (objfmt_macho->parse_scnum > 0) {
- head_ncmds++;
- head_sizeofcmds +=
- macho_segcmdsize + macho_sectcmdsize * objfmt_macho->parse_scnum;
- }
- if (symtab_count > 0) {
- head_ncmds++;
- head_sizeofcmds += MACHO_SYMCMD_SIZE;
- }
-
- YASM_WRITE_32_L(localbuf, head_ncmds);
- YASM_WRITE_32_L(localbuf, head_sizeofcmds);
- YASM_WRITE_32_L(localbuf, 0); /* no flags (yet) */
- if (info.is_64) {
- YASM_WRITE_32_L(localbuf, 0); /* reserved in 64 bit */
- fileoffset = MACHO_HEADER64_SIZE + head_sizeofcmds;
- } else {
- /* initial offset to first section */
- fileoffset = MACHO_HEADER_SIZE + head_sizeofcmds;
- }
-
- /* --------------- write segment header command ---------------- */
- YASM_WRITE_32_L(localbuf, macho_segcmd); /* command LC_SEGMENT */
- /* size of load command including section load commands */
- YASM_WRITE_32_L(localbuf,
- macho_segcmdsize +
- macho_sectcmdsize * objfmt_macho->parse_scnum);
- /* in an MH_OBJECT file all sections are in one unnamed (name all zeros)
- * segment (16x0)
- */
- YASM_WRITE_32_L(localbuf, 0);
- YASM_WRITE_32_L(localbuf, 0);
- YASM_WRITE_32_L(localbuf, 0);
- YASM_WRITE_32_L(localbuf, 0);
-
- /* in-memory offset, in-memory size */
- yasm_intnum_set_uint(val, 0); /* offset in memory (vmaddr) */
- yasm_intnum_get_sized(val, localbuf, long_int_bytes,
- ((long_int_bytes) << 3), 0, 0, 0);
- localbuf += long_int_bytes;
- yasm_intnum_set_uint(val, info.vmsize); /* size in memory (vmsize) */
- yasm_intnum_get_sized(val, localbuf, long_int_bytes,
- ((long_int_bytes) << 3), 0, 0, 0);
- localbuf += long_int_bytes;
- /* offset in file to first section */
- yasm_intnum_set_uint(val, fileoffset);
- yasm_intnum_get_sized(val, localbuf, long_int_bytes,
- ((long_int_bytes) << 3), 0, 0, 0);
- localbuf += long_int_bytes;
- yasm_intnum_set_uint(val, info.filesize); /* overall size in file */
- yasm_intnum_get_sized(val, localbuf, long_int_bytes,
- ((long_int_bytes) << 3), 0, 0, 0);
- localbuf += long_int_bytes;
-
- YASM_WRITE_32_L(localbuf, VM_PROT_DEFAULT); /* VM protection, maximum */
- YASM_WRITE_32_L(localbuf, VM_PROT_DEFAULT); /* VM protection, initial */
- /* number of sections */
- YASM_WRITE_32_L(localbuf, objfmt_macho->parse_scnum);
- YASM_WRITE_32_L(localbuf, 0); /* no flags */
-
- /* write MACH-O header and segment command to outfile */
- fwrite(info.buf, (size_t) (localbuf - info.buf), 1, f);
-
- /* next: section headers */
- /* offset to relocs for first section */
- info.rel_base = align32((long)fileoff_sections);
- info.s_reloff = 0; /* offset for relocs of following sections */
- yasm_object_sections_traverse(object, &info, macho_objfmt_output_secthead);
-
- localbuf = info.buf;
- /* write out symbol command */
- YASM_WRITE_32_L(localbuf, LC_SYMTAB); /* cmd == LC_SYMTAB */
- YASM_WRITE_32_L(localbuf, MACHO_SYMCMD_SIZE);
- /* symbol table offset */
- YASM_WRITE_32_L(localbuf, info.rel_base + info.s_reloff);
- YASM_WRITE_32_L(localbuf, symtab_count); /* number of symbols */
-
- YASM_WRITE_32_L(localbuf, macho_nlistsize * symtab_count + info.rel_base +
- info.s_reloff); /* string table offset */
- YASM_WRITE_32_L(localbuf, info.strlength); /* string table size */
- /* write symbol command */
- fwrite(info.buf, (size_t)(localbuf - info.buf), 1, f);
-
- /*printf("num symbols %d, vmsize %d, filesize %d\n",symtab_count,
- info.vmsize, info.filesize ); */
-
- /* get back to end of raw section data */
- if (fseek(f, (long)fileoff_sections, SEEK_SET) < 0) {
- yasm__fatal(N_("could not seek on output file"));
- /*@notreached@*/
- return;
- }
-
- /* padding to long boundary */
- if ((info.rel_base - fileoff_sections) > 0) {
- fwrite(pad_data, info.rel_base - fileoff_sections, 1, f);
- }
-
- /* relocation data */
- yasm_object_sections_traverse(object, &info, macho_objfmt_output_relocs);
-
- /* symbol table (NLIST) */
- info.indx = 1; /* restart symbol table indices */
- yasm_symtab_traverse(object->symtab, &info, macho_objfmt_output_symtable);
-
- /* symbol strings */
- fwrite(pad_data, 1, 1, f);
- yasm_symtab_traverse(object->symtab, &info, macho_objfmt_output_str);
-
- yasm_intnum_destroy(val);
- yasm_xfree(info.buf);
-}
-
-static void
-macho_objfmt_destroy(yasm_objfmt *objfmt)
-{
- yasm_xfree(objfmt);
-}
-
-static void
-macho_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_macho *objfmt_macho = (yasm_objfmt_macho *)object->objfmt;
- macho_section_data *data;
- yasm_symrec *sym;
-
- data = yasm_xmalloc(sizeof(macho_section_data));
- data->scnum = objfmt_macho->parse_scnum++;
- data->segname = NULL;
- data->sectname = NULL;
- data->flags = S_REGULAR;
- data->size = 0;
- data->offset = 0;
- data->vmoff = 0;
- data->nreloc = 0;
- data->extreloc = 0;
- yasm_section_add_data(sect, &macho_section_data_cb, data);
-
- sym = yasm_symtab_define_label(object->symtab, sectname,
- yasm_section_bcs_first(sect), 1, line);
- data->sym = sym;
-}
-
-static yasm_section *
-macho_objfmt_add_default_section(yasm_object *object)
-{
- yasm_section *retval;
- macho_section_data *msd;
- int isnew;
-
- retval = yasm_object_get_general(object, "LC_SEGMENT.__TEXT.__text", 0, 1,
- 0, &isnew, 0);
- if (isnew) {
- msd = yasm_section_get_data(retval, &macho_section_data_cb);
- msd->segname = yasm__xstrdup("__TEXT");
- msd->sectname = yasm__xstrdup("__text");
- msd->flags = S_ATTR_PURE_INSTRUCTIONS;
- yasm_section_set_align(retval, 0, 0);
- yasm_section_set_default(retval, 1);
- }
- return retval;
-}
-
-static /*@observer@*/ /*@null@*/ yasm_section *
-macho_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;
- /*@only@*/ char *f_sectname;
- unsigned long flags;
- unsigned long align;
- int flags_override = 0;
- const char *sectname;
- char *realname;
- int resonly = 0;
- macho_section_data *msd;
- size_t i;
-
- static const struct {
- const char *in;
- const char *seg;
- const char *sect;
- unsigned long flags;
- unsigned long align;
- } section_name_translation[] = {
- {".text", "__TEXT", "__text", S_ATTR_PURE_INSTRUCTIONS, 0},
- {".const", "__TEXT", "__const", S_REGULAR, 0},
- {".static_const", "__TEXT", "__static_const", S_REGULAR, 0},
- {".cstring", "__TEXT", "__cstring", S_CSTRING_LITERALS, 0},
- {".literal4", "__TEXT", "__literal4", S_4BYTE_LITERALS, 4},
- {".literal8", "__TEXT", "__literal8", S_8BYTE_LITERALS, 8},
- {".literal16", "__TEXT", "__literal16", S_16BYTE_LITERALS, 16},
- {".constructor", "__TEXT", "__constructor", S_REGULAR, 0},
- {".destructor", "__TEXT", "__destructor", S_REGULAR, 0},
- {".fvmlib_init0", "__TEXT", "__fvmlib_init0", S_REGULAR, 0},
- {".fvmlib_init1", "__TEXT", "__fvmlib_init1", S_REGULAR, 0},
- {".mod_init_func", "__DATA", "__mod_init_func",
- S_MOD_INIT_FUNC_POINTERS, 4},
- {".mod_term_func", "__DATA", "__mod_term_func",
- S_MOD_TERM_FUNC_POINTERS, 4},
- {".dyld", "__DATA", "__dyld", S_REGULAR, 0},
- {".data", "__DATA", "__data", S_REGULAR, 0},
- {".static_data", "__DATA", "__static_data", S_REGULAR, 0},
- {".const_data", "__DATA", "__const", S_REGULAR, 0},
- {".rodata", "__DATA", "__const", S_REGULAR, 0},
- {".bss", "__DATA", "__bss", S_ZEROFILL, 0},
- {".objc_class_names", "__TEXT", "__cstring", S_CSTRING_LITERALS, 0},
- {".objc_meth_var_types","__TEXT", "__cstring", S_CSTRING_LITERALS, 0},
- {".objc_meth_var_names","__TEXT", "__cstring", S_CSTRING_LITERALS, 0},
- {".objc_selector_strs", "__OBJC", "__selector_strs",
- S_CSTRING_LITERALS, 0},
- {".objc_class", "__OBJC", "__class",
- S_ATTR_NO_DEAD_STRIP, 0},
- {".objc_meta_class", "__OBJC", "__meta_class",
- S_ATTR_NO_DEAD_STRIP, 0},
- {".objc_string_object", "__OBJC", "__string_object",
- S_ATTR_NO_DEAD_STRIP, 0},
- {".objc_protocol", "__OBJC", "__protocol",
- S_ATTR_NO_DEAD_STRIP, 0},
- {".objc_cat_cls_meth", "__OBJC", "__cat_cls_meth",
- S_ATTR_NO_DEAD_STRIP, 0},
- {".objc_cat_inst_meth", "__OBJC", "__cat_inst_meth",
- S_ATTR_NO_DEAD_STRIP, 0},
- {".objc_cls_meth", "__OBJC", "__cls_meth",
- S_ATTR_NO_DEAD_STRIP, 0},
- {".objc_inst_meth", "__OBJC", "__inst_meth",
- S_ATTR_NO_DEAD_STRIP, 0},
- {".objc_message_refs", "__OBJC", "__message_refs",
- S_LITERAL_POINTERS|S_ATTR_NO_DEAD_STRIP, 4},
- {".objc_cls_refs", "__OBJC", "__cls_refs",
- S_LITERAL_POINTERS|S_ATTR_NO_DEAD_STRIP, 4},
- {".objc_module_info", "__OBJC", "__module_info",
- S_ATTR_NO_DEAD_STRIP, 0},
- {".objc_symbols", "__OBJC", "__symbols",
- S_ATTR_NO_DEAD_STRIP, 0},
- {".objc_category", "__OBJC", "__category",
- S_ATTR_NO_DEAD_STRIP, 0},
- {".objc_class_vars", "__OBJC", "__class_vars",
- S_ATTR_NO_DEAD_STRIP, 0},
- {".objc_instance_vars", "__OBJC", "__instance_vars",
- S_ATTR_NO_DEAD_STRIP, 0}
- };
-
- struct macho_section_switch_data {
- /*@only@*/ /*@null@*/ char *f_segname;
- /*@only@*/ /*@null@*/ yasm_intnum *align_intn;
- } data;
-
- static const yasm_dir_help help[] = {
- { "segname", 1, yasm_dir_helper_string,
- offsetof(struct macho_section_switch_data, f_segname), 0 },
- { "align", 1, yasm_dir_helper_intn,
- offsetof(struct macho_section_switch_data, align_intn), 0 }
- };
-
- data.f_segname = NULL;
- data.align_intn = NULL;
-
- vp = yasm_vps_first(valparams);
- sectname = yasm_vp_string(vp);
- if (!sectname)
- return NULL;
- vp = yasm_vps_next(vp);
-
- /* translate .text,.data,.bss to __text,__data,__bss... */
- for (i=0; i<NELEMS(section_name_translation); i++) {
- if (yasm__strcasecmp(sectname, section_name_translation[i].in) == 0)
- break;
- }
-
- if (i == NELEMS(section_name_translation)) {
- const char *s;
- if (vp && !vp->val && (s = yasm_vp_string(vp))) {
- /* Treat as SEGNAME, SECTNAME */
- if (strlen(sectname) > 16)
- yasm_warn_set(YASM_WARN_GENERAL,
- N_("segment name is too long, max 16 chars; truncating"));
- data.f_segname = yasm__xstrndup(sectname, 16);
- if (strlen(s) > 16)
- yasm_warn_set(YASM_WARN_GENERAL,
- N_("section name is too long, max 16 chars; truncating"));
- f_sectname = yasm__xstrndup(s, 16);
- flags = S_REGULAR;
- align = 0;
-
- sectname = s;
- vp = yasm_vps_next(vp);
- } else {
- data.f_segname = NULL;
- if (strlen(sectname) > 16)
- yasm_warn_set(YASM_WARN_GENERAL,
- N_("section name is too long, max 16 chars; truncating"));
- f_sectname = yasm__xstrndup(sectname, 16);
- flags = S_ATTR_SOME_INSTRUCTIONS;
- align = 0;
- }
- } else {
- data.f_segname = yasm__xstrdup(section_name_translation[i].seg);
- f_sectname = yasm__xstrdup(section_name_translation[i].sect);
- flags = section_name_translation[i].flags;
- align = section_name_translation[i].align;
- }
-
- 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.align_intn) {
- align = yasm_intnum_get_uint(data.align_intn);
- yasm_intnum_destroy(data.align_intn);
-
- /* 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"),
- vp->val);
- return NULL;
- }
-
- /* Check to see if alignment is supported size */
- if (align > 16384) {
- yasm_error_set(YASM_ERROR_VALUE,
- N_("macho implementation does not support alignments > 16384"));
- return NULL;
- }
- }
-
- if (!data.f_segname) {
- yasm_warn_set(YASM_WARN_GENERAL,
- N_("Unknown section name, defaulting to __TEXT segment"));
- data.f_segname = yasm__xstrdup("__TEXT");
- }
-
- /* Build a unique sectname from f_segname and f_sectname. */
- realname = yasm_xmalloc(strlen("LC_SEGMENT") + 1 + strlen(data.f_segname) + 1 +
- strlen(f_sectname) + 1);
- sprintf(realname, "LC_SEGMENT.%s.%s", data.f_segname, f_sectname);
- retval = yasm_object_get_general(object, realname, align, 1, resonly,
- &isnew, line);
- yasm_xfree(realname);
-
- msd = yasm_section_get_data(retval, &macho_section_data_cb);
-
- if (isnew || yasm_section_is_default(retval)) {
- yasm_section_set_default(retval, 0);
- msd->segname = data.f_segname;
- msd->sectname = f_sectname;
- msd->flags = flags;
- yasm_section_set_align(retval, align, line);
- } else if (flags_override) {
- /* align is the only value used from overrides. */
- if (yasm_section_get_align(retval) != align) {
- yasm_warn_set(YASM_WARN_GENERAL,
- N_("section flags ignored on section redeclaration"));
- }
- }
- return retval;
-}
-
-static /*@observer@*/ /*@null@*/ yasm_symrec *
-macho_objfmt_get_special_sym(yasm_object *object, const char *name,
- const char *parser)
-{
- yasm_objfmt_macho *objfmt_macho = (yasm_objfmt_macho *)object->objfmt;
- if (yasm__strcasecmp(name, "gotpcrel") == 0) {
- return objfmt_macho->gotpcrel_sym;
- }
- return NULL;
-}
-
-static void
-macho_section_data_destroy(void *data)
-{
- macho_section_data *msd = (macho_section_data *) data;
- yasm_xfree(msd->segname);
- yasm_xfree(msd->sectname);
- yasm_xfree(data);
-}
-
-static void
-macho_section_data_print(void *data, FILE *f, int indent_level)
-{
- macho_section_data *msd = (macho_section_data *) data;
-
- fprintf(f, "%*ssym=\n", indent_level, "");
- yasm_symrec_print(msd->sym, f, indent_level + 1);
- fprintf(f, "%*sscnum=%ld\n", indent_level, "", msd->scnum);
- fprintf(f, "%*sflags=0x%lx\n", indent_level, "", msd->flags);
- fprintf(f, "%*ssize=%lu\n", indent_level, "", msd->size);
- fprintf(f, "%*snreloc=%lu\n", indent_level, "", msd->nreloc);
- fprintf(f, "%*soffset=%lu\n", indent_level, "", msd->offset);
- fprintf(f, "%*sextreloc=%u\n", indent_level, "", msd->extreloc);
-}
-
-static void
-macho_symrec_data_destroy(void *data)
-{
- yasm_xfree(data);
-}
-
-static void
-macho_symrec_data_print(void *data, FILE *f, int indent_level)
-{
- macho_symrec_data *msd = (macho_symrec_data *)data;
-
- fprintf(f, "%*sindex=%ld\n", indent_level, "", msd->index);
- fprintf(f, "%*svalue=", indent_level, "");
- if (msd->value)
- fprintf(f, "%ld\n", yasm_intnum_get_int(msd->value));
- else
- fprintf(f, "nil\n");
-}
-
-
-/* Define valid debug formats to use with this object format */
-static const char *macho_objfmt_dbgfmt_keywords[] = {
- "null",
- NULL
-};
-
-/* Define objfmt structure -- see objfmt.h for details */
-yasm_objfmt_module yasm_macho_LTX_objfmt = {
- "Mac OS X ABI Mach-O File Format",
- "macho",
- "o",
- 32,
- 0,
- macho_objfmt_dbgfmt_keywords,
- "null",
- NULL, /* no directives */
- NULL, /* no standard macros */
- macho_objfmt_create,
- macho_objfmt_output,
- macho_objfmt_destroy,
- macho_objfmt_add_default_section,
- macho_objfmt_init_new_section,
- macho_objfmt_section_switch,
- macho_objfmt_get_special_sym
-};
-
-yasm_objfmt_module yasm_macho32_LTX_objfmt = {
- "Mac OS X ABI Mach-O File Format (32-bit)",
- "macho32",
- "o",
- 32,
- 0,
- macho_objfmt_dbgfmt_keywords,
- "null",
- NULL, /* no directives */
- NULL, /* no standard macros */
- macho32_objfmt_create,
- macho_objfmt_output,
- macho_objfmt_destroy,
- macho_objfmt_add_default_section,
- macho_objfmt_init_new_section,
- macho_objfmt_section_switch,
- macho_objfmt_get_special_sym
-};
-
-yasm_objfmt_module yasm_macho64_LTX_objfmt = {
- "Mac OS X ABI Mach-O File Format (64-bit)",
- "macho64",
- "o",
- 64,
- 0,
- macho_objfmt_dbgfmt_keywords,
- "null",
- NULL, /* no directives */
- NULL, /* no standard macros */
- macho64_objfmt_create,
- macho_objfmt_output,
- macho_objfmt_destroy,
- macho_objfmt_add_default_section,
- macho_objfmt_init_new_section,
- macho_objfmt_section_switch,
- macho_objfmt_get_special_sym
-};
+/*
+ * Mac OS X ABI Mach-O File Format
+ *
+ * Copyright (C) 2007 Henryk Richter, built upon xdf objfmt (C) 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.
+ */
+/*
+ notes: This implementation is rather basic. There are several implementation
+ issues to be sorted out for full compliance and error resilience.
+ Some examples are given below (nasm syntax).
+
+ 1) section placement
+ Mach-O requires BSS sections to be placed last in object files. This
+ has to be done manually.
+ Example:
+
+ section .text
+ mov rax,[qword foo]
+ section .data
+ dw 0
+ section .bss
+ foo dw 0
+
+ 2) addressing issues
+
+ 2.1) symbol relative relocation (i.e. mov eax,[foo wrt bar])
+ Not implemented yet.
+
+ 2.2) data referencing in 64 bit mode
+ While ELF allows 32 bit absolute relocations in 64 bit mode, Mach-O
+ does not. Therefore code like
+ lea rbx,[_foo] ;48 8d 1c 25 00 00 00 00
+ mov rcx,[_bar] ;48 8b 0c 25 00 00 00 00
+ with a 32 bit address field cannot be relocated into an address >= 0x100000000 (OSX actually
+ uses that).
+
+ Actually, the only register where a 64 bit displacement is allowed in x86-64, is rax
+ as in the example 1).
+
+ A plausible workaround is either classic PIC (like in C), which is in turn
+ not implemented in this object format. The recommended was is PC relative
+ code (called RIP-relative in x86-64). So instead of the lines above, just write:
+ lea rbx,[_foo wrt rip]
+ mov rcx,[_bar wrt rip]
+
+ 2.3) section/data alignment
+ Normally, you specify sections with a specific alignment
+ and get your data layed out as desired. Unfortunately, the
+ linker in MacOS X seems to ignore the section alignment requests.
+ The workaround is an explicit alignment at the end of the text section.
+
+ section .text
+ movdqa xmm0,[_foo wrt rip]
+
+ align 16
+ section .data align=16
+ _foo dw 32,32,32,32,32,32,32,32
+
+ FIXME: perform that operation implicitly!
+
+ 2.4) cross section symbol differences unsupported in current implementation
+ [extern foo]
+ [extern bar]
+ section .data
+ dq bar-foo
+
+ Will currently produce an error though the necessary means are provided
+ by the Mach-O specification.
+
+*/
+
+#include <util.h>
+
+#include <libyasm.h>
+
+/* MACH-O DEFINES */
+/* Mach-O in-file header structure sizes (32 BIT, see below for 64 bit defs) */
+#define MACHO_HEADER_SIZE 28
+#define MACHO_SEGCMD_SIZE 56
+#define MACHO_SECTCMD_SIZE 68
+#define MACHO_SYMCMD_SIZE 24
+#define MACHO_NLIST_SIZE 12
+#define MACHO_RELINFO_SIZE 8
+
+/* 64 bit sizes */
+#define MACHO_HEADER64_SIZE 32
+#define MACHO_SEGCMD64_SIZE 72
+#define MACHO_SECTCMD64_SIZE 80
+#define MACHO_NLIST64_SIZE 16
+#define MACHO_RELINFO64_SIZE 8
+
+
+/* Mach-O file header values */
+#define MH_MAGIC 0xfeedface
+#define MH_MAGIC_64 0xfeedfacf
+
+/* CPU machine type */
+#define CPU_TYPE_I386 7 /* x86 platform */
+#define CPU_TYPE_X86_64 (CPU_TYPE_I386|CPU_ARCH_ABI64)
+#define CPU_ARCH_ABI64 0x01000000 /* 64 bit ABI */
+
+/* CPU machine subtype, e.g. processor */
+#define CPU_SUBTYPE_I386_ALL 3 /* all-x86 compatible */
+#define CPU_SUBTYPE_X86_64_ALL CPU_SUBTYPE_I386_ALL
+#define CPU_SUBTYPE_386 3
+#define CPU_SUBTYPE_486 4
+#define CPU_SUBTYPE_486SX (4 + 128)
+#define CPU_SUBTYPE_586 5
+#define CPU_SUBTYPE_INTEL(f, m) ((f) + ((m) << 4))
+#define CPU_SUBTYPE_PENT CPU_SUBTYPE_INTEL(5, 0)
+#define CPU_SUBTYPE_PENTPRO CPU_SUBTYPE_INTEL(6, 1)
+#define CPU_SUBTYPE_PENTII_M3 CPU_SUBTYPE_INTEL(6, 3)
+#define CPU_SUBTYPE_PENTII_M5 CPU_SUBTYPE_INTEL(6, 5)
+#define CPU_SUBTYPE_PENTIUM_4 CPU_SUBTYPE_INTEL(10, 0)
+
+#define CPU_SUBTYPE_INTEL_FAMILY(x) ((x) & 15)
+#define CPU_SUBTYPE_INTEL_FAMILY_MAX 15
+
+#define CPU_SUBTYPE_INTEL_MODEL(x) ((x) >> 4)
+#define CPU_SUBTYPE_INTEL_MODEL_ALL 0
+
+#define MH_OBJECT 0x1 /* object file */
+
+#define LC_SEGMENT 0x1 /* segment load command */
+#define LC_SYMTAB 0x2 /* symbol table load command */
+#define LC_SEGMENT_64 0x19 /* segment load command */
+
+
+#define VM_PROT_NONE 0x00
+#define VM_PROT_READ 0x01
+#define VM_PROT_WRITE 0x02
+#define VM_PROT_EXECUTE 0x04
+
+#define VM_PROT_DEFAULT (VM_PROT_READ | VM_PROT_WRITE | VM_PROT_EXECUTE)
+#define VM_PROT_ALL (VM_PROT_READ | VM_PROT_WRITE | VM_PROT_EXECUTE)
+
+#define SECTION_TYPE 0x000000ff /* section type mask */
+#define SECTION_ATTRIBUTES 0xffffff00UL/* section attributes mask */
+
+#define S_REGULAR 0x0 /* standard section */
+#define S_ZEROFILL 0x1 /* zerofill, in-memory only */
+#define S_CSTRING_LITERALS 0x2 /* literal C strings */
+#define S_4BYTE_LITERALS 0x3 /* only 4-byte literals */
+#define S_8BYTE_LITERALS 0x4 /* only 8-byte literals */
+#define S_LITERAL_POINTERS 0x5 /* only pointers to literals */
+#define S_NON_LAZY_SYMBOL_POINTERS 0x6 /* only non-lazy symbol pointers */
+#define S_LAZY_SYMBOL_POINTERS 0x7 /* only lazy symbol pointers */
+#define S_SYMBOL_STUBS 0x8 /* only symbol stubs; byte size of
+ * stub in the reserved2 field */
+#define S_MOD_INIT_FUNC_POINTERS 0x9 /* only function pointers for init */
+#define S_MOD_TERM_FUNC_POINTERS 0xa /* only function pointers for term */
+#define S_COALESCED 0xb /* symbols that are to be coalesced */
+#define S_GB_ZEROFILL 0xc /* >4GB zero fill on demand section */
+#define S_INTERPOSING 0xd /* only pairs of function pointers for
+ * interposing */
+#define S_16BYTE_LITERALS 0xe /* only 16 byte literals */
+
+#define S_ATTR_DEBUG 0x02000000 /* a debug section */
+#define SECTION_ATTRIBUTES_SYS 0x00ffff00 /* system setable attributes */
+#define S_ATTR_SOME_INSTRUCTIONS 0x00000400 /* section contains some
+ * machine instructions */
+#define S_ATTR_EXT_RELOC 0x00000200 /* section has external
+ * relocation entries */
+#define S_ATTR_LOC_RELOC 0x00000100 /* section has local
+ * relocation entries */
+
+#define SECTION_ATTRIBUTES_USR 0xff000000UL /* User setable attributes */
+#define S_ATTR_PURE_INSTRUCTIONS 0x80000000UL /* only true machine insns */
+#define S_ATTR_NO_TOC 0x40000000UL /* coalesced symbols that are
+ * not to be in a ranlib table
+ * of contents */
+#define S_ATTR_STRIP_STATIC_SYMS 0x20000000UL /* ok to strip static symbols
+ * in this section in files
+ * with the MH_DYLDLINK flag */
+#define S_ATTR_NO_DEAD_STRIP 0x10000000UL /* no dead stripping */
+#define S_ATTR_LIVE_SUPPORT 0x08000000UL /* blocks are live if they
+ * reference live blocks */
+#define S_ATTR_SELF_MODIFYING_CODE 0x04000000UL /* Used with i386 code stubs
+ * written on by dyld */
+
+/* macho references symbols in different ways whether they are linked at
+ * runtime (LAZY, read library functions) or at link time (NON_LAZY, mostly
+ * data)
+ *
+ * TODO: proper support for dynamically linkable modules would require the
+ * __import sections as well as the dsymtab command
+ */
+#define REFERENCE_FLAG_UNDEFINED_NON_LAZY 0x0
+#define REFERENCE_FLAG_UNDEFINED_LAZY 0x1
+
+#define align(x, y) \
+ (((x) + (y) - 1) & ~((y) - 1)) /* align x to multiple of y */
+
+#define align32(x) \
+ align(x, 4) /* align x to 32 bit boundary */
+
+#define macho_MAGIC 0x87654322
+
+/* Symbol table type field bit masks */
+#define N_STAB 0xe0 /* mask indicating stab entry */
+#define N_PEXT 0x10 /* private external bit */
+#define N_TYPE 0x0e /* mask for all the type bits */
+#define N_EXT 0x01 /* external (global) bit */
+
+/* Symbol table type field values */
+#define N_UNDF 0x00 /* undefined */
+#define N_ABS 0x02 /* absolute address */
+#define N_SECT 0x0e /* symbol is defined in a section */
+
+#define NO_SECT 0 /* no section for symbol in nlist */
+
+#define REGULAR_OUTBUF_SIZE 1024
+
+
+typedef struct macho_reloc {
+ yasm_reloc reloc;
+ int pcrel;
+ int length;
+ int ext;
+ enum reloc_type_x86_64 {
+ /* x86 relocations */
+ GENERIC_RELOC_VANILLA = 0, /* generic relocation */
+ GENERIC_RELOC_PAIR = 1, /* Only follows a GENERIC_RELOC_SECTDIFF */
+ GENERIC_RELOC_SECTDIFF = 2,
+ GENERIC_RELOC_PB_LA_PTR = 3, /* prebound lazy pointer */
+ GENERIC_RELOC_LOCAL_SECTDIFF = 4,
+
+ /* x86-64 relocations */
+ X86_64_RELOC_UNSIGNED = 0, /* for absolute addresses */
+ X86_64_RELOC_SIGNED = 1, /* for signed 32-bit displacement */
+ X86_64_RELOC_BRANCH = 2, /* a CALL/JMP insn with 32-bit disp */
+ X86_64_RELOC_GOT_LOAD = 3, /* a MOVQ load of a GOT entry */
+ X86_64_RELOC_GOT = 4, /* other GOT references */
+ X86_64_RELOC_SUBTRACTOR = 5, /* must be followed by a X86_64_RELOC_UNSIGNED */
+ X86_64_RELOC_SIGNED_1 = 6, /* signed 32-bit disp, -1 addend */
+ X86_64_RELOC_SIGNED_2 = 7, /* signed 32-bit disp, -2 addend */
+ X86_64_RELOC_SIGNED_4 = 8 /* signed 32-bit disp, -4 addend */
+ } type;
+} macho_reloc;
+
+typedef struct macho_section_data {
+ /*@dependent@*/ yasm_symrec *sym; /* symbol created for this section */
+ long scnum; /* section number (0=first section) */
+ /*@only@*/ char *segname; /* segment name in file */
+ /*@only@*/ char *sectname; /* section name in file */
+ unsigned long flags; /* S_* flags */
+ unsigned long size; /* size of raw data (section data) in bytes */
+ unsigned long offset; /* offset in raw data within file in bytes */
+ unsigned long vmoff; /* memory offset */
+ unsigned long nreloc; /* number of relocation entries */
+ unsigned int extreloc; /* external relocations present (0/1) */
+} macho_section_data;
+
+
+typedef struct macho_symrec_data {
+ unsigned long index; /* index in output order */
+ yasm_intnum *value; /* valid after writing symtable to file */
+ unsigned long length; /* length + 1 (plus auto underscore) */
+} macho_symrec_data;
+
+
+typedef struct yasm_objfmt_macho {
+ yasm_objfmt_base objfmt; /* base structure */
+
+ long parse_scnum; /* sect numbering in parser */
+ int bits; /* 32 / 64 */
+
+ yasm_symrec *gotpcrel_sym; /* ..gotpcrel */
+} yasm_objfmt_macho;
+
+
+typedef struct macho_objfmt_output_info {
+ yasm_object *object;
+ yasm_objfmt_macho *objfmt_macho;
+ yasm_errwarns *errwarns;
+ /*@dependent@ */ FILE *f;
+ /*@only@ */ unsigned char *buf;
+ yasm_section *sect;
+ /*@dependent@ */ macho_section_data *msd;
+
+ unsigned int is_64; /* write object in 64 bit mode */
+
+ /* vmsize and filesize available after traversing section count routine */
+ unsigned long vmsize; /* raw size of all sections (including BSS) */
+ unsigned long filesize; /* size of sections in file (excluding BSS) */
+ unsigned long offset; /* offset within file */
+
+ /* forward offset tracking */
+ unsigned long rel_base; /* first relocation in file */
+ unsigned long s_reloff; /* in-file offset to relocations */
+
+ unsigned long indx; /* current symbol size in bytes (name length+1) */
+ unsigned long symindex; /* current symbol index in output order */
+ int all_syms; /* outputting all symbols? */
+ unsigned long strlength; /* length of all strings */
+} macho_objfmt_output_info;
+
+
+static void macho_section_data_destroy(/*@only@*/ void *d);
+static void macho_section_data_print(void *data, FILE *f, int indent_level);
+
+static const yasm_assoc_data_callback macho_section_data_cb = {
+ macho_section_data_destroy,
+ macho_section_data_print
+};
+
+static void macho_symrec_data_destroy(/*@only@*/ void *d);
+static void macho_symrec_data_print(void *data, FILE *f, int indent_level);
+
+static const yasm_assoc_data_callback macho_symrec_data_cb = {
+ macho_symrec_data_destroy,
+ macho_symrec_data_print
+};
+
+yasm_objfmt_module yasm_macho_LTX_objfmt;
+yasm_objfmt_module yasm_macho32_LTX_objfmt;
+yasm_objfmt_module yasm_macho64_LTX_objfmt;
+
+static yasm_objfmt *
+macho_objfmt_create_common(yasm_object *object, yasm_objfmt_module *module,
+ int bits_pref)
+{
+ yasm_objfmt_macho *objfmt_macho = yasm_xmalloc(sizeof(yasm_objfmt_macho));
+
+ objfmt_macho->objfmt.module = module;
+
+ /* Only support x86 arch for now */
+ if (yasm__strcasecmp(yasm_arch_keyword(object->arch), "x86") != 0) {
+ yasm_xfree(objfmt_macho);
+ return NULL;
+ }
+
+ /* Support x86 and amd64 machines of x86 arch */
+ if (yasm__strcasecmp(yasm_arch_get_machine(object->arch), "x86") == 0 &&
+ (bits_pref == 0 || bits_pref == 32)) {
+ objfmt_macho->bits = 32;
+ objfmt_macho->gotpcrel_sym = NULL;
+ } else if (yasm__strcasecmp(yasm_arch_get_machine(object->arch),
+ "amd64") == 0 &&
+ (bits_pref == 0 || bits_pref == 64)) {
+ objfmt_macho->bits = 64;
+ /* FIXME: misuse of NULL bytecode */
+ objfmt_macho->gotpcrel_sym =
+ yasm_symtab_define_label(object->symtab, "..gotpcrel", NULL, 0, 0);
+ } else {
+ yasm_xfree(objfmt_macho);
+ return NULL;
+ }
+
+ objfmt_macho->parse_scnum = 0; /* section numbering starts at 0 */
+ return (yasm_objfmt *)objfmt_macho;
+}
+
+static yasm_objfmt *
+macho_objfmt_create(yasm_object *object)
+{
+ yasm_objfmt *objfmt;
+ yasm_objfmt_macho *objfmt_macho;
+
+ objfmt = macho_objfmt_create_common(object, &yasm_macho_LTX_objfmt, 0);
+ if (objfmt) {
+ objfmt_macho = (yasm_objfmt_macho *)objfmt;
+ /* Figure out which bitness of object format to use */
+ if (objfmt_macho->bits == 32)
+ objfmt_macho->objfmt.module = &yasm_macho32_LTX_objfmt;
+ else if (objfmt_macho->bits == 64)
+ objfmt_macho->objfmt.module = &yasm_macho64_LTX_objfmt;
+ }
+ return objfmt;
+}
+
+static yasm_objfmt *
+macho32_objfmt_create(yasm_object *object)
+{
+ return macho_objfmt_create_common(object, &yasm_macho32_LTX_objfmt, 32);
+}
+
+static yasm_objfmt *
+macho64_objfmt_create(yasm_object *object)
+{
+ return macho_objfmt_create_common(object, &yasm_macho64_LTX_objfmt, 64);
+}
+
+static int
+macho_objfmt_output_value(yasm_value *value, unsigned char *buf,
+ unsigned int destsize, unsigned long offset,
+ yasm_bytecode *bc, int warn, /*@null@*/ void *d)
+{
+ /*@null@*/ macho_objfmt_output_info *info = (macho_objfmt_output_info *)d;
+ yasm_objfmt_macho *objfmt_macho;
+ /*@dependent@*/ /*@null@*/ yasm_intnum *intn;
+ unsigned long intn_minus = 0, intn_plus = 0;
+ int retval;
+ unsigned int valsize = value->size;
+ macho_reloc *reloc = NULL;
+
+ assert(info != NULL);
+ objfmt_macho = info->objfmt_macho;
+
+ if (value->abs)
+ value->abs = yasm_expr_simplify(value->abs, 1);
+
+ /* Try to output constant and PC-relative section-local first.
+ * Note this does NOT output any value with a SEG, WRT, external,
+ * cross-section, or non-PC-relative reference (those are handled below).
+ */
+ switch (yasm_value_output_basic(value, buf, destsize, bc, warn,
+ info->object->arch)) {
+ case -1:
+ return 1;
+ case 0:
+ break;
+ default:
+ return 0;
+ }
+
+ if (value->section_rel) {
+ yasm_error_set(YASM_ERROR_TOO_COMPLEX,
+ N_("macho: relocation too complex for current implementation"));
+ return 1;
+ }
+
+ if (value->rel) {
+ yasm_sym_vis vis = yasm_symrec_get_visibility(value->rel);
+
+ reloc = yasm_xcalloc(sizeof(macho_reloc), 1);
+ reloc->reloc.addr = yasm_intnum_create_uint(bc->offset + offset);
+ reloc->reloc.sym = value->rel;
+ switch (valsize) {
+ case 64:
+ reloc->length = 3;
+ break;
+ case 32:
+ reloc->length = 2;
+ break;
+ case 16:
+ reloc->length = 1;
+ break;
+ case 8:
+ reloc->length = 0;
+ break;
+ default:
+ yasm_error_set(YASM_ERROR_TOO_COMPLEX,
+ N_("macho: relocation size unsupported"));
+ yasm_xfree(reloc);
+ return 1;
+ }
+ reloc->pcrel = 0;
+ reloc->ext = 0;
+ reloc->type = GENERIC_RELOC_VANILLA;
+ /* R_ABS */
+
+ if (value->rshift > 0) {
+ yasm_error_set(YASM_ERROR_TOO_COMPLEX,
+ N_("macho: shifted relocations not supported"));
+ yasm_xfree(reloc);
+ return 1;
+ }
+
+ if (value->seg_of) {
+ yasm_error_set(YASM_ERROR_TOO_COMPLEX,
+ N_("macho: SEG not supported"));
+ yasm_xfree(reloc);
+ return 1;
+ }
+
+ if (value->curpos_rel && objfmt_macho->gotpcrel_sym &&
+ value->wrt == objfmt_macho->gotpcrel_sym) {
+ reloc->type = X86_64_RELOC_GOT;
+ value->wrt = NULL;
+ } else if (value->wrt) {
+ yasm_error_set(YASM_ERROR_TOO_COMPLEX,
+ N_("macho: invalid WRT"));
+ yasm_xfree(reloc);
+ return 1;
+ }
+
+ if (value->curpos_rel) {
+ reloc->pcrel = 1;
+ if (!info->is_64) {
+ /* Adjust to start of section, so subtract out the bytecode
+ * offset.
+ */
+ intn_minus = bc->offset;
+ } else {
+ /* Add in the offset plus value size to end up with 0. */
+ intn_plus = offset+destsize;
+ if (reloc->type == X86_64_RELOC_GOT) {
+ /* XXX: This is a hack */
+ if (offset >= 2 && buf[-2] == 0x8B)
+ reloc->type = X86_64_RELOC_GOT_LOAD;
+ } else if (value->jump_target)
+ reloc->type = X86_64_RELOC_BRANCH;
+ else
+ reloc->type = X86_64_RELOC_SIGNED;
+ }
+ } else if (info->is_64) {
+ if (valsize == 32) {
+ yasm_error_set(YASM_ERROR_NOT_CONSTANT,
+ N_("macho: sorry, cannot apply 32 bit absolute relocations in 64 bit mode, consider \"[_symbol wrt rip]\" for mem access, \"qword\" and \"dq _foo\" for pointers."));
+ return 1;
+ }
+ reloc->type = X86_64_RELOC_UNSIGNED;
+ }
+
+ /* It seems that x86-64 objects need to have all extern relocs? */
+ if (info->is_64)
+ reloc->ext = 1;
+
+ if ((vis & YASM_SYM_EXTERN) || (vis & YASM_SYM_COMMON)) {
+ reloc->ext = 1;
+ info->msd->extreloc = 1; /* section has external relocations */
+ } else if (!info->is_64) {
+ /*@dependent@*/ /*@null@*/ yasm_bytecode *sym_precbc;
+
+ /* Local symbols need valued to their actual address */
+ if (yasm_symrec_get_label(value->rel, &sym_precbc)) {
+ yasm_section *sym_sect = yasm_bc_get_section(sym_precbc);
+ /*@null@*/ macho_section_data *msd;
+ msd = yasm_section_get_data(sym_sect, &macho_section_data_cb);
+ assert(msd != NULL);
+ intn_plus += msd->vmoff + yasm_bc_next_offset(sym_precbc);
+ }
+ }
+
+ info->msd->nreloc++;
+ /*printf("reloc %s type %d ",yasm_symrec_get_name(reloc->reloc.sym),reloc->type);*/
+ yasm_section_add_reloc(info->sect, (yasm_reloc *)reloc, yasm_xfree);
+ }
+
+ if (intn_minus <= intn_plus)
+ intn = yasm_intnum_create_uint(intn_plus-intn_minus);
+ else {
+ intn = yasm_intnum_create_uint(intn_minus-intn_plus);
+ yasm_intnum_calc(intn, YASM_EXPR_NEG, NULL);
+ }
+
+ if (value->abs) {
+ yasm_intnum *intn2 = yasm_expr_get_intnum(&value->abs, 0);
+
+ if (!intn2) {
+ yasm_error_set(YASM_ERROR_TOO_COMPLEX,
+ N_("macho: relocation too complex"));
+ yasm_intnum_destroy(intn);
+ return 1;
+ }
+ yasm_intnum_calc(intn, YASM_EXPR_ADD, intn2);
+ }
+
+ retval = yasm_arch_intnum_tobytes(info->object->arch, intn, buf, destsize,
+ valsize, 0, bc, warn);
+ /*printf("val %ld\n",yasm_intnum_get_int(intn));*/
+ yasm_intnum_destroy(intn);
+ return retval;
+}
+
+static int
+macho_objfmt_output_bytecode(yasm_bytecode *bc, /*@null@*/ void *d)
+{
+ /*@null@*/ macho_objfmt_output_info *info = (macho_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,
+ macho_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: 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;
+}
+
+static int
+macho_objfmt_output_section(yasm_section *sect, /*@null@ */ void *d)
+{
+ /*@null@ */ macho_objfmt_output_info *info =
+ (macho_objfmt_output_info *) d;
+ /*@dependent@ *//*@null@ */ macho_section_data *msd;
+
+ assert(info != NULL);
+ msd = yasm_section_get_data(sect, &macho_section_data_cb);
+ assert(msd != NULL);
+
+ if (!(msd->flags & S_ZEROFILL)) {
+ /* Output non-BSS sections */
+ info->sect = sect;
+ info->msd = msd;
+ yasm_section_bcs_traverse(sect, info->errwarns, info,
+ macho_objfmt_output_bytecode);
+ }
+ return 0;
+}
+
+static int
+macho_objfmt_output_relocs(yasm_section *sect, /*@null@*/ void *d)
+{
+ /*@null@*/ macho_objfmt_output_info *info = (macho_objfmt_output_info *)d;
+ /*@dependent@*/ /*@null@*/ macho_section_data *msd;
+ macho_reloc *reloc;
+
+ reloc = (macho_reloc *)yasm_section_relocs_first(sect);
+ while (reloc) {
+ unsigned char *localbuf = info->buf;
+ /*@null@*/ macho_symrec_data *xsymd;
+ unsigned long symnum;
+
+ xsymd = yasm_symrec_get_data(reloc->reloc.sym, &macho_symrec_data_cb);
+ yasm_intnum_get_sized(reloc->reloc.addr, localbuf, 4, 32, 0, 0, 0);
+ localbuf += 4; /* address of relocation */
+
+ if (reloc->ext)
+ symnum = xsymd->index;
+ else {
+ /* find section where the symbol relates to */
+ /*@dependent@*/ /*@null@*/ yasm_section *dsect;
+ /*@dependent@*/ /*@null@*/ yasm_bytecode *precbc;
+ symnum = 0; /* default to absolute */
+ if (yasm_symrec_get_label(reloc->reloc.sym, &precbc) &&
+ (dsect = yasm_bc_get_section(precbc)) &&
+ (msd = yasm_section_get_data(dsect, &macho_section_data_cb)))
+ symnum = msd->scnum+1;
+ }
+ YASM_WRITE_32_L(localbuf,
+ (symnum & 0x00ffffff) |
+ (((unsigned long)reloc->pcrel & 1) << 24) |
+ (((unsigned long)reloc->length & 3) << 25) |
+ (((unsigned long)reloc->ext & 1) << 27) |
+ (((unsigned long)reloc->type & 0xf) << 28));
+ fwrite(info->buf, 8, 1, info->f);
+ reloc = (macho_reloc *)yasm_section_reloc_next((yasm_reloc *)reloc);
+ }
+
+ return 0;
+}
+
+static int
+exp2_to_bits(unsigned long val)
+{
+ int ret = 0;
+
+ while (val) {
+ val >>= 1;
+ ret++;
+ }
+ ret = (ret > 0) ? ret - 1 : 0;
+
+ return ret;
+}
+
+static int
+macho_objfmt_is_section_label(yasm_symrec *sym)
+{
+ /*@dependent@*/ /*@null@*/ yasm_section *sect;
+ /*@dependent@*/ /*@null@*/ yasm_bytecode *precbc;
+
+ /* Look at symrec for value/scnum/etc. */
+ if (yasm_symrec_get_label(sym, &precbc)) {
+ if (precbc)
+ sect = yasm_bc_get_section(precbc);
+ else
+ sect = NULL;
+ /* it's a label: get value and offset.
+ * If there is not a section, leave as debugging symbol.
+ */
+ if (sect) {
+ /*@dependent@*/ /*@null@*/ macho_section_data *msd;
+
+ msd = yasm_section_get_data(sect, &macho_section_data_cb);
+ if (msd) {
+ if (msd->sym == sym)
+ return 1; /* don't store section names */
+ }
+ }
+ }
+ return 0;
+}
+
+static int
+macho_objfmt_output_secthead(yasm_section *sect, /*@null@*/ void *d)
+{
+ /*@null@*/ macho_objfmt_output_info *info = (macho_objfmt_output_info *)d;
+ /*@dependent@*/ /*@null@*/ macho_section_data *msd;
+ unsigned char *localbuf;
+
+ assert(info != NULL);
+ msd = yasm_section_get_data(sect, &macho_section_data_cb);
+ assert(msd != NULL);
+
+ localbuf = info->buf;
+
+ memset(localbuf, 0, 16);
+ strncpy((char *)localbuf, msd->sectname, 16);
+ localbuf += 16;
+ memset(localbuf, 0, 16);
+ strncpy((char *)localbuf, msd->segname, 16);
+ localbuf += 16;
+ /* section address, size depend on 32/64 bit mode */
+ YASM_WRITE_32_L(localbuf, msd->vmoff); /* address in memory */
+ if (info->is_64)
+ YASM_WRITE_32_L(localbuf, 0); /* 64-bit mode: upper 32 bits = 0 */
+ YASM_WRITE_32_L(localbuf, msd->size); /* size in memory */
+ if (info->is_64)
+ YASM_WRITE_32_L(localbuf, 0); /* 64-bit mode: upper 32 bits = 0 */
+
+ /* offset,align,reloff,nreloc,flags,reserved1,reserved2 are 32 bit */
+ if ((msd->flags & SECTION_TYPE) != S_ZEROFILL) {
+ YASM_WRITE_32_L(localbuf, msd->offset);
+ YASM_WRITE_32_L(localbuf, exp2_to_bits(yasm_section_get_align(sect)));
+ if (msd->nreloc) {
+ msd->flags |= S_ATTR_LOC_RELOC;
+ if (msd->extreloc)
+ msd->flags |= S_ATTR_EXT_RELOC;
+ YASM_WRITE_32_L(localbuf,
+ align32((long)(info->rel_base + info->s_reloff)));
+ YASM_WRITE_32_L(localbuf, msd->nreloc); /* nreloc */
+ } else {
+ YASM_WRITE_32_L(localbuf, 0);
+ YASM_WRITE_32_L(localbuf, 0);
+ }
+
+ info->s_reloff += msd->nreloc * MACHO_RELINFO_SIZE; /* nreloc */
+ } else {
+ YASM_WRITE_32_L(localbuf, 0); /* these are zero in BSS */
+ YASM_WRITE_32_L(localbuf, 0);
+ YASM_WRITE_32_L(localbuf, 0);
+ YASM_WRITE_32_L(localbuf, 0);
+ }
+
+ YASM_WRITE_32_L(localbuf, msd->flags); /* flags */
+ YASM_WRITE_32_L(localbuf, 0); /* reserved 1 */
+ YASM_WRITE_32_L(localbuf, 0); /* reserved 2 */
+
+ if (info->is_64)
+ fwrite(info->buf, MACHO_SECTCMD64_SIZE, 1, info->f);
+ else
+ fwrite(info->buf, MACHO_SECTCMD_SIZE, 1, info->f);
+
+ return 0;
+}
+
+
+static int
+macho_objfmt_count_sym(yasm_symrec *sym, /*@null@*/ void *d)
+{
+ /*@null@*/ macho_objfmt_output_info *info = (macho_objfmt_output_info *)d;
+ /*@only@*/ char *name;
+ yasm_sym_vis vis = yasm_symrec_get_visibility(sym);
+
+ assert(info != NULL);
+ if (info->all_syms ||
+ vis & (YASM_SYM_GLOBAL | YASM_SYM_COMMON | YASM_SYM_EXTERN)) {
+ if (0 == macho_objfmt_is_section_label(sym)) {
+ /* Save index in symrec data */
+ macho_symrec_data *sym_data =
+ yasm_symrec_get_data(sym, &macho_symrec_data_cb);
+ if (!sym_data) {
+ sym_data = yasm_xcalloc(sizeof(macho_symrec_data), 1);
+ yasm_symrec_add_data(sym, &macho_symrec_data_cb, sym_data);
+ }
+ sym_data->index = info->symindex;
+ info->symindex++;
+
+ name = yasm_symrec_get_global_name(sym, info->object);
+ /*printf("%s\n",name); */
+ /* name length + delimiter */
+ sym_data->length = (unsigned long)strlen(name) + 1;
+ info->strlength += sym_data->length;
+ info->indx++;
+ yasm_xfree(name);
+ }
+ }
+ return 0;
+}
+
+
+static int
+macho_objfmt_output_symtable(yasm_symrec *sym, /*@null@*/ void *d)
+{
+ /*@null@*/ macho_objfmt_output_info *info = (macho_objfmt_output_info *)d;
+ yasm_sym_vis vis = yasm_symrec_get_visibility(sym);
+
+ assert(info != NULL);
+
+ if (info->all_syms ||
+ vis & (YASM_SYM_GLOBAL | YASM_SYM_COMMON | YASM_SYM_EXTERN)) {
+ const yasm_expr *equ_val;
+ const yasm_intnum *intn;
+ unsigned long value = 0;
+ long scnum = -3; /* -3 = debugging symbol */
+ /*@dependent@*/ /*@null@*/ yasm_section *sect;
+ /*@dependent@*/ /*@null@*/ yasm_bytecode *precbc;
+ unsigned char *localbuf;
+ yasm_intnum *val;
+ unsigned int long_int_bytes = (info->is_64) ? 8 : 4;
+ unsigned int n_type = 0, n_sect = 0, n_desc = 0;
+ macho_symrec_data *symd;
+
+ val = yasm_intnum_create_uint(0);
+
+ symd = yasm_symrec_get_data(sym, &macho_symrec_data_cb);
+
+ /* Look at symrec for value/scnum/etc. */
+ if (yasm_symrec_get_label(sym, &precbc)) {
+ if (precbc)
+ sect = yasm_bc_get_section(precbc);
+ else
+ sect = NULL;
+ /* it's a label: get value and offset.
+ * If there is not a section, leave as debugging symbol.
+ */
+ if (sect) {
+ /*@dependent@*/ /*@null@*/ macho_section_data *msd;
+
+ msd = yasm_section_get_data(sect, &macho_section_data_cb);
+ if (msd) {
+ if (msd->sym == sym) {
+ /* don't store section names */
+ yasm_intnum_destroy(val);
+ return 0;
+ }
+ scnum = msd->scnum;
+ n_type = N_SECT;
+ } else
+ yasm_internal_error(N_("didn't understand section"));
+ if (precbc)
+ value += yasm_bc_next_offset(precbc);
+ /* all values are subject to correction: base offset is first
+ * raw section, therefore add section offset
+ */
+ if (msd)
+ value += msd->vmoff;
+ yasm_intnum_set_uint(val, value);
+ /*printf("%s offset %lx\n",name,value);*/
+ }
+ } else if ((equ_val = yasm_symrec_get_equ(sym))) {
+ yasm_expr *equ_val_copy = yasm_expr_copy(equ_val);
+
+ intn = yasm_expr_get_intnum(&equ_val_copy, 1);
+ if (!intn) {
+ if (vis & YASM_SYM_GLOBAL) {
+ yasm_error_set(YASM_ERROR_NOT_CONSTANT,
+ N_("global EQU value not an integer expression"));
+ yasm_errwarn_propagate(info->errwarns, equ_val->line);
+ }
+ } else
+ value = yasm_intnum_get_uint(intn);
+ yasm_expr_destroy(equ_val_copy);
+ yasm_intnum_set_uint(val, value);
+ n_type = N_ABS;
+ scnum = -2; /* -2 = absolute symbol */
+ }
+
+ if (vis & YASM_SYM_EXTERN) {
+ n_type = N_EXT;
+ scnum = -1;
+ /*n_desc = REFERENCE_FLAG_UNDEFINED_LAZY; * FIXME: see definition of REFERENCE_FLAG_* above */
+ } else if (vis & YASM_SYM_COMMON) {
+ yasm_expr **csize = yasm_symrec_get_common_size(sym);
+ n_type = N_UNDF | N_EXT;
+ if (csize) {
+ intn = yasm_expr_get_intnum(csize, 1);
+ if (!intn) {
+ yasm_error_set(YASM_ERROR_NOT_CONSTANT,
+ N_("COMMON data size not an integer expression"));
+ yasm_errwarn_propagate(info->errwarns, (*csize)->line);
+ } else
+ yasm_intnum_set_uint(val, yasm_intnum_get_uint(intn));
+ }
+ /*printf("common symbol %s val %lu\n", name, yasm_intnum_get_uint(val));*/
+ } else if (vis & YASM_SYM_GLOBAL) {
+ yasm_valparamhead *valparams =
+ yasm_symrec_get_objext_valparams(sym);
+
+ struct macho_global_data {
+ unsigned long flag; /* N_PEXT */
+ } data;
+
+ data.flag = 0;
+
+ if (valparams) {
+ static const yasm_dir_help help[] = {
+ { "private_extern", 0, yasm_dir_helper_flag_set,
+ offsetof(struct macho_global_data, flag), N_PEXT },
+ };
+ yasm_dir_helper(sym, yasm_vps_first(valparams),
+ yasm_symrec_get_decl_line(sym), help, NELEMS(help),
+ &data, yasm_dir_helper_valparam_warn);
+ }
+
+ n_type |= N_EXT | data.flag;
+ }
+
+ localbuf = info->buf;
+ YASM_WRITE_32_L(localbuf, info->indx); /* offset in string table */
+ YASM_WRITE_8(localbuf, n_type); /* type of symbol entry */
+ n_sect = (scnum >= 0) ? scnum + 1 : NO_SECT;
+ YASM_WRITE_8(localbuf, n_sect); /* referring section where symbol is found */
+ YASM_WRITE_16_L(localbuf, n_desc); /* extra description */
+ yasm_intnum_get_sized(val, localbuf, long_int_bytes, ((long_int_bytes) << 3), 0, 0, 0); /* value/argument */
+ localbuf += long_int_bytes;
+ if (symd)
+ symd->value = val;
+ else
+ yasm_intnum_destroy(val);
+
+ info->indx += symd->length;
+
+ fwrite(info->buf, 8 + long_int_bytes, 1, info->f);
+ }
+
+ return 0;
+}
+
+
+static int
+macho_objfmt_output_str(yasm_symrec *sym, /*@null@*/ void *d)
+{
+ /*@null@*/ macho_objfmt_output_info *info = (macho_objfmt_output_info *)d;
+ yasm_sym_vis vis = yasm_symrec_get_visibility(sym);
+
+ assert(info != NULL);
+
+ if (info->all_syms ||
+ vis & (YASM_SYM_GLOBAL | YASM_SYM_COMMON | YASM_SYM_EXTERN)) {
+ if (0 == macho_objfmt_is_section_label(sym)) {
+ /*@only@*/ char *name =
+ yasm_symrec_get_global_name(sym, info->object);
+ size_t len = strlen(name);
+
+ fwrite(name, len + 1, 1, info->f);
+ yasm_xfree(name);
+ }
+ }
+ return 0;
+}
+
+static int
+macho_objfmt_calc_sectsize(yasm_section *sect, /*@null@ */ void *d)
+{
+ /*@null@ */ macho_objfmt_output_info *info =
+ (macho_objfmt_output_info *) d;
+ /*@dependent@ *//*@null@ */ macho_section_data *msd;
+ unsigned long align;
+
+ assert(info != NULL);
+ msd = yasm_section_get_data(sect, &macho_section_data_cb);
+ assert(msd != NULL);
+
+ msd->size = yasm_bc_next_offset(yasm_section_bcs_last(sect));
+ if (!(msd->flags & S_ZEROFILL)) {
+ msd->offset = info->offset;
+ info->offset += msd->size;
+ info->filesize += msd->size;
+ }
+
+ /* accumulate size in memory */
+ msd->vmoff = info->vmsize;
+ info->vmsize += msd->size;
+
+ /* align both start and end of section */
+ align = yasm_section_get_align(sect);
+ if (align != 0) {
+ unsigned long delta = msd->vmoff % align;
+ if (delta > 0) {
+ msd->vmoff += align - delta;
+ info->vmsize += align - delta;
+ }
+ }
+
+ return 0;
+}
+
+/* write object */
+static void
+macho_objfmt_output(yasm_object *object, FILE *f, int all_syms,
+ yasm_errwarns *errwarns)
+{
+ yasm_objfmt_macho *objfmt_macho = (yasm_objfmt_macho *)object->objfmt;
+ macho_objfmt_output_info info;
+ unsigned char *localbuf;
+ unsigned long symtab_count = 0;
+ unsigned long headsize;
+ unsigned int macho_segcmdsize, macho_sectcmdsize, macho_nlistsize;
+ unsigned int macho_segcmd;
+ unsigned int head_ncmds, head_sizeofcmds;
+ unsigned long fileoffset, fileoff_sections;
+ yasm_intnum *val;
+ unsigned long long_int_bytes;
+ const char pad_data[3] = "\0\0\0";
+
+ info.object = object;
+ info.objfmt_macho = objfmt_macho;
+ info.errwarns = errwarns;
+ info.f = f;
+ info.buf = yasm_xmalloc(REGULAR_OUTBUF_SIZE);
+
+ if (objfmt_macho->parse_scnum == 0) {
+ yasm_internal_error(N_("no sections defined"));
+ /*@notreached@*/
+ return;
+ }
+
+ val = yasm_intnum_create_uint(0);
+
+ /*
+ * MACH-O Header, Seg CMD, Sect CMDs, Sym Tab, Reloc Data
+ */
+ info.is_64 = (objfmt_macho->bits == 32) ? 0 : 1;
+ if (info.is_64) {
+ /* this works only when SYMBOLS and SECTIONS present */
+ headsize =
+ MACHO_HEADER64_SIZE + MACHO_SEGCMD64_SIZE +
+ (MACHO_SECTCMD64_SIZE * (objfmt_macho->parse_scnum)) +
+ MACHO_SYMCMD_SIZE;
+ macho_segcmd = LC_SEGMENT_64;
+ macho_segcmdsize = MACHO_SEGCMD64_SIZE;
+ macho_sectcmdsize = MACHO_SECTCMD64_SIZE;
+ macho_nlistsize = MACHO_NLIST64_SIZE;
+ long_int_bytes = 8;
+ } else {
+ headsize =
+ MACHO_HEADER_SIZE + MACHO_SEGCMD_SIZE +
+ (MACHO_SECTCMD_SIZE * (objfmt_macho->parse_scnum)) +
+ MACHO_SYMCMD_SIZE;
+ macho_segcmd = LC_SEGMENT;
+ macho_segcmdsize = MACHO_SEGCMD_SIZE;
+ macho_sectcmdsize = MACHO_SECTCMD_SIZE;
+ macho_nlistsize = MACHO_NLIST_SIZE;
+ long_int_bytes = 4;
+ }
+
+ /* Get number of symbols */
+ info.symindex = 0;
+ info.indx = 0;
+ info.strlength = 1; /* string table starts with a zero byte */
+ info.all_syms = all_syms || info.is_64;
+ /*info.all_syms = 1; * force all syms into symbol table */
+ yasm_symtab_traverse(object->symtab, &info, macho_objfmt_count_sym);
+ symtab_count = info.indx;
+
+ /* write raw section data first */
+ if (fseek(f, (long)headsize, SEEK_SET) < 0) {
+ yasm__fatal(N_("could not seek on output file"));
+ /*@notreached@ */
+ return;
+ }
+
+ /* get size of sections in memory (including BSS) and size of sections
+ * in file (without BSS)
+ */
+ info.vmsize = 0;
+ info.filesize = 0;
+ info.offset = headsize;
+ yasm_object_sections_traverse(object, &info, macho_objfmt_calc_sectsize);
+
+ /* output sections to file */
+ yasm_object_sections_traverse(object, &info, macho_objfmt_output_section);
+
+ fileoff_sections = ftell(f);
+
+ /* Write headers */
+ if (fseek(f, 0, SEEK_SET) < 0) {
+ yasm__fatal(N_("could not seek on output file"));
+ /*@notreached@*/
+ return;
+ }
+
+ localbuf = info.buf;
+
+ /* header size is common to 32 bit and 64 bit variants */
+ if (info.is_64) {
+ YASM_WRITE_32_L(localbuf, MH_MAGIC_64); /* magic number */
+ /* i386 64-bit ABI */
+ YASM_WRITE_32_L(localbuf, CPU_ARCH_ABI64 | CPU_TYPE_I386);
+ } else {
+ YASM_WRITE_32_L(localbuf, MH_MAGIC); /* magic number */
+ YASM_WRITE_32_L(localbuf, CPU_TYPE_I386); /* i386 32-bit ABI */
+ }
+ /* i386 all cpu subtype compatible */
+ YASM_WRITE_32_L(localbuf, CPU_SUBTYPE_I386_ALL);
+ YASM_WRITE_32_L(localbuf, MH_OBJECT); /* MACH file type */
+
+ /* calculate number of commands and their size, put to stream */
+ head_ncmds = 0;
+ head_sizeofcmds = 0;
+ if (objfmt_macho->parse_scnum > 0) {
+ head_ncmds++;
+ head_sizeofcmds +=
+ macho_segcmdsize + macho_sectcmdsize * objfmt_macho->parse_scnum;
+ }
+ if (symtab_count > 0) {
+ head_ncmds++;
+ head_sizeofcmds += MACHO_SYMCMD_SIZE;
+ }
+
+ YASM_WRITE_32_L(localbuf, head_ncmds);
+ YASM_WRITE_32_L(localbuf, head_sizeofcmds);
+ YASM_WRITE_32_L(localbuf, 0); /* no flags (yet) */
+ if (info.is_64) {
+ YASM_WRITE_32_L(localbuf, 0); /* reserved in 64 bit */
+ fileoffset = MACHO_HEADER64_SIZE + head_sizeofcmds;
+ } else {
+ /* initial offset to first section */
+ fileoffset = MACHO_HEADER_SIZE + head_sizeofcmds;
+ }
+
+ /* --------------- write segment header command ---------------- */
+ YASM_WRITE_32_L(localbuf, macho_segcmd); /* command LC_SEGMENT */
+ /* size of load command including section load commands */
+ YASM_WRITE_32_L(localbuf,
+ macho_segcmdsize +
+ macho_sectcmdsize * objfmt_macho->parse_scnum);
+ /* in an MH_OBJECT file all sections are in one unnamed (name all zeros)
+ * segment (16x0)
+ */
+ YASM_WRITE_32_L(localbuf, 0);
+ YASM_WRITE_32_L(localbuf, 0);
+ YASM_WRITE_32_L(localbuf, 0);
+ YASM_WRITE_32_L(localbuf, 0);
+
+ /* in-memory offset, in-memory size */
+ yasm_intnum_set_uint(val, 0); /* offset in memory (vmaddr) */
+ yasm_intnum_get_sized(val, localbuf, long_int_bytes,
+ ((long_int_bytes) << 3), 0, 0, 0);
+ localbuf += long_int_bytes;
+ yasm_intnum_set_uint(val, info.vmsize); /* size in memory (vmsize) */
+ yasm_intnum_get_sized(val, localbuf, long_int_bytes,
+ ((long_int_bytes) << 3), 0, 0, 0);
+ localbuf += long_int_bytes;
+ /* offset in file to first section */
+ yasm_intnum_set_uint(val, fileoffset);
+ yasm_intnum_get_sized(val, localbuf, long_int_bytes,
+ ((long_int_bytes) << 3), 0, 0, 0);
+ localbuf += long_int_bytes;
+ yasm_intnum_set_uint(val, info.filesize); /* overall size in file */
+ yasm_intnum_get_sized(val, localbuf, long_int_bytes,
+ ((long_int_bytes) << 3), 0, 0, 0);
+ localbuf += long_int_bytes;
+
+ YASM_WRITE_32_L(localbuf, VM_PROT_DEFAULT); /* VM protection, maximum */
+ YASM_WRITE_32_L(localbuf, VM_PROT_DEFAULT); /* VM protection, initial */
+ /* number of sections */
+ YASM_WRITE_32_L(localbuf, objfmt_macho->parse_scnum);
+ YASM_WRITE_32_L(localbuf, 0); /* no flags */
+
+ /* write MACH-O header and segment command to outfile */
+ fwrite(info.buf, (size_t) (localbuf - info.buf), 1, f);
+
+ /* next: section headers */
+ /* offset to relocs for first section */
+ info.rel_base = align32((long)fileoff_sections);
+ info.s_reloff = 0; /* offset for relocs of following sections */
+ yasm_object_sections_traverse(object, &info, macho_objfmt_output_secthead);
+
+ localbuf = info.buf;
+ /* write out symbol command */
+ YASM_WRITE_32_L(localbuf, LC_SYMTAB); /* cmd == LC_SYMTAB */
+ YASM_WRITE_32_L(localbuf, MACHO_SYMCMD_SIZE);
+ /* symbol table offset */
+ YASM_WRITE_32_L(localbuf, info.rel_base + info.s_reloff);
+ YASM_WRITE_32_L(localbuf, symtab_count); /* number of symbols */
+
+ YASM_WRITE_32_L(localbuf, macho_nlistsize * symtab_count + info.rel_base +
+ info.s_reloff); /* string table offset */
+ YASM_WRITE_32_L(localbuf, info.strlength); /* string table size */
+ /* write symbol command */
+ fwrite(info.buf, (size_t)(localbuf - info.buf), 1, f);
+
+ /*printf("num symbols %d, vmsize %d, filesize %d\n",symtab_count,
+ info.vmsize, info.filesize ); */
+
+ /* get back to end of raw section data */
+ if (fseek(f, (long)fileoff_sections, SEEK_SET) < 0) {
+ yasm__fatal(N_("could not seek on output file"));
+ /*@notreached@*/
+ return;
+ }
+
+ /* padding to long boundary */
+ if ((info.rel_base - fileoff_sections) > 0) {
+ fwrite(pad_data, info.rel_base - fileoff_sections, 1, f);
+ }
+
+ /* relocation data */
+ yasm_object_sections_traverse(object, &info, macho_objfmt_output_relocs);
+
+ /* symbol table (NLIST) */
+ info.indx = 1; /* restart symbol table indices */
+ yasm_symtab_traverse(object->symtab, &info, macho_objfmt_output_symtable);
+
+ /* symbol strings */
+ fwrite(pad_data, 1, 1, f);
+ yasm_symtab_traverse(object->symtab, &info, macho_objfmt_output_str);
+
+ yasm_intnum_destroy(val);
+ yasm_xfree(info.buf);
+}
+
+static void
+macho_objfmt_destroy(yasm_objfmt *objfmt)
+{
+ yasm_xfree(objfmt);
+}
+
+static void
+macho_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_macho *objfmt_macho = (yasm_objfmt_macho *)object->objfmt;
+ macho_section_data *data;
+ yasm_symrec *sym;
+
+ data = yasm_xmalloc(sizeof(macho_section_data));
+ data->scnum = objfmt_macho->parse_scnum++;
+ data->segname = NULL;
+ data->sectname = NULL;
+ data->flags = S_REGULAR;
+ data->size = 0;
+ data->offset = 0;
+ data->vmoff = 0;
+ data->nreloc = 0;
+ data->extreloc = 0;
+ yasm_section_add_data(sect, &macho_section_data_cb, data);
+
+ sym = yasm_symtab_define_label(object->symtab, sectname,
+ yasm_section_bcs_first(sect), 1, line);
+ data->sym = sym;
+}
+
+static yasm_section *
+macho_objfmt_add_default_section(yasm_object *object)
+{
+ yasm_section *retval;
+ macho_section_data *msd;
+ int isnew;
+
+ retval = yasm_object_get_general(object, "LC_SEGMENT.__TEXT.__text", 0, 1,
+ 0, &isnew, 0);
+ if (isnew) {
+ msd = yasm_section_get_data(retval, &macho_section_data_cb);
+ msd->segname = yasm__xstrdup("__TEXT");
+ msd->sectname = yasm__xstrdup("__text");
+ msd->flags = S_ATTR_PURE_INSTRUCTIONS;
+ yasm_section_set_align(retval, 0, 0);
+ yasm_section_set_default(retval, 1);
+ }
+ return retval;
+}
+
+static /*@observer@*/ /*@null@*/ yasm_section *
+macho_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;
+ /*@only@*/ char *f_sectname;
+ unsigned long flags;
+ unsigned long align;
+ int flags_override = 0;
+ const char *sectname;
+ char *realname;
+ int resonly = 0;
+ macho_section_data *msd;
+ size_t i;
+
+ static const struct {
+ const char *in;
+ const char *seg;
+ const char *sect;
+ unsigned long flags;
+ unsigned long align;
+ } section_name_translation[] = {
+ {".text", "__TEXT", "__text", S_ATTR_PURE_INSTRUCTIONS, 0},
+ {".const", "__TEXT", "__const", S_REGULAR, 0},
+ {".static_const", "__TEXT", "__static_const", S_REGULAR, 0},
+ {".cstring", "__TEXT", "__cstring", S_CSTRING_LITERALS, 0},
+ {".literal4", "__TEXT", "__literal4", S_4BYTE_LITERALS, 4},
+ {".literal8", "__TEXT", "__literal8", S_8BYTE_LITERALS, 8},
+ {".literal16", "__TEXT", "__literal16", S_16BYTE_LITERALS, 16},
+ {".constructor", "__TEXT", "__constructor", S_REGULAR, 0},
+ {".destructor", "__TEXT", "__destructor", S_REGULAR, 0},
+ {".fvmlib_init0", "__TEXT", "__fvmlib_init0", S_REGULAR, 0},
+ {".fvmlib_init1", "__TEXT", "__fvmlib_init1", S_REGULAR, 0},
+ {".mod_init_func", "__DATA", "__mod_init_func",
+ S_MOD_INIT_FUNC_POINTERS, 4},
+ {".mod_term_func", "__DATA", "__mod_term_func",
+ S_MOD_TERM_FUNC_POINTERS, 4},
+ {".dyld", "__DATA", "__dyld", S_REGULAR, 0},
+ {".data", "__DATA", "__data", S_REGULAR, 0},
+ {".static_data", "__DATA", "__static_data", S_REGULAR, 0},
+ {".const_data", "__DATA", "__const", S_REGULAR, 0},
+ {".rodata", "__DATA", "__const", S_REGULAR, 0},
+ {".bss", "__DATA", "__bss", S_ZEROFILL, 0},
+ {".objc_class_names", "__TEXT", "__cstring", S_CSTRING_LITERALS, 0},
+ {".objc_meth_var_types","__TEXT", "__cstring", S_CSTRING_LITERALS, 0},
+ {".objc_meth_var_names","__TEXT", "__cstring", S_CSTRING_LITERALS, 0},
+ {".objc_selector_strs", "__OBJC", "__selector_strs",
+ S_CSTRING_LITERALS, 0},
+ {".objc_class", "__OBJC", "__class",
+ S_ATTR_NO_DEAD_STRIP, 0},
+ {".objc_meta_class", "__OBJC", "__meta_class",
+ S_ATTR_NO_DEAD_STRIP, 0},
+ {".objc_string_object", "__OBJC", "__string_object",
+ S_ATTR_NO_DEAD_STRIP, 0},
+ {".objc_protocol", "__OBJC", "__protocol",
+ S_ATTR_NO_DEAD_STRIP, 0},
+ {".objc_cat_cls_meth", "__OBJC", "__cat_cls_meth",
+ S_ATTR_NO_DEAD_STRIP, 0},
+ {".objc_cat_inst_meth", "__OBJC", "__cat_inst_meth",
+ S_ATTR_NO_DEAD_STRIP, 0},
+ {".objc_cls_meth", "__OBJC", "__cls_meth",
+ S_ATTR_NO_DEAD_STRIP, 0},
+ {".objc_inst_meth", "__OBJC", "__inst_meth",
+ S_ATTR_NO_DEAD_STRIP, 0},
+ {".objc_message_refs", "__OBJC", "__message_refs",
+ S_LITERAL_POINTERS|S_ATTR_NO_DEAD_STRIP, 4},
+ {".objc_cls_refs", "__OBJC", "__cls_refs",
+ S_LITERAL_POINTERS|S_ATTR_NO_DEAD_STRIP, 4},
+ {".objc_module_info", "__OBJC", "__module_info",
+ S_ATTR_NO_DEAD_STRIP, 0},
+ {".objc_symbols", "__OBJC", "__symbols",
+ S_ATTR_NO_DEAD_STRIP, 0},
+ {".objc_category", "__OBJC", "__category",
+ S_ATTR_NO_DEAD_STRIP, 0},
+ {".objc_class_vars", "__OBJC", "__class_vars",
+ S_ATTR_NO_DEAD_STRIP, 0},
+ {".objc_instance_vars", "__OBJC", "__instance_vars",
+ S_ATTR_NO_DEAD_STRIP, 0}
+ };
+
+ struct macho_section_switch_data {
+ /*@only@*/ /*@null@*/ char *f_segname;
+ /*@only@*/ /*@null@*/ yasm_intnum *align_intn;
+ } data;
+
+ static const yasm_dir_help help[] = {
+ { "segname", 1, yasm_dir_helper_string,
+ offsetof(struct macho_section_switch_data, f_segname), 0 },
+ { "align", 1, yasm_dir_helper_intn,
+ offsetof(struct macho_section_switch_data, align_intn), 0 }
+ };
+
+ data.f_segname = NULL;
+ data.align_intn = NULL;
+
+ vp = yasm_vps_first(valparams);
+ sectname = yasm_vp_string(vp);
+ if (!sectname)
+ return NULL;
+ vp = yasm_vps_next(vp);
+
+ /* translate .text,.data,.bss to __text,__data,__bss... */
+ for (i=0; i<NELEMS(section_name_translation); i++) {
+ if (yasm__strcasecmp(sectname, section_name_translation[i].in) == 0)
+ break;
+ }
+
+ if (i == NELEMS(section_name_translation)) {
+ const char *s;
+ if (vp && !vp->val && (s = yasm_vp_string(vp))) {
+ /* Treat as SEGNAME, SECTNAME */
+ if (strlen(sectname) > 16)
+ yasm_warn_set(YASM_WARN_GENERAL,
+ N_("segment name is too long, max 16 chars; truncating"));
+ data.f_segname = yasm__xstrndup(sectname, 16);
+ if (strlen(s) > 16)
+ yasm_warn_set(YASM_WARN_GENERAL,
+ N_("section name is too long, max 16 chars; truncating"));
+ f_sectname = yasm__xstrndup(s, 16);
+ flags = S_REGULAR;
+ align = 0;
+
+ sectname = s;
+ vp = yasm_vps_next(vp);
+ } else {
+ data.f_segname = NULL;
+ if (strlen(sectname) > 16)
+ yasm_warn_set(YASM_WARN_GENERAL,
+ N_("section name is too long, max 16 chars; truncating"));
+ f_sectname = yasm__xstrndup(sectname, 16);
+ flags = S_ATTR_SOME_INSTRUCTIONS;
+ align = 0;
+ }
+ } else {
+ data.f_segname = yasm__xstrdup(section_name_translation[i].seg);
+ f_sectname = yasm__xstrdup(section_name_translation[i].sect);
+ flags = section_name_translation[i].flags;
+ align = section_name_translation[i].align;
+ }
+
+ 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.align_intn) {
+ align = yasm_intnum_get_uint(data.align_intn);
+ yasm_intnum_destroy(data.align_intn);
+
+ /* 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"),
+ vp->val);
+ return NULL;
+ }
+
+ /* Check to see if alignment is supported size */
+ if (align > 16384) {
+ yasm_error_set(YASM_ERROR_VALUE,
+ N_("macho implementation does not support alignments > 16384"));
+ return NULL;
+ }
+ }
+
+ if (!data.f_segname) {
+ yasm_warn_set(YASM_WARN_GENERAL,
+ N_("Unknown section name, defaulting to __TEXT segment"));
+ data.f_segname = yasm__xstrdup("__TEXT");
+ }
+
+ /* Build a unique sectname from f_segname and f_sectname. */
+ realname = yasm_xmalloc(strlen("LC_SEGMENT") + 1 + strlen(data.f_segname) + 1 +
+ strlen(f_sectname) + 1);
+ sprintf(realname, "LC_SEGMENT.%s.%s", data.f_segname, f_sectname);
+ retval = yasm_object_get_general(object, realname, align, 1, resonly,
+ &isnew, line);
+ yasm_xfree(realname);
+
+ msd = yasm_section_get_data(retval, &macho_section_data_cb);
+
+ if (isnew || yasm_section_is_default(retval)) {
+ yasm_section_set_default(retval, 0);
+ msd->segname = data.f_segname;
+ msd->sectname = f_sectname;
+ msd->flags = flags;
+ yasm_section_set_align(retval, align, line);
+ } else if (flags_override) {
+ /* align is the only value used from overrides. */
+ if (yasm_section_get_align(retval) != align) {
+ yasm_warn_set(YASM_WARN_GENERAL,
+ N_("section flags ignored on section redeclaration"));
+ }
+ }
+ return retval;
+}
+
+static /*@observer@*/ /*@null@*/ yasm_symrec *
+macho_objfmt_get_special_sym(yasm_object *object, const char *name,
+ const char *parser)
+{
+ yasm_objfmt_macho *objfmt_macho = (yasm_objfmt_macho *)object->objfmt;
+ if (yasm__strcasecmp(name, "gotpcrel") == 0) {
+ return objfmt_macho->gotpcrel_sym;
+ }
+ return NULL;
+}
+
+static void
+macho_section_data_destroy(void *data)
+{
+ macho_section_data *msd = (macho_section_data *) data;
+ yasm_xfree(msd->segname);
+ yasm_xfree(msd->sectname);
+ yasm_xfree(data);
+}
+
+static void
+macho_section_data_print(void *data, FILE *f, int indent_level)
+{
+ macho_section_data *msd = (macho_section_data *) data;
+
+ fprintf(f, "%*ssym=\n", indent_level, "");
+ yasm_symrec_print(msd->sym, f, indent_level + 1);
+ fprintf(f, "%*sscnum=%ld\n", indent_level, "", msd->scnum);
+ fprintf(f, "%*sflags=0x%lx\n", indent_level, "", msd->flags);
+ fprintf(f, "%*ssize=%lu\n", indent_level, "", msd->size);
+ fprintf(f, "%*snreloc=%lu\n", indent_level, "", msd->nreloc);
+ fprintf(f, "%*soffset=%lu\n", indent_level, "", msd->offset);
+ fprintf(f, "%*sextreloc=%u\n", indent_level, "", msd->extreloc);
+}
+
+static void
+macho_symrec_data_destroy(void *data)
+{
+ yasm_xfree(data);
+}
+
+static void
+macho_symrec_data_print(void *data, FILE *f, int indent_level)
+{
+ macho_symrec_data *msd = (macho_symrec_data *)data;
+
+ fprintf(f, "%*sindex=%ld\n", indent_level, "", msd->index);
+ fprintf(f, "%*svalue=", indent_level, "");
+ if (msd->value)
+ fprintf(f, "%ld\n", yasm_intnum_get_int(msd->value));
+ else
+ fprintf(f, "nil\n");
+}
+
+
+/* Define valid debug formats to use with this object format */
+static const char *macho_objfmt_dbgfmt_keywords[] = {
+ "null",
+ NULL
+};
+
+/* Define objfmt structure -- see objfmt.h for details */
+yasm_objfmt_module yasm_macho_LTX_objfmt = {
+ "Mac OS X ABI Mach-O File Format",
+ "macho",
+ "o",
+ 32,
+ 0,
+ macho_objfmt_dbgfmt_keywords,
+ "null",
+ NULL, /* no directives */
+ NULL, /* no standard macros */
+ macho_objfmt_create,
+ macho_objfmt_output,
+ macho_objfmt_destroy,
+ macho_objfmt_add_default_section,
+ macho_objfmt_init_new_section,
+ macho_objfmt_section_switch,
+ macho_objfmt_get_special_sym
+};
+
+yasm_objfmt_module yasm_macho32_LTX_objfmt = {
+ "Mac OS X ABI Mach-O File Format (32-bit)",
+ "macho32",
+ "o",
+ 32,
+ 0,
+ macho_objfmt_dbgfmt_keywords,
+ "null",
+ NULL, /* no directives */
+ NULL, /* no standard macros */
+ macho32_objfmt_create,
+ macho_objfmt_output,
+ macho_objfmt_destroy,
+ macho_objfmt_add_default_section,
+ macho_objfmt_init_new_section,
+ macho_objfmt_section_switch,
+ macho_objfmt_get_special_sym
+};
+
+yasm_objfmt_module yasm_macho64_LTX_objfmt = {
+ "Mac OS X ABI Mach-O File Format (64-bit)",
+ "macho64",
+ "o",
+ 64,
+ 0,
+ macho_objfmt_dbgfmt_keywords,
+ "null",
+ NULL, /* no directives */
+ NULL, /* no standard macros */
+ macho64_objfmt_create,
+ macho_objfmt_output,
+ macho_objfmt_destroy,
+ macho_objfmt_add_default_section,
+ macho_objfmt_init_new_section,
+ macho_objfmt_section_switch,
+ macho_objfmt_get_special_sym
+};
diff --git a/contrib/tools/yasm/modules/objfmts/rdf/rdf-objfmt.c b/contrib/tools/yasm/modules/objfmts/rdf/rdf-objfmt.c
index eb3c66688c..a65c4b94dd 100644
--- a/contrib/tools/yasm/modules/objfmts/rdf/rdf-objfmt.c
+++ b/contrib/tools/yasm/modules/objfmts/rdf/rdf-objfmt.c
@@ -1,1088 +1,1088 @@
-/*
- * Relocatable Dynamic Object File Format (RDOFF) version 2 format
- *
- * Copyright (C) 2006-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>
-
-#include <libyasm.h>
-
-
-#define REGULAR_OUTBUF_SIZE 1024
-
-#define RDF_MAGIC "RDOFF2"
-
-/* Maximum size of an import/export label (including trailing zero) */
-#define EXIM_LABEL_MAX 64
-
-/* Maximum size of library or module name (including trailing zero) */
-#define MODLIB_NAME_MAX 128
-
-/* Maximum number of segments that we can handle in one file */
-#define RDF_MAXSEGS 64
-
-/* Record types that may present the RDOFF header */
-#define RDFREC_GENERIC 0
-#define RDFREC_RELOC 1
-#define RDFREC_IMPORT 2
-#define RDFREC_GLOBAL 3
-#define RDFREC_DLL 4
-#define RDFREC_BSS 5
-#define RDFREC_SEGRELOC 6
-#define RDFREC_FARIMPORT 7
-#define RDFREC_MODNAME 8
-#define RDFREC_COMMON 10
-
-/* Flags for ExportRec/ImportRec */
-#define SYM_DATA 1
-#define SYM_FUNCTION 2
-
-/* Flags for ExportRec */
-#define SYM_GLOBAL 4
-
-/* Flags for ImportRec */
-#define SYM_IMPORT 8
-#define SYM_FAR 16
-
-typedef struct rdf_reloc {
- yasm_reloc reloc;
- enum {
- RDF_RELOC_NORM, /* normal */
- RDF_RELOC_REL, /* relative to current position */
- RDF_RELOC_SEG /* segment containing symbol */
- } type; /* type of relocation */
- unsigned int size;
- unsigned int refseg;
-} rdf_reloc;
-
-typedef struct rdf_section_data {
- /*@dependent@*/ yasm_symrec *sym; /* symbol created for this section */
- long scnum; /* section number (0=first section) */
- enum {
- RDF_SECT_BSS = 0,
- RDF_SECT_CODE = 1,
- RDF_SECT_DATA = 2,
- RDF_SECT_COMMENT = 3,
- RDF_SECT_LCOMMENT = 4,
- RDF_SECT_PCOMMENT = 5,
- RDF_SECT_SYMDEBUG = 6,
- RDF_SECT_LINEDEBUG = 7
- } type; /* section type */
- unsigned int reserved; /* reserved data */
- unsigned long size; /* size of raw data (section data) in bytes */
-
- unsigned char *raw_data; /* raw section data, only used during output */
-} rdf_section_data;
-
-typedef struct rdf_symrec_data {
- unsigned int segment; /* assigned RDF "segment" index */
-} rdf_symrec_data;
-
-typedef STAILQ_HEAD(xdf_str_head, xdf_str) xdf_str_head;
-typedef struct xdf_str {
- STAILQ_ENTRY(xdf_str) link;
- /*@owned@*/ char *str;
-} xdf_str;
-
-typedef struct yasm_objfmt_rdf {
- yasm_objfmt_base objfmt; /* base structure */
-
- long parse_scnum; /* sect numbering in parser */
-
- /*@owned@*/ xdf_str_head module_names;
- /*@owned@*/ xdf_str_head library_names;
-} yasm_objfmt_rdf;
-
-typedef struct rdf_objfmt_output_info {
- yasm_object *object;
- yasm_objfmt_rdf *objfmt_rdf;
- yasm_errwarns *errwarns;
- /*@dependent@*/ FILE *f;
- /*@only@*/ unsigned char *buf;
- yasm_section *sect;
- /*@dependent@*/ rdf_section_data *rsd;
-
- unsigned long indx; /* symbol "segment" (extern/common only) */
-
- unsigned long bss_size; /* total BSS size */
-} rdf_objfmt_output_info;
-
-static void rdf_section_data_destroy(/*@only@*/ void *d);
-static void rdf_section_data_print(void *data, FILE *f, int indent_level);
-
-static const yasm_assoc_data_callback rdf_section_data_cb = {
- rdf_section_data_destroy,
- rdf_section_data_print
-};
-
-static void rdf_symrec_data_destroy(/*@only@*/ void *d);
-static void rdf_symrec_data_print(void *data, FILE *f, int indent_level);
-
-static const yasm_assoc_data_callback rdf_symrec_data_cb = {
- rdf_symrec_data_destroy,
- rdf_symrec_data_print
-};
-
-yasm_objfmt_module yasm_rdf_LTX_objfmt;
-
-
-static /*@dependent@*/ rdf_symrec_data *
-rdf_objfmt_sym_set_data(yasm_symrec *sym, unsigned int segment)
-{
- rdf_symrec_data *rsymd = yasm_xmalloc(sizeof(rdf_symrec_data));
-
- rsymd->segment = segment;
-
- yasm_symrec_add_data(sym, &rdf_symrec_data_cb, rsymd);
- return rsymd;
-}
-
-static yasm_objfmt *
-rdf_objfmt_create(yasm_object *object)
-{
- yasm_objfmt_rdf *objfmt_rdf = yasm_xmalloc(sizeof(yasm_objfmt_rdf));
-
- /* We theoretically support all arches, so don't check.
- * Really we only support byte-addressable ones.
- */
-
- objfmt_rdf->parse_scnum = 0; /* section numbering starts at 0 */
-
- STAILQ_INIT(&objfmt_rdf->module_names);
- STAILQ_INIT(&objfmt_rdf->library_names);
-
- objfmt_rdf->objfmt.module = &yasm_rdf_LTX_objfmt;
-
- return (yasm_objfmt *)objfmt_rdf;
-}
-
-static int
-rdf_objfmt_output_value(yasm_value *value, unsigned char *buf,
- unsigned int destsize, unsigned long offset,
- yasm_bytecode *bc, int warn, /*@null@*/ void *d)
-{
- /*@null@*/ rdf_objfmt_output_info *info = (rdf_objfmt_output_info *)d;
- /*@dependent@*/ /*@null@*/ yasm_intnum *intn;
- unsigned long intn_minus;
- unsigned long intn_plus;
- int retval;
- unsigned int valsize = value->size;
-
- assert(info != NULL);
-
- if (value->abs)
- value->abs = yasm_expr_simplify(value->abs, 1);
-
- /* Try to output constant and PC-relative section-local first.
- * Note this does NOT output any value with a SEG, WRT, external,
- * cross-section, or non-PC-relative reference (those are handled below).
- */
- switch (yasm_value_output_basic(value, buf, destsize, bc, warn,
- info->object->arch)) {
- case -1:
- return 1;
- case 0:
- break;
- default:
- return 0;
- }
-
- if (value->section_rel) {
- yasm_error_set(YASM_ERROR_TOO_COMPLEX,
- N_("rdf: relocation too complex"));
- return 1;
- }
-
- if (value->rel && value->wrt) {
- yasm_error_set(YASM_ERROR_TOO_COMPLEX,
- N_("rdf: WRT not supported"));
- return 1;
- }
-
- intn_minus = 0;
- intn_plus = 0;
- if (value->rel) {
- rdf_reloc *reloc;
- /*@null@*/ rdf_symrec_data *rsymd;
- /*@dependent@*/ yasm_bytecode *precbc;
-
- reloc = yasm_xmalloc(sizeof(rdf_reloc));
- reloc->reloc.addr = yasm_intnum_create_uint(bc->offset + offset);
- reloc->reloc.sym = value->rel;
- reloc->size = valsize/8;
-
- if (value->seg_of)
- reloc->type = RDF_RELOC_SEG;
- else if (value->curpos_rel) {
- reloc->type = RDF_RELOC_REL;
- /* Adjust to start of section, so subtract out the bytecode
- * offset.
- */
- intn_minus = bc->offset;
- } else
- reloc->type = RDF_RELOC_NORM;
-
- if (yasm_symrec_get_label(value->rel, &precbc)) {
- /* local, set the value to be the offset, and the refseg to the
- * segment number.
- */
- /*@dependent@*/ /*@null@*/ rdf_section_data *csectd;
- /*@dependent@*/ yasm_section *sect;
-
- sect = yasm_bc_get_section(precbc);
- csectd = yasm_section_get_data(sect, &rdf_section_data_cb);
- if (!csectd)
- yasm_internal_error(N_("didn't understand section"));
- reloc->refseg = csectd->scnum;
- intn_plus = yasm_bc_next_offset(precbc);
- } else {
- /* must be common/external */
- rsymd = yasm_symrec_get_data(reloc->reloc.sym,
- &rdf_symrec_data_cb);
- if (!rsymd)
- yasm_internal_error(
- N_("rdf: no symbol data for relocated symbol"));
- reloc->refseg = rsymd->segment;
- }
-
- yasm_section_add_reloc(info->sect, (yasm_reloc *)reloc, yasm_xfree);
- }
-
- if (intn_minus > 0) {
- intn = yasm_intnum_create_uint(intn_minus);
- yasm_intnum_calc(intn, YASM_EXPR_NEG, NULL);
- } else
- intn = yasm_intnum_create_uint(intn_plus);
-
- if (value->abs) {
- yasm_intnum *intn2 = yasm_expr_get_intnum(&value->abs, 0);
- if (!intn2) {
- yasm_error_set(YASM_ERROR_TOO_COMPLEX,
- N_("rdf: relocation too complex"));
- yasm_intnum_destroy(intn);
- return 1;
- }
- yasm_intnum_calc(intn, YASM_EXPR_ADD, intn2);
- }
-
- retval = yasm_arch_intnum_tobytes(info->object->arch, intn, buf, destsize,
- valsize, 0, bc, warn);
- yasm_intnum_destroy(intn);
- return retval;
-}
-
-static int
-rdf_objfmt_output_bytecode(yasm_bytecode *bc, /*@null@*/ void *d)
-{
- /*@null@*/ rdf_objfmt_output_info *info = (rdf_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,
- rdf_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) {
- yasm_warn_set(YASM_WARN_UNINIT_CONTENTS,
- N_("uninitialized space: zeroing"));
- /* Write out in chunks */
- memset(&info->rsd->raw_data[info->rsd->size], 0, size);
- } else {
- /* Output buf (or bigbuf if non-NULL) to file */
- memcpy(&info->rsd->raw_data[info->rsd->size],
- bigbuf ? bigbuf : info->buf, (size_t)size);
- }
-
- info->rsd->size += size;
-
- /* If bigbuf was allocated, free it */
- if (bigbuf)
- yasm_xfree(bigbuf);
-
- return 0;
-}
-
-static int
-rdf_objfmt_output_section_mem(yasm_section *sect, /*@null@*/ void *d)
-{
- /*@null@*/ rdf_objfmt_output_info *info = (rdf_objfmt_output_info *)d;
- /*@dependent@*/ /*@null@*/ rdf_section_data *rsd;
- unsigned long size;
-
- assert(info != NULL);
- rsd = yasm_section_get_data(sect, &rdf_section_data_cb);
- assert(rsd != NULL);
-
- size = yasm_bc_next_offset(yasm_section_bcs_last(sect));
-
- if (rsd->type == RDF_SECT_BSS) {
- /* Don't output BSS sections, but remember length
- * TODO: Check for non-reserve bytecodes?
- */
- info->bss_size += size;
- return 0;
- }
-
- /* Empty? Go on to next section */
- if (size == 0)
- return 0;
-
- /* See UGH comment in output() for why we're doing this */
- rsd->raw_data = yasm_xmalloc(size);
- rsd->size = 0;
-
- info->sect = sect;
- info->rsd = rsd;
- yasm_section_bcs_traverse(sect, info->errwarns, info,
- rdf_objfmt_output_bytecode);
-
- /* Sanity check final section size */
- if (rsd->size != size)
- yasm_internal_error(
- N_("rdf: section computed size did not match actual size"));
-
- return 0;
-}
-
-static int
-rdf_objfmt_output_section_reloc(yasm_section *sect, /*@null@*/ void *d)
-{
- /*@null@*/ rdf_objfmt_output_info *info = (rdf_objfmt_output_info *)d;
- /*@dependent@*/ /*@null@*/ rdf_section_data *rsd;
- rdf_reloc *reloc;
-
- assert(info != NULL);
- rsd = yasm_section_get_data(sect, &rdf_section_data_cb);
- assert(rsd != NULL);
-
- if (rsd->type == RDF_SECT_BSS) {
- /* Don't output BSS sections. */
- return 0;
- }
-
- /* Empty? Go on to next section */
- if (rsd->size == 0)
- return 0;
-
- reloc = (rdf_reloc *)yasm_section_relocs_first(sect);
- while (reloc) {
- unsigned char *localbuf = info->buf;
-
- if (reloc->type == RDF_RELOC_SEG)
- YASM_WRITE_8(localbuf, RDFREC_SEGRELOC);
- else
- YASM_WRITE_8(localbuf, RDFREC_RELOC);
- YASM_WRITE_8(localbuf, 8); /* record length */
- /* Section number, +0x40 if relative reloc */
- YASM_WRITE_8(localbuf, rsd->scnum +
- (reloc->type == RDF_RELOC_REL ? 0x40 : 0));
- yasm_intnum_get_sized(reloc->reloc.addr, localbuf, 4, 32, 0, 0, 0);
- localbuf += 4; /* offset of relocation */
- YASM_WRITE_8(localbuf, reloc->size); /* size of relocation */
- YASM_WRITE_16_L(localbuf, reloc->refseg); /* relocated symbol */
- fwrite(info->buf, 10, 1, info->f);
-
- reloc = (rdf_reloc *)yasm_section_reloc_next((yasm_reloc *)reloc);
- }
-
- return 0;
-}
-
-static int
-rdf_objfmt_output_section_file(yasm_section *sect, /*@null@*/ void *d)
-{
- /*@null@*/ rdf_objfmt_output_info *info = (rdf_objfmt_output_info *)d;
- /*@dependent@*/ /*@null@*/ rdf_section_data *rsd;
- unsigned char *localbuf;
-
- assert(info != NULL);
- rsd = yasm_section_get_data(sect, &rdf_section_data_cb);
- assert(rsd != NULL);
-
- if (rsd->type == RDF_SECT_BSS) {
- /* Don't output BSS sections. */
- return 0;
- }
-
- /* Empty? Go on to next section */
- if (rsd->size == 0)
- return 0;
-
- /* Section header */
- localbuf = info->buf;
- YASM_WRITE_16_L(localbuf, rsd->type); /* type */
- YASM_WRITE_16_L(localbuf, rsd->scnum); /* number */
- YASM_WRITE_16_L(localbuf, rsd->reserved); /* reserved */
- YASM_WRITE_32_L(localbuf, rsd->size); /* length */
- fwrite(info->buf, 10, 1, info->f);
-
- /* Section data */
- fwrite(rsd->raw_data, rsd->size, 1, info->f);
-
- /* Free section data */
- yasm_xfree(rsd->raw_data);
- rsd->raw_data = NULL;
-
- return 0;
-}
-
-#define FLAG_EXT 0x1000
-#define FLAG_GLOB 0x2000
-#define FLAG_SET 0x4000
-#define FLAG_CLR 0x8000
-#define FLAG_MASK 0x0fff
-
-static int
-rdf_helper_flag(void *obj, yasm_valparam *vp, unsigned long line, void *d,
- uintptr_t flag)
-{
- yasm_symrec *sym = (yasm_symrec *)obj;
- yasm_sym_vis vis = yasm_symrec_get_visibility(sym);
- unsigned int *flags = (unsigned int *)d;
-
- if (((vis & YASM_SYM_GLOBAL) && (flag & FLAG_GLOB)) ||
- ((vis & YASM_SYM_EXTERN) && (flag & FLAG_EXT))) {
- if (flag & FLAG_SET)
- *flags |= flag & FLAG_MASK;
- else if (flag & FLAG_CLR)
- *flags &= ~(flag & FLAG_MASK);
- }
- return 0;
-}
-
-static unsigned int
-rdf_parse_flags(yasm_symrec *sym)
-{
- /*@dependent@*/ /*@null@*/ yasm_valparamhead *objext_valparams =
- yasm_symrec_get_objext_valparams(sym);
- unsigned int flags = 0;
-
- static const yasm_dir_help help[] = {
- { "data", 0, rdf_helper_flag, 0,
- FLAG_EXT|FLAG_GLOB|FLAG_SET|SYM_DATA },
- { "object", 0, rdf_helper_flag, 0,
- FLAG_EXT|FLAG_GLOB|FLAG_SET|SYM_DATA },
- { "proc", 0, rdf_helper_flag, 0,
- FLAG_EXT|FLAG_GLOB|FLAG_SET|SYM_FUNCTION },
- { "function", 0, rdf_helper_flag, 0,
- FLAG_EXT|FLAG_GLOB|FLAG_SET|SYM_FUNCTION },
- { "import", 0, rdf_helper_flag, 0, FLAG_EXT|FLAG_SET|SYM_IMPORT },
- { "export", 0, rdf_helper_flag, 0, FLAG_GLOB|FLAG_SET|SYM_GLOBAL },
- { "far", 0, rdf_helper_flag, 0, FLAG_EXT|FLAG_SET|SYM_FAR },
- { "near", 0, rdf_helper_flag, 0, FLAG_EXT|FLAG_CLR|SYM_FAR }
- };
-
- if (!objext_valparams)
- return 0;
-
- yasm_dir_helper(sym, yasm_vps_first(objext_valparams), 0, help,
- NELEMS(help), &flags, yasm_dir_helper_valparam_warn);
-
- return flags;
-}
-
-static int
-rdf_objfmt_output_sym(yasm_symrec *sym, /*@null@*/ void *d)
-{
- /*@null@*/ rdf_objfmt_output_info *info = (rdf_objfmt_output_info *)d;
- yasm_sym_vis vis = yasm_symrec_get_visibility(sym);
- /*@only@*/ char *name;
- size_t len;
- unsigned long value = 0;
- unsigned int scnum = 0;
- /*@dependent@*/ /*@null@*/ yasm_section *sect;
- /*@dependent@*/ /*@null@*/ yasm_bytecode *precbc;
- unsigned char *localbuf;
-
- assert(info != NULL);
-
- if (vis == YASM_SYM_LOCAL || vis == YASM_SYM_DLOCAL)
- return 0; /* skip local syms */
-
- /* Look at symrec for value/scnum/etc. */
- if (yasm_symrec_get_label(sym, &precbc)) {
- /*@dependent@*/ /*@null@*/ rdf_section_data *csectd;
-
- if (precbc)
- sect = yasm_bc_get_section(precbc);
- else
- sect = NULL;
- if (!sect)
- return 0;
-
- /* it's a label: get value and offset. */
- csectd = yasm_section_get_data(sect, &rdf_section_data_cb);
- if (csectd)
- scnum = csectd->scnum;
- else
- yasm_internal_error(N_("didn't understand section"));
- value = yasm_bc_next_offset(precbc);
- } else if (yasm_symrec_get_equ(sym)) {
- yasm_warn_set(YASM_WARN_GENERAL,
- N_("rdf does not support exporting EQU/absolute values"));
- yasm_errwarn_propagate(info->errwarns, yasm_symrec_get_decl_line(sym));
- return 0;
- }
-
- name = yasm_symrec_get_global_name(sym, info->object);
- len = strlen(name);
-
- if (len > EXIM_LABEL_MAX-1) {
- yasm_warn_set(YASM_WARN_GENERAL,
- N_("label name too long, truncating to %d bytes"),
- EXIM_LABEL_MAX);
- len = EXIM_LABEL_MAX-1;
- }
-
- localbuf = info->buf;
- if (vis & YASM_SYM_GLOBAL) {
- YASM_WRITE_8(localbuf, RDFREC_GLOBAL);
- YASM_WRITE_8(localbuf, 6+len+1); /* record length */
- YASM_WRITE_8(localbuf, rdf_parse_flags(sym)); /* flags */
- YASM_WRITE_8(localbuf, scnum); /* segment referred to */
- YASM_WRITE_32_L(localbuf, value); /* offset */
- } else {
- /* Save symbol segment in symrec data (for later reloc gen) */
- scnum = info->indx++;
- rdf_objfmt_sym_set_data(sym, scnum);
-
- if (vis & YASM_SYM_COMMON) {
- /*@dependent@*/ /*@null@*/ yasm_expr **csize_expr;
- const yasm_intnum *intn;
- /*@dependent@*/ /*@null@*/ yasm_valparamhead *objext_valparams =
- yasm_symrec_get_objext_valparams(sym);
- unsigned long addralign = 0;
-
- YASM_WRITE_8(localbuf, RDFREC_COMMON);
- YASM_WRITE_8(localbuf, 8+len+1); /* record length */
- YASM_WRITE_16_L(localbuf, scnum); /* segment allocated */
-
- /* size */
- csize_expr = yasm_symrec_get_common_size(sym);
- assert(csize_expr != NULL);
- intn = yasm_expr_get_intnum(csize_expr, 1);
- if (!intn) {
- yasm_error_set(YASM_ERROR_NOT_CONSTANT,
- N_("COMMON data size not an integer expression"));
- } else
- value = yasm_intnum_get_uint(intn);
- YASM_WRITE_32_L(localbuf, value);
-
- /* alignment */
- if (objext_valparams) {
- yasm_valparam *vp = yasm_vps_first(objext_valparams);
- for (; vp; vp = yasm_vps_next(vp)) {
- if (!vp->val) {
- /*@only@*/ /*@null@*/ yasm_expr *align_expr;
- /*@dependent@*/ /*@null@*/
- const yasm_intnum *align_intn;
-
- if (!(align_expr = yasm_vp_expr(vp,
- info->object->symtab,
- yasm_symrec_get_decl_line(sym))) ||
- !(align_intn = yasm_expr_get_intnum(&align_expr,
- 0))) {
- yasm_error_set(YASM_ERROR_VALUE,
- N_("argument to `%s' is not an integer"),
- vp->val);
- if (align_expr)
- yasm_expr_destroy(align_expr);
- continue;
- }
- addralign = yasm_intnum_get_uint(align_intn);
- yasm_expr_destroy(align_expr);
-
- /* Alignments must be a power of two. */
- if (!is_exp2(addralign)) {
- yasm_error_set(YASM_ERROR_VALUE,
- N_("alignment constraint is not a power of two"));
- continue;
- }
- } else
- yasm_warn_set(YASM_WARN_GENERAL,
- N_("Unrecognized qualifier `%s'"), vp->val);
- }
- }
- YASM_WRITE_16_L(localbuf, addralign);
- } else if (vis & YASM_SYM_EXTERN) {
- unsigned int flags = rdf_parse_flags(sym);
- if (flags & SYM_FAR) {
- YASM_WRITE_8(localbuf, RDFREC_FARIMPORT);
- flags &= ~SYM_FAR;
- } else
- YASM_WRITE_8(localbuf, RDFREC_IMPORT);
- YASM_WRITE_8(localbuf, 3+len+1); /* record length */
- YASM_WRITE_8(localbuf, flags); /* flags */
- YASM_WRITE_16_L(localbuf, scnum); /* segment allocated */
- }
- }
-
- /* Symbol name */
- memcpy(localbuf, name, len);
- localbuf += len;
- YASM_WRITE_8(localbuf, 0); /* 0-terminated name */
- yasm_xfree(name);
-
- fwrite(info->buf, (unsigned long)(localbuf-info->buf), 1, info->f);
-
- yasm_errwarn_propagate(info->errwarns, yasm_symrec_get_decl_line(sym));
- return 0;
-}
-
-static void
-rdf_objfmt_output(yasm_object *object, FILE *f, int all_syms,
- yasm_errwarns *errwarns)
-{
- yasm_objfmt_rdf *objfmt_rdf = (yasm_objfmt_rdf *)object->objfmt;
- rdf_objfmt_output_info info;
- unsigned char *localbuf;
- long headerlen, filelen;
- xdf_str *cur;
- size_t len;
-
- info.object = object;
- info.objfmt_rdf = objfmt_rdf;
- info.errwarns = errwarns;
- info.f = f;
- info.buf = yasm_xmalloc(REGULAR_OUTBUF_SIZE);
- info.bss_size = 0;
-
- /* Allocate space for file header by seeking forward */
- if (fseek(f, (long)strlen(RDF_MAGIC)+8, SEEK_SET) < 0) {
- yasm__fatal(N_("could not seek on output file"));
- /*@notreached@*/
- return;
- }
-
- /* Output custom header records (library and module, etc) */
- cur = STAILQ_FIRST(&objfmt_rdf->module_names);
- while (cur) {
- len = strlen(cur->str)+1;
- localbuf = info.buf;
- YASM_WRITE_8(localbuf, RDFREC_MODNAME); /* record type */
- YASM_WRITE_8(localbuf, len); /* record length */
- fwrite(info.buf, 2, 1, f);
- fwrite(cur->str, len, 1, f);
- cur = STAILQ_NEXT(cur, link);
- }
-
- cur = STAILQ_FIRST(&objfmt_rdf->library_names);
- while (cur) {
- len = strlen(cur->str)+1;
- localbuf = info.buf;
- YASM_WRITE_8(localbuf, RDFREC_DLL); /* record type */
- YASM_WRITE_8(localbuf, len); /* record length */
- fwrite(info.buf, 2, 1, f);
- fwrite(cur->str, len, 1, f);
- cur = STAILQ_NEXT(cur, link);
- }
-
- /* Output symbol table */
- info.indx = objfmt_rdf->parse_scnum;
- yasm_symtab_traverse(object->symtab, &info, rdf_objfmt_output_sym);
-
- /* UGH! Due to the fact the relocs go at the beginning of the file, and
- * we only know if we have relocs when we output the sections, we have
- * to output the section data before we have output the relocs. But
- * we also don't know how much space to preallocate for relocs, so....
- * we output into memory buffers first (thus the UGH).
- *
- * Stupid object format design, if you ask me (basically all other
- * object formats put the relocs *after* the section data to avoid this
- * exact problem).
- *
- * We also calculate the total size of all BSS sections here.
- */
- if (yasm_object_sections_traverse(object, &info,
- rdf_objfmt_output_section_mem))
- return;
-
- /* Output all relocs */
- if (yasm_object_sections_traverse(object, &info,
- rdf_objfmt_output_section_reloc))
- return;
-
- /* Output BSS record */
- if (info.bss_size > 0) {
- localbuf = info.buf;
- YASM_WRITE_8(localbuf, RDFREC_BSS); /* record type */
- YASM_WRITE_8(localbuf, 4); /* record length */
- YASM_WRITE_32_L(localbuf, info.bss_size); /* total BSS size */
- fwrite(info.buf, 6, 1, f);
- }
-
- /* Determine header length */
- headerlen = ftell(f);
- if (headerlen == -1) {
- yasm__fatal(N_("could not get file position on output file"));
- /*@notreached@*/
- return;
- }
-
- /* Section data (to file) */
- if (yasm_object_sections_traverse(object, &info,
- rdf_objfmt_output_section_file))
- return;
-
- /* NULL section to end file */
- memset(info.buf, 0, 10);
- fwrite(info.buf, 10, 1, f);
-
- /* Determine object length */
- filelen = ftell(f);
- if (filelen == -1) {
- yasm__fatal(N_("could not get file position on output file"));
- /*@notreached@*/
- return;
- }
-
- /* Write file header */
- if (fseek(f, 0, SEEK_SET) < 0) {
- yasm__fatal(N_("could not seek on output file"));
- /*@notreached@*/
- return;
- }
-
- fwrite(RDF_MAGIC, strlen(RDF_MAGIC), 1, f);
- localbuf = info.buf;
- YASM_WRITE_32_L(localbuf, filelen-10); /* object size */
- YASM_WRITE_32_L(localbuf, headerlen-14); /* header size */
- fwrite(info.buf, 8, 1, f);
-
- yasm_xfree(info.buf);
-}
-
-static void
-rdf_objfmt_destroy(yasm_objfmt *objfmt)
-{
- yasm_objfmt_rdf *objfmt_rdf = (yasm_objfmt_rdf *)objfmt;
- xdf_str *cur, *next;
-
- cur = STAILQ_FIRST(&objfmt_rdf->module_names);
- while (cur) {
- next = STAILQ_NEXT(cur, link);
- yasm_xfree(cur->str);
- yasm_xfree(cur);
- cur = next;
- }
-
- cur = STAILQ_FIRST(&objfmt_rdf->library_names);
- while (cur) {
- next = STAILQ_NEXT(cur, link);
- yasm_xfree(cur->str);
- yasm_xfree(cur);
- cur = next;
- }
-
- yasm_xfree(objfmt);
-}
-
-static void
-rdf_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_rdf *objfmt_rdf = (yasm_objfmt_rdf *)object->objfmt;
- rdf_section_data *data;
- yasm_symrec *sym;
-
- data = yasm_xmalloc(sizeof(rdf_section_data));
- data->scnum = objfmt_rdf->parse_scnum++;
- data->type = 0;
- data->reserved = 0;
- data->size = 0;
- data->raw_data = NULL;
- yasm_section_add_data(sect, &rdf_section_data_cb, data);
-
- sym = yasm_symtab_define_label(object->symtab, sectname,
- yasm_section_bcs_first(sect), 1, line);
- data->sym = sym;
-}
-
-static yasm_section *
-rdf_objfmt_add_default_section(yasm_object *object)
-{
- yasm_section *retval;
- rdf_section_data *rsd;
- int isnew;
-
- retval = yasm_object_get_general(object, ".text", 0, 1, 0, &isnew, 0);
- if (isnew) {
- rsd = yasm_section_get_data(retval, &rdf_section_data_cb);
- rsd->type = RDF_SECT_CODE;
- rsd->reserved = 0;
- yasm_section_set_default(retval, 1);
- }
- return retval;
-}
-
-static int
-rdf_helper_set_type(void *obj, yasm_valparam *vp, unsigned long line,
- void *d, uintptr_t newtype)
-{
- unsigned int *type = (unsigned int *)d;
- *type = newtype;
- return 0;
-}
-
-struct rdf_section_switch_data {
- /*@only@*/ /*@null@*/ yasm_intnum *reserved_intn;
- unsigned int type;
-};
-
-static int
-rdf_helper_set_reserved(void *obj, yasm_valparam *vp, unsigned long line,
- void *d)
-{
- struct rdf_section_switch_data *data = (struct rdf_section_switch_data *)d;
-
- if (!vp->val && vp->type == YASM_PARAM_EXPR)
- return yasm_dir_helper_intn(obj, vp, line, &data->reserved_intn, 0);
- else
- return yasm_dir_helper_valparam_warn(obj, vp, line, d);
-}
-
-static /*@observer@*/ /*@null@*/ yasm_section *
-rdf_objfmt_section_switch(yasm_object *object, yasm_valparamhead *valparams,
- /*@unused@*/ /*@null@*/
- yasm_valparamhead *objext_valparams,
- unsigned long line)
-{
- yasm_valparam *vp = yasm_vps_first(valparams);
- yasm_section *retval;
- int isnew;
- unsigned int reserved = 0;
- int flags_override = 0;
- const char *sectname;
- rdf_section_data *rsd;
-
- struct rdf_section_switch_data data;
-
- static const yasm_dir_help help[] = {
- { "bss", 0, rdf_helper_set_type,
- offsetof(struct rdf_section_switch_data, type), RDF_SECT_BSS },
- { "code", 0, rdf_helper_set_type,
- offsetof(struct rdf_section_switch_data, type), RDF_SECT_CODE },
- { "text", 0, rdf_helper_set_type,
- offsetof(struct rdf_section_switch_data, type), RDF_SECT_CODE },
- { "data", 0, rdf_helper_set_type,
- offsetof(struct rdf_section_switch_data, type), RDF_SECT_DATA },
- { "comment", 0, rdf_helper_set_type,
- offsetof(struct rdf_section_switch_data, type), RDF_SECT_COMMENT },
- { "lcomment", 0, rdf_helper_set_type,
- offsetof(struct rdf_section_switch_data, type), RDF_SECT_LCOMMENT },
- { "pcomment", 0, rdf_helper_set_type,
- offsetof(struct rdf_section_switch_data, type), RDF_SECT_PCOMMENT },
- { "symdebug", 0, rdf_helper_set_type,
- offsetof(struct rdf_section_switch_data, type), RDF_SECT_SYMDEBUG },
- { "linedebug", 0, rdf_helper_set_type,
- offsetof(struct rdf_section_switch_data, type), RDF_SECT_LINEDEBUG },
- { "reserved", 1, yasm_dir_helper_intn,
- offsetof(struct rdf_section_switch_data, reserved_intn), 0 }
- };
-
- data.reserved_intn = NULL;
- data.type = 0xffff;
-
- vp = yasm_vps_first(valparams);
- sectname = yasm_vp_string(vp);
- if (!sectname)
- return NULL;
- vp = yasm_vps_next(vp);
-
- if (strcmp(sectname, ".text") == 0)
- data.type = RDF_SECT_CODE;
- else if (strcmp(sectname, ".data") == 0)
- data.type = RDF_SECT_DATA;
- else if (strcmp(sectname, ".bss") == 0)
- data.type = RDF_SECT_BSS;
-
- flags_override = yasm_dir_helper(object, vp, line, help, NELEMS(help),
- &data, rdf_helper_set_reserved);
- if (flags_override < 0)
- return NULL; /* error occurred */
-
- if (data.type == 0xffff) {
- yasm_error_set(YASM_ERROR_VALUE,
- N_("new segment declared without type code"));
- data.type = RDF_SECT_DATA;
- }
-
- if (data.reserved_intn) {
- reserved = yasm_intnum_get_uint(data.reserved_intn);
- yasm_intnum_destroy(data.reserved_intn);
- }
-
- retval = yasm_object_get_general(object, sectname, 0, 1,
- data.type == RDF_SECT_BSS, &isnew, line);
-
- rsd = yasm_section_get_data(retval, &rdf_section_data_cb);
-
- if (isnew || yasm_section_is_default(retval)) {
- yasm_section_set_default(retval, 0);
- rsd->type = data.type;
- rsd->reserved = reserved;
- } else if (flags_override)
- yasm_warn_set(YASM_WARN_GENERAL,
- N_("section flags ignored on section redeclaration"));
- return retval;
-}
-
-static /*@observer@*/ /*@null@*/ yasm_symrec *
-rdf_objfmt_get_special_sym(yasm_object *object, const char *name,
- const char *parser)
-{
- return NULL;
-}
-
-static void
-rdf_section_data_destroy(void *data)
-{
- rdf_section_data *rsd = (rdf_section_data *)data;
- if (rsd->raw_data)
- yasm_xfree(rsd->raw_data);
- yasm_xfree(data);
-}
-
-static void
-rdf_section_data_print(void *data, FILE *f, int indent_level)
-{
- rdf_section_data *rsd = (rdf_section_data *)data;
-
- fprintf(f, "%*ssym=\n", indent_level, "");
- yasm_symrec_print(rsd->sym, f, indent_level+1);
- fprintf(f, "%*sscnum=%ld\n", indent_level, "", rsd->scnum);
- fprintf(f, "%*stype=0x%x\n", indent_level, "", rsd->type);
- fprintf(f, "%*sreserved=0x%x\n", indent_level, "", rsd->reserved);
- fprintf(f, "%*ssize=%ld\n", indent_level, "", rsd->size);
-}
-
-static void
-rdf_symrec_data_destroy(void *data)
-{
- yasm_xfree(data);
-}
-
-static void
-rdf_symrec_data_print(void *data, FILE *f, int indent_level)
-{
- rdf_symrec_data *rsymd = (rdf_symrec_data *)data;
-
- fprintf(f, "%*ssymtab segment=%u\n", indent_level, "", rsymd->segment);
-}
-
-static void
-rdf_objfmt_add_libmodule(yasm_object *object, char *name, int lib)
-{
- yasm_objfmt_rdf *objfmt_rdf = (yasm_objfmt_rdf *)object->objfmt;
- xdf_str *str;
-
- /* Add to list */
- str = yasm_xmalloc(sizeof(xdf_str));
- str->str = name;
- if (lib)
- STAILQ_INSERT_TAIL(&objfmt_rdf->library_names, str, link);
- else
- STAILQ_INSERT_TAIL(&objfmt_rdf->module_names, str, link);
-
- if (strlen(str->str) > MODLIB_NAME_MAX-1) {
- yasm_warn_set(YASM_WARN_GENERAL,
- N_("name too long, truncating to %d bytes"),
- MODLIB_NAME_MAX);
- str->str[MODLIB_NAME_MAX-1] = '\0';
- }
-}
-
-static void
-dir_library(yasm_object *object, yasm_valparamhead *valparams,
- yasm_valparamhead *objext_valparams, unsigned long line)
-{
- yasm_valparam *vp = yasm_vps_first(valparams);
- rdf_objfmt_add_libmodule(object, yasm__xstrdup(yasm_vp_string(vp)), 1);
-}
-
-static void
-dir_module(yasm_object *object, yasm_valparamhead *valparams,
- yasm_valparamhead *objext_valparams, unsigned long line)
-{
- yasm_valparam *vp = yasm_vps_first(valparams);
- rdf_objfmt_add_libmodule(object, yasm__xstrdup(yasm_vp_string(vp)), 0);
-}
-
-/* Define valid debug formats to use with this object format */
-static const char *rdf_objfmt_dbgfmt_keywords[] = {
- "null",
- NULL
-};
-
-static const yasm_directive rdf_objfmt_directives[] = {
- { "library", "nasm", dir_library, YASM_DIR_ARG_REQUIRED },
- { "module", "nasm", dir_module, YASM_DIR_ARG_REQUIRED },
- { NULL, NULL, NULL, 0 }
-};
-
-static const char *rdf_nasm_stdmac[] = {
- "%imacro library 1+.nolist",
- "[library %1]",
- "%endmacro",
- "%imacro module 1+.nolist",
- "[module %1]",
- "%endmacro",
- NULL
-};
-
-static const yasm_stdmac rdf_objfmt_stdmacs[] = {
- { "nasm", "nasm", rdf_nasm_stdmac },
- { NULL, NULL, NULL }
-};
-
-/* Define objfmt structure -- see objfmt.h for details */
-yasm_objfmt_module yasm_rdf_LTX_objfmt = {
- "Relocatable Dynamic Object File Format (RDOFF) v2.0",
- "rdf",
- "rdf",
- 32,
- 0,
- rdf_objfmt_dbgfmt_keywords,
- "null",
- rdf_objfmt_directives,
- rdf_objfmt_stdmacs,
- rdf_objfmt_create,
- rdf_objfmt_output,
- rdf_objfmt_destroy,
- rdf_objfmt_add_default_section,
- rdf_objfmt_init_new_section,
- rdf_objfmt_section_switch,
- rdf_objfmt_get_special_sym
-};
+/*
+ * Relocatable Dynamic Object File Format (RDOFF) version 2 format
+ *
+ * Copyright (C) 2006-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>
+
+#include <libyasm.h>
+
+
+#define REGULAR_OUTBUF_SIZE 1024
+
+#define RDF_MAGIC "RDOFF2"
+
+/* Maximum size of an import/export label (including trailing zero) */
+#define EXIM_LABEL_MAX 64
+
+/* Maximum size of library or module name (including trailing zero) */
+#define MODLIB_NAME_MAX 128
+
+/* Maximum number of segments that we can handle in one file */
+#define RDF_MAXSEGS 64
+
+/* Record types that may present the RDOFF header */
+#define RDFREC_GENERIC 0
+#define RDFREC_RELOC 1
+#define RDFREC_IMPORT 2
+#define RDFREC_GLOBAL 3
+#define RDFREC_DLL 4
+#define RDFREC_BSS 5
+#define RDFREC_SEGRELOC 6
+#define RDFREC_FARIMPORT 7
+#define RDFREC_MODNAME 8
+#define RDFREC_COMMON 10
+
+/* Flags for ExportRec/ImportRec */
+#define SYM_DATA 1
+#define SYM_FUNCTION 2
+
+/* Flags for ExportRec */
+#define SYM_GLOBAL 4
+
+/* Flags for ImportRec */
+#define SYM_IMPORT 8
+#define SYM_FAR 16
+
+typedef struct rdf_reloc {
+ yasm_reloc reloc;
+ enum {
+ RDF_RELOC_NORM, /* normal */
+ RDF_RELOC_REL, /* relative to current position */
+ RDF_RELOC_SEG /* segment containing symbol */
+ } type; /* type of relocation */
+ unsigned int size;
+ unsigned int refseg;
+} rdf_reloc;
+
+typedef struct rdf_section_data {
+ /*@dependent@*/ yasm_symrec *sym; /* symbol created for this section */
+ long scnum; /* section number (0=first section) */
+ enum {
+ RDF_SECT_BSS = 0,
+ RDF_SECT_CODE = 1,
+ RDF_SECT_DATA = 2,
+ RDF_SECT_COMMENT = 3,
+ RDF_SECT_LCOMMENT = 4,
+ RDF_SECT_PCOMMENT = 5,
+ RDF_SECT_SYMDEBUG = 6,
+ RDF_SECT_LINEDEBUG = 7
+ } type; /* section type */
+ unsigned int reserved; /* reserved data */
+ unsigned long size; /* size of raw data (section data) in bytes */
+
+ unsigned char *raw_data; /* raw section data, only used during output */
+} rdf_section_data;
+
+typedef struct rdf_symrec_data {
+ unsigned int segment; /* assigned RDF "segment" index */
+} rdf_symrec_data;
+
+typedef STAILQ_HEAD(xdf_str_head, xdf_str) xdf_str_head;
+typedef struct xdf_str {
+ STAILQ_ENTRY(xdf_str) link;
+ /*@owned@*/ char *str;
+} xdf_str;
+
+typedef struct yasm_objfmt_rdf {
+ yasm_objfmt_base objfmt; /* base structure */
+
+ long parse_scnum; /* sect numbering in parser */
+
+ /*@owned@*/ xdf_str_head module_names;
+ /*@owned@*/ xdf_str_head library_names;
+} yasm_objfmt_rdf;
+
+typedef struct rdf_objfmt_output_info {
+ yasm_object *object;
+ yasm_objfmt_rdf *objfmt_rdf;
+ yasm_errwarns *errwarns;
+ /*@dependent@*/ FILE *f;
+ /*@only@*/ unsigned char *buf;
+ yasm_section *sect;
+ /*@dependent@*/ rdf_section_data *rsd;
+
+ unsigned long indx; /* symbol "segment" (extern/common only) */
+
+ unsigned long bss_size; /* total BSS size */
+} rdf_objfmt_output_info;
+
+static void rdf_section_data_destroy(/*@only@*/ void *d);
+static void rdf_section_data_print(void *data, FILE *f, int indent_level);
+
+static const yasm_assoc_data_callback rdf_section_data_cb = {
+ rdf_section_data_destroy,
+ rdf_section_data_print
+};
+
+static void rdf_symrec_data_destroy(/*@only@*/ void *d);
+static void rdf_symrec_data_print(void *data, FILE *f, int indent_level);
+
+static const yasm_assoc_data_callback rdf_symrec_data_cb = {
+ rdf_symrec_data_destroy,
+ rdf_symrec_data_print
+};
+
+yasm_objfmt_module yasm_rdf_LTX_objfmt;
+
+
+static /*@dependent@*/ rdf_symrec_data *
+rdf_objfmt_sym_set_data(yasm_symrec *sym, unsigned int segment)
+{
+ rdf_symrec_data *rsymd = yasm_xmalloc(sizeof(rdf_symrec_data));
+
+ rsymd->segment = segment;
+
+ yasm_symrec_add_data(sym, &rdf_symrec_data_cb, rsymd);
+ return rsymd;
+}
+
+static yasm_objfmt *
+rdf_objfmt_create(yasm_object *object)
+{
+ yasm_objfmt_rdf *objfmt_rdf = yasm_xmalloc(sizeof(yasm_objfmt_rdf));
+
+ /* We theoretically support all arches, so don't check.
+ * Really we only support byte-addressable ones.
+ */
+
+ objfmt_rdf->parse_scnum = 0; /* section numbering starts at 0 */
+
+ STAILQ_INIT(&objfmt_rdf->module_names);
+ STAILQ_INIT(&objfmt_rdf->library_names);
+
+ objfmt_rdf->objfmt.module = &yasm_rdf_LTX_objfmt;
+
+ return (yasm_objfmt *)objfmt_rdf;
+}
+
+static int
+rdf_objfmt_output_value(yasm_value *value, unsigned char *buf,
+ unsigned int destsize, unsigned long offset,
+ yasm_bytecode *bc, int warn, /*@null@*/ void *d)
+{
+ /*@null@*/ rdf_objfmt_output_info *info = (rdf_objfmt_output_info *)d;
+ /*@dependent@*/ /*@null@*/ yasm_intnum *intn;
+ unsigned long intn_minus;
+ unsigned long intn_plus;
+ int retval;
+ unsigned int valsize = value->size;
+
+ assert(info != NULL);
+
+ if (value->abs)
+ value->abs = yasm_expr_simplify(value->abs, 1);
+
+ /* Try to output constant and PC-relative section-local first.
+ * Note this does NOT output any value with a SEG, WRT, external,
+ * cross-section, or non-PC-relative reference (those are handled below).
+ */
+ switch (yasm_value_output_basic(value, buf, destsize, bc, warn,
+ info->object->arch)) {
+ case -1:
+ return 1;
+ case 0:
+ break;
+ default:
+ return 0;
+ }
+
+ if (value->section_rel) {
+ yasm_error_set(YASM_ERROR_TOO_COMPLEX,
+ N_("rdf: relocation too complex"));
+ return 1;
+ }
+
+ if (value->rel && value->wrt) {
+ yasm_error_set(YASM_ERROR_TOO_COMPLEX,
+ N_("rdf: WRT not supported"));
+ return 1;
+ }
+
+ intn_minus = 0;
+ intn_plus = 0;
+ if (value->rel) {
+ rdf_reloc *reloc;
+ /*@null@*/ rdf_symrec_data *rsymd;
+ /*@dependent@*/ yasm_bytecode *precbc;
+
+ reloc = yasm_xmalloc(sizeof(rdf_reloc));
+ reloc->reloc.addr = yasm_intnum_create_uint(bc->offset + offset);
+ reloc->reloc.sym = value->rel;
+ reloc->size = valsize/8;
+
+ if (value->seg_of)
+ reloc->type = RDF_RELOC_SEG;
+ else if (value->curpos_rel) {
+ reloc->type = RDF_RELOC_REL;
+ /* Adjust to start of section, so subtract out the bytecode
+ * offset.
+ */
+ intn_minus = bc->offset;
+ } else
+ reloc->type = RDF_RELOC_NORM;
+
+ if (yasm_symrec_get_label(value->rel, &precbc)) {
+ /* local, set the value to be the offset, and the refseg to the
+ * segment number.
+ */
+ /*@dependent@*/ /*@null@*/ rdf_section_data *csectd;
+ /*@dependent@*/ yasm_section *sect;
+
+ sect = yasm_bc_get_section(precbc);
+ csectd = yasm_section_get_data(sect, &rdf_section_data_cb);
+ if (!csectd)
+ yasm_internal_error(N_("didn't understand section"));
+ reloc->refseg = csectd->scnum;
+ intn_plus = yasm_bc_next_offset(precbc);
+ } else {
+ /* must be common/external */
+ rsymd = yasm_symrec_get_data(reloc->reloc.sym,
+ &rdf_symrec_data_cb);
+ if (!rsymd)
+ yasm_internal_error(
+ N_("rdf: no symbol data for relocated symbol"));
+ reloc->refseg = rsymd->segment;
+ }
+
+ yasm_section_add_reloc(info->sect, (yasm_reloc *)reloc, yasm_xfree);
+ }
+
+ if (intn_minus > 0) {
+ intn = yasm_intnum_create_uint(intn_minus);
+ yasm_intnum_calc(intn, YASM_EXPR_NEG, NULL);
+ } else
+ intn = yasm_intnum_create_uint(intn_plus);
+
+ if (value->abs) {
+ yasm_intnum *intn2 = yasm_expr_get_intnum(&value->abs, 0);
+ if (!intn2) {
+ yasm_error_set(YASM_ERROR_TOO_COMPLEX,
+ N_("rdf: relocation too complex"));
+ yasm_intnum_destroy(intn);
+ return 1;
+ }
+ yasm_intnum_calc(intn, YASM_EXPR_ADD, intn2);
+ }
+
+ retval = yasm_arch_intnum_tobytes(info->object->arch, intn, buf, destsize,
+ valsize, 0, bc, warn);
+ yasm_intnum_destroy(intn);
+ return retval;
+}
+
+static int
+rdf_objfmt_output_bytecode(yasm_bytecode *bc, /*@null@*/ void *d)
+{
+ /*@null@*/ rdf_objfmt_output_info *info = (rdf_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,
+ rdf_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) {
+ yasm_warn_set(YASM_WARN_UNINIT_CONTENTS,
+ N_("uninitialized space: zeroing"));
+ /* Write out in chunks */
+ memset(&info->rsd->raw_data[info->rsd->size], 0, size);
+ } else {
+ /* Output buf (or bigbuf if non-NULL) to file */
+ memcpy(&info->rsd->raw_data[info->rsd->size],
+ bigbuf ? bigbuf : info->buf, (size_t)size);
+ }
+
+ info->rsd->size += size;
+
+ /* If bigbuf was allocated, free it */
+ if (bigbuf)
+ yasm_xfree(bigbuf);
+
+ return 0;
+}
+
+static int
+rdf_objfmt_output_section_mem(yasm_section *sect, /*@null@*/ void *d)
+{
+ /*@null@*/ rdf_objfmt_output_info *info = (rdf_objfmt_output_info *)d;
+ /*@dependent@*/ /*@null@*/ rdf_section_data *rsd;
+ unsigned long size;
+
+ assert(info != NULL);
+ rsd = yasm_section_get_data(sect, &rdf_section_data_cb);
+ assert(rsd != NULL);
+
+ size = yasm_bc_next_offset(yasm_section_bcs_last(sect));
+
+ if (rsd->type == RDF_SECT_BSS) {
+ /* Don't output BSS sections, but remember length
+ * TODO: Check for non-reserve bytecodes?
+ */
+ info->bss_size += size;
+ return 0;
+ }
+
+ /* Empty? Go on to next section */
+ if (size == 0)
+ return 0;
+
+ /* See UGH comment in output() for why we're doing this */
+ rsd->raw_data = yasm_xmalloc(size);
+ rsd->size = 0;
+
+ info->sect = sect;
+ info->rsd = rsd;
+ yasm_section_bcs_traverse(sect, info->errwarns, info,
+ rdf_objfmt_output_bytecode);
+
+ /* Sanity check final section size */
+ if (rsd->size != size)
+ yasm_internal_error(
+ N_("rdf: section computed size did not match actual size"));
+
+ return 0;
+}
+
+static int
+rdf_objfmt_output_section_reloc(yasm_section *sect, /*@null@*/ void *d)
+{
+ /*@null@*/ rdf_objfmt_output_info *info = (rdf_objfmt_output_info *)d;
+ /*@dependent@*/ /*@null@*/ rdf_section_data *rsd;
+ rdf_reloc *reloc;
+
+ assert(info != NULL);
+ rsd = yasm_section_get_data(sect, &rdf_section_data_cb);
+ assert(rsd != NULL);
+
+ if (rsd->type == RDF_SECT_BSS) {
+ /* Don't output BSS sections. */
+ return 0;
+ }
+
+ /* Empty? Go on to next section */
+ if (rsd->size == 0)
+ return 0;
+
+ reloc = (rdf_reloc *)yasm_section_relocs_first(sect);
+ while (reloc) {
+ unsigned char *localbuf = info->buf;
+
+ if (reloc->type == RDF_RELOC_SEG)
+ YASM_WRITE_8(localbuf, RDFREC_SEGRELOC);
+ else
+ YASM_WRITE_8(localbuf, RDFREC_RELOC);
+ YASM_WRITE_8(localbuf, 8); /* record length */
+ /* Section number, +0x40 if relative reloc */
+ YASM_WRITE_8(localbuf, rsd->scnum +
+ (reloc->type == RDF_RELOC_REL ? 0x40 : 0));
+ yasm_intnum_get_sized(reloc->reloc.addr, localbuf, 4, 32, 0, 0, 0);
+ localbuf += 4; /* offset of relocation */
+ YASM_WRITE_8(localbuf, reloc->size); /* size of relocation */
+ YASM_WRITE_16_L(localbuf, reloc->refseg); /* relocated symbol */
+ fwrite(info->buf, 10, 1, info->f);
+
+ reloc = (rdf_reloc *)yasm_section_reloc_next((yasm_reloc *)reloc);
+ }
+
+ return 0;
+}
+
+static int
+rdf_objfmt_output_section_file(yasm_section *sect, /*@null@*/ void *d)
+{
+ /*@null@*/ rdf_objfmt_output_info *info = (rdf_objfmt_output_info *)d;
+ /*@dependent@*/ /*@null@*/ rdf_section_data *rsd;
+ unsigned char *localbuf;
+
+ assert(info != NULL);
+ rsd = yasm_section_get_data(sect, &rdf_section_data_cb);
+ assert(rsd != NULL);
+
+ if (rsd->type == RDF_SECT_BSS) {
+ /* Don't output BSS sections. */
+ return 0;
+ }
+
+ /* Empty? Go on to next section */
+ if (rsd->size == 0)
+ return 0;
+
+ /* Section header */
+ localbuf = info->buf;
+ YASM_WRITE_16_L(localbuf, rsd->type); /* type */
+ YASM_WRITE_16_L(localbuf, rsd->scnum); /* number */
+ YASM_WRITE_16_L(localbuf, rsd->reserved); /* reserved */
+ YASM_WRITE_32_L(localbuf, rsd->size); /* length */
+ fwrite(info->buf, 10, 1, info->f);
+
+ /* Section data */
+ fwrite(rsd->raw_data, rsd->size, 1, info->f);
+
+ /* Free section data */
+ yasm_xfree(rsd->raw_data);
+ rsd->raw_data = NULL;
+
+ return 0;
+}
+
+#define FLAG_EXT 0x1000
+#define FLAG_GLOB 0x2000
+#define FLAG_SET 0x4000
+#define FLAG_CLR 0x8000
+#define FLAG_MASK 0x0fff
+
+static int
+rdf_helper_flag(void *obj, yasm_valparam *vp, unsigned long line, void *d,
+ uintptr_t flag)
+{
+ yasm_symrec *sym = (yasm_symrec *)obj;
+ yasm_sym_vis vis = yasm_symrec_get_visibility(sym);
+ unsigned int *flags = (unsigned int *)d;
+
+ if (((vis & YASM_SYM_GLOBAL) && (flag & FLAG_GLOB)) ||
+ ((vis & YASM_SYM_EXTERN) && (flag & FLAG_EXT))) {
+ if (flag & FLAG_SET)
+ *flags |= flag & FLAG_MASK;
+ else if (flag & FLAG_CLR)
+ *flags &= ~(flag & FLAG_MASK);
+ }
+ return 0;
+}
+
+static unsigned int
+rdf_parse_flags(yasm_symrec *sym)
+{
+ /*@dependent@*/ /*@null@*/ yasm_valparamhead *objext_valparams =
+ yasm_symrec_get_objext_valparams(sym);
+ unsigned int flags = 0;
+
+ static const yasm_dir_help help[] = {
+ { "data", 0, rdf_helper_flag, 0,
+ FLAG_EXT|FLAG_GLOB|FLAG_SET|SYM_DATA },
+ { "object", 0, rdf_helper_flag, 0,
+ FLAG_EXT|FLAG_GLOB|FLAG_SET|SYM_DATA },
+ { "proc", 0, rdf_helper_flag, 0,
+ FLAG_EXT|FLAG_GLOB|FLAG_SET|SYM_FUNCTION },
+ { "function", 0, rdf_helper_flag, 0,
+ FLAG_EXT|FLAG_GLOB|FLAG_SET|SYM_FUNCTION },
+ { "import", 0, rdf_helper_flag, 0, FLAG_EXT|FLAG_SET|SYM_IMPORT },
+ { "export", 0, rdf_helper_flag, 0, FLAG_GLOB|FLAG_SET|SYM_GLOBAL },
+ { "far", 0, rdf_helper_flag, 0, FLAG_EXT|FLAG_SET|SYM_FAR },
+ { "near", 0, rdf_helper_flag, 0, FLAG_EXT|FLAG_CLR|SYM_FAR }
+ };
+
+ if (!objext_valparams)
+ return 0;
+
+ yasm_dir_helper(sym, yasm_vps_first(objext_valparams), 0, help,
+ NELEMS(help), &flags, yasm_dir_helper_valparam_warn);
+
+ return flags;
+}
+
+static int
+rdf_objfmt_output_sym(yasm_symrec *sym, /*@null@*/ void *d)
+{
+ /*@null@*/ rdf_objfmt_output_info *info = (rdf_objfmt_output_info *)d;
+ yasm_sym_vis vis = yasm_symrec_get_visibility(sym);
+ /*@only@*/ char *name;
+ size_t len;
+ unsigned long value = 0;
+ unsigned int scnum = 0;
+ /*@dependent@*/ /*@null@*/ yasm_section *sect;
+ /*@dependent@*/ /*@null@*/ yasm_bytecode *precbc;
+ unsigned char *localbuf;
+
+ assert(info != NULL);
+
+ if (vis == YASM_SYM_LOCAL || vis == YASM_SYM_DLOCAL)
+ return 0; /* skip local syms */
+
+ /* Look at symrec for value/scnum/etc. */
+ if (yasm_symrec_get_label(sym, &precbc)) {
+ /*@dependent@*/ /*@null@*/ rdf_section_data *csectd;
+
+ if (precbc)
+ sect = yasm_bc_get_section(precbc);
+ else
+ sect = NULL;
+ if (!sect)
+ return 0;
+
+ /* it's a label: get value and offset. */
+ csectd = yasm_section_get_data(sect, &rdf_section_data_cb);
+ if (csectd)
+ scnum = csectd->scnum;
+ else
+ yasm_internal_error(N_("didn't understand section"));
+ value = yasm_bc_next_offset(precbc);
+ } else if (yasm_symrec_get_equ(sym)) {
+ yasm_warn_set(YASM_WARN_GENERAL,
+ N_("rdf does not support exporting EQU/absolute values"));
+ yasm_errwarn_propagate(info->errwarns, yasm_symrec_get_decl_line(sym));
+ return 0;
+ }
+
+ name = yasm_symrec_get_global_name(sym, info->object);
+ len = strlen(name);
+
+ if (len > EXIM_LABEL_MAX-1) {
+ yasm_warn_set(YASM_WARN_GENERAL,
+ N_("label name too long, truncating to %d bytes"),
+ EXIM_LABEL_MAX);
+ len = EXIM_LABEL_MAX-1;
+ }
+
+ localbuf = info->buf;
+ if (vis & YASM_SYM_GLOBAL) {
+ YASM_WRITE_8(localbuf, RDFREC_GLOBAL);
+ YASM_WRITE_8(localbuf, 6+len+1); /* record length */
+ YASM_WRITE_8(localbuf, rdf_parse_flags(sym)); /* flags */
+ YASM_WRITE_8(localbuf, scnum); /* segment referred to */
+ YASM_WRITE_32_L(localbuf, value); /* offset */
+ } else {
+ /* Save symbol segment in symrec data (for later reloc gen) */
+ scnum = info->indx++;
+ rdf_objfmt_sym_set_data(sym, scnum);
+
+ if (vis & YASM_SYM_COMMON) {
+ /*@dependent@*/ /*@null@*/ yasm_expr **csize_expr;
+ const yasm_intnum *intn;
+ /*@dependent@*/ /*@null@*/ yasm_valparamhead *objext_valparams =
+ yasm_symrec_get_objext_valparams(sym);
+ unsigned long addralign = 0;
+
+ YASM_WRITE_8(localbuf, RDFREC_COMMON);
+ YASM_WRITE_8(localbuf, 8+len+1); /* record length */
+ YASM_WRITE_16_L(localbuf, scnum); /* segment allocated */
+
+ /* size */
+ csize_expr = yasm_symrec_get_common_size(sym);
+ assert(csize_expr != NULL);
+ intn = yasm_expr_get_intnum(csize_expr, 1);
+ if (!intn) {
+ yasm_error_set(YASM_ERROR_NOT_CONSTANT,
+ N_("COMMON data size not an integer expression"));
+ } else
+ value = yasm_intnum_get_uint(intn);
+ YASM_WRITE_32_L(localbuf, value);
+
+ /* alignment */
+ if (objext_valparams) {
+ yasm_valparam *vp = yasm_vps_first(objext_valparams);
+ for (; vp; vp = yasm_vps_next(vp)) {
+ if (!vp->val) {
+ /*@only@*/ /*@null@*/ yasm_expr *align_expr;
+ /*@dependent@*/ /*@null@*/
+ const yasm_intnum *align_intn;
+
+ if (!(align_expr = yasm_vp_expr(vp,
+ info->object->symtab,
+ yasm_symrec_get_decl_line(sym))) ||
+ !(align_intn = yasm_expr_get_intnum(&align_expr,
+ 0))) {
+ yasm_error_set(YASM_ERROR_VALUE,
+ N_("argument to `%s' is not an integer"),
+ vp->val);
+ if (align_expr)
+ yasm_expr_destroy(align_expr);
+ continue;
+ }
+ addralign = yasm_intnum_get_uint(align_intn);
+ yasm_expr_destroy(align_expr);
+
+ /* Alignments must be a power of two. */
+ if (!is_exp2(addralign)) {
+ yasm_error_set(YASM_ERROR_VALUE,
+ N_("alignment constraint is not a power of two"));
+ continue;
+ }
+ } else
+ yasm_warn_set(YASM_WARN_GENERAL,
+ N_("Unrecognized qualifier `%s'"), vp->val);
+ }
+ }
+ YASM_WRITE_16_L(localbuf, addralign);
+ } else if (vis & YASM_SYM_EXTERN) {
+ unsigned int flags = rdf_parse_flags(sym);
+ if (flags & SYM_FAR) {
+ YASM_WRITE_8(localbuf, RDFREC_FARIMPORT);
+ flags &= ~SYM_FAR;
+ } else
+ YASM_WRITE_8(localbuf, RDFREC_IMPORT);
+ YASM_WRITE_8(localbuf, 3+len+1); /* record length */
+ YASM_WRITE_8(localbuf, flags); /* flags */
+ YASM_WRITE_16_L(localbuf, scnum); /* segment allocated */
+ }
+ }
+
+ /* Symbol name */
+ memcpy(localbuf, name, len);
+ localbuf += len;
+ YASM_WRITE_8(localbuf, 0); /* 0-terminated name */
+ yasm_xfree(name);
+
+ fwrite(info->buf, (unsigned long)(localbuf-info->buf), 1, info->f);
+
+ yasm_errwarn_propagate(info->errwarns, yasm_symrec_get_decl_line(sym));
+ return 0;
+}
+
+static void
+rdf_objfmt_output(yasm_object *object, FILE *f, int all_syms,
+ yasm_errwarns *errwarns)
+{
+ yasm_objfmt_rdf *objfmt_rdf = (yasm_objfmt_rdf *)object->objfmt;
+ rdf_objfmt_output_info info;
+ unsigned char *localbuf;
+ long headerlen, filelen;
+ xdf_str *cur;
+ size_t len;
+
+ info.object = object;
+ info.objfmt_rdf = objfmt_rdf;
+ info.errwarns = errwarns;
+ info.f = f;
+ info.buf = yasm_xmalloc(REGULAR_OUTBUF_SIZE);
+ info.bss_size = 0;
+
+ /* Allocate space for file header by seeking forward */
+ if (fseek(f, (long)strlen(RDF_MAGIC)+8, SEEK_SET) < 0) {
+ yasm__fatal(N_("could not seek on output file"));
+ /*@notreached@*/
+ return;
+ }
+
+ /* Output custom header records (library and module, etc) */
+ cur = STAILQ_FIRST(&objfmt_rdf->module_names);
+ while (cur) {
+ len = strlen(cur->str)+1;
+ localbuf = info.buf;
+ YASM_WRITE_8(localbuf, RDFREC_MODNAME); /* record type */
+ YASM_WRITE_8(localbuf, len); /* record length */
+ fwrite(info.buf, 2, 1, f);
+ fwrite(cur->str, len, 1, f);
+ cur = STAILQ_NEXT(cur, link);
+ }
+
+ cur = STAILQ_FIRST(&objfmt_rdf->library_names);
+ while (cur) {
+ len = strlen(cur->str)+1;
+ localbuf = info.buf;
+ YASM_WRITE_8(localbuf, RDFREC_DLL); /* record type */
+ YASM_WRITE_8(localbuf, len); /* record length */
+ fwrite(info.buf, 2, 1, f);
+ fwrite(cur->str, len, 1, f);
+ cur = STAILQ_NEXT(cur, link);
+ }
+
+ /* Output symbol table */
+ info.indx = objfmt_rdf->parse_scnum;
+ yasm_symtab_traverse(object->symtab, &info, rdf_objfmt_output_sym);
+
+ /* UGH! Due to the fact the relocs go at the beginning of the file, and
+ * we only know if we have relocs when we output the sections, we have
+ * to output the section data before we have output the relocs. But
+ * we also don't know how much space to preallocate for relocs, so....
+ * we output into memory buffers first (thus the UGH).
+ *
+ * Stupid object format design, if you ask me (basically all other
+ * object formats put the relocs *after* the section data to avoid this
+ * exact problem).
+ *
+ * We also calculate the total size of all BSS sections here.
+ */
+ if (yasm_object_sections_traverse(object, &info,
+ rdf_objfmt_output_section_mem))
+ return;
+
+ /* Output all relocs */
+ if (yasm_object_sections_traverse(object, &info,
+ rdf_objfmt_output_section_reloc))
+ return;
+
+ /* Output BSS record */
+ if (info.bss_size > 0) {
+ localbuf = info.buf;
+ YASM_WRITE_8(localbuf, RDFREC_BSS); /* record type */
+ YASM_WRITE_8(localbuf, 4); /* record length */
+ YASM_WRITE_32_L(localbuf, info.bss_size); /* total BSS size */
+ fwrite(info.buf, 6, 1, f);
+ }
+
+ /* Determine header length */
+ headerlen = ftell(f);
+ if (headerlen == -1) {
+ yasm__fatal(N_("could not get file position on output file"));
+ /*@notreached@*/
+ return;
+ }
+
+ /* Section data (to file) */
+ if (yasm_object_sections_traverse(object, &info,
+ rdf_objfmt_output_section_file))
+ return;
+
+ /* NULL section to end file */
+ memset(info.buf, 0, 10);
+ fwrite(info.buf, 10, 1, f);
+
+ /* Determine object length */
+ filelen = ftell(f);
+ if (filelen == -1) {
+ yasm__fatal(N_("could not get file position on output file"));
+ /*@notreached@*/
+ return;
+ }
+
+ /* Write file header */
+ if (fseek(f, 0, SEEK_SET) < 0) {
+ yasm__fatal(N_("could not seek on output file"));
+ /*@notreached@*/
+ return;
+ }
+
+ fwrite(RDF_MAGIC, strlen(RDF_MAGIC), 1, f);
+ localbuf = info.buf;
+ YASM_WRITE_32_L(localbuf, filelen-10); /* object size */
+ YASM_WRITE_32_L(localbuf, headerlen-14); /* header size */
+ fwrite(info.buf, 8, 1, f);
+
+ yasm_xfree(info.buf);
+}
+
+static void
+rdf_objfmt_destroy(yasm_objfmt *objfmt)
+{
+ yasm_objfmt_rdf *objfmt_rdf = (yasm_objfmt_rdf *)objfmt;
+ xdf_str *cur, *next;
+
+ cur = STAILQ_FIRST(&objfmt_rdf->module_names);
+ while (cur) {
+ next = STAILQ_NEXT(cur, link);
+ yasm_xfree(cur->str);
+ yasm_xfree(cur);
+ cur = next;
+ }
+
+ cur = STAILQ_FIRST(&objfmt_rdf->library_names);
+ while (cur) {
+ next = STAILQ_NEXT(cur, link);
+ yasm_xfree(cur->str);
+ yasm_xfree(cur);
+ cur = next;
+ }
+
+ yasm_xfree(objfmt);
+}
+
+static void
+rdf_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_rdf *objfmt_rdf = (yasm_objfmt_rdf *)object->objfmt;
+ rdf_section_data *data;
+ yasm_symrec *sym;
+
+ data = yasm_xmalloc(sizeof(rdf_section_data));
+ data->scnum = objfmt_rdf->parse_scnum++;
+ data->type = 0;
+ data->reserved = 0;
+ data->size = 0;
+ data->raw_data = NULL;
+ yasm_section_add_data(sect, &rdf_section_data_cb, data);
+
+ sym = yasm_symtab_define_label(object->symtab, sectname,
+ yasm_section_bcs_first(sect), 1, line);
+ data->sym = sym;
+}
+
+static yasm_section *
+rdf_objfmt_add_default_section(yasm_object *object)
+{
+ yasm_section *retval;
+ rdf_section_data *rsd;
+ int isnew;
+
+ retval = yasm_object_get_general(object, ".text", 0, 1, 0, &isnew, 0);
+ if (isnew) {
+ rsd = yasm_section_get_data(retval, &rdf_section_data_cb);
+ rsd->type = RDF_SECT_CODE;
+ rsd->reserved = 0;
+ yasm_section_set_default(retval, 1);
+ }
+ return retval;
+}
+
+static int
+rdf_helper_set_type(void *obj, yasm_valparam *vp, unsigned long line,
+ void *d, uintptr_t newtype)
+{
+ unsigned int *type = (unsigned int *)d;
+ *type = newtype;
+ return 0;
+}
+
+struct rdf_section_switch_data {
+ /*@only@*/ /*@null@*/ yasm_intnum *reserved_intn;
+ unsigned int type;
+};
+
+static int
+rdf_helper_set_reserved(void *obj, yasm_valparam *vp, unsigned long line,
+ void *d)
+{
+ struct rdf_section_switch_data *data = (struct rdf_section_switch_data *)d;
+
+ if (!vp->val && vp->type == YASM_PARAM_EXPR)
+ return yasm_dir_helper_intn(obj, vp, line, &data->reserved_intn, 0);
+ else
+ return yasm_dir_helper_valparam_warn(obj, vp, line, d);
+}
+
+static /*@observer@*/ /*@null@*/ yasm_section *
+rdf_objfmt_section_switch(yasm_object *object, yasm_valparamhead *valparams,
+ /*@unused@*/ /*@null@*/
+ yasm_valparamhead *objext_valparams,
+ unsigned long line)
+{
+ yasm_valparam *vp = yasm_vps_first(valparams);
+ yasm_section *retval;
+ int isnew;
+ unsigned int reserved = 0;
+ int flags_override = 0;
+ const char *sectname;
+ rdf_section_data *rsd;
+
+ struct rdf_section_switch_data data;
+
+ static const yasm_dir_help help[] = {
+ { "bss", 0, rdf_helper_set_type,
+ offsetof(struct rdf_section_switch_data, type), RDF_SECT_BSS },
+ { "code", 0, rdf_helper_set_type,
+ offsetof(struct rdf_section_switch_data, type), RDF_SECT_CODE },
+ { "text", 0, rdf_helper_set_type,
+ offsetof(struct rdf_section_switch_data, type), RDF_SECT_CODE },
+ { "data", 0, rdf_helper_set_type,
+ offsetof(struct rdf_section_switch_data, type), RDF_SECT_DATA },
+ { "comment", 0, rdf_helper_set_type,
+ offsetof(struct rdf_section_switch_data, type), RDF_SECT_COMMENT },
+ { "lcomment", 0, rdf_helper_set_type,
+ offsetof(struct rdf_section_switch_data, type), RDF_SECT_LCOMMENT },
+ { "pcomment", 0, rdf_helper_set_type,
+ offsetof(struct rdf_section_switch_data, type), RDF_SECT_PCOMMENT },
+ { "symdebug", 0, rdf_helper_set_type,
+ offsetof(struct rdf_section_switch_data, type), RDF_SECT_SYMDEBUG },
+ { "linedebug", 0, rdf_helper_set_type,
+ offsetof(struct rdf_section_switch_data, type), RDF_SECT_LINEDEBUG },
+ { "reserved", 1, yasm_dir_helper_intn,
+ offsetof(struct rdf_section_switch_data, reserved_intn), 0 }
+ };
+
+ data.reserved_intn = NULL;
+ data.type = 0xffff;
+
+ vp = yasm_vps_first(valparams);
+ sectname = yasm_vp_string(vp);
+ if (!sectname)
+ return NULL;
+ vp = yasm_vps_next(vp);
+
+ if (strcmp(sectname, ".text") == 0)
+ data.type = RDF_SECT_CODE;
+ else if (strcmp(sectname, ".data") == 0)
+ data.type = RDF_SECT_DATA;
+ else if (strcmp(sectname, ".bss") == 0)
+ data.type = RDF_SECT_BSS;
+
+ flags_override = yasm_dir_helper(object, vp, line, help, NELEMS(help),
+ &data, rdf_helper_set_reserved);
+ if (flags_override < 0)
+ return NULL; /* error occurred */
+
+ if (data.type == 0xffff) {
+ yasm_error_set(YASM_ERROR_VALUE,
+ N_("new segment declared without type code"));
+ data.type = RDF_SECT_DATA;
+ }
+
+ if (data.reserved_intn) {
+ reserved = yasm_intnum_get_uint(data.reserved_intn);
+ yasm_intnum_destroy(data.reserved_intn);
+ }
+
+ retval = yasm_object_get_general(object, sectname, 0, 1,
+ data.type == RDF_SECT_BSS, &isnew, line);
+
+ rsd = yasm_section_get_data(retval, &rdf_section_data_cb);
+
+ if (isnew || yasm_section_is_default(retval)) {
+ yasm_section_set_default(retval, 0);
+ rsd->type = data.type;
+ rsd->reserved = reserved;
+ } else if (flags_override)
+ yasm_warn_set(YASM_WARN_GENERAL,
+ N_("section flags ignored on section redeclaration"));
+ return retval;
+}
+
+static /*@observer@*/ /*@null@*/ yasm_symrec *
+rdf_objfmt_get_special_sym(yasm_object *object, const char *name,
+ const char *parser)
+{
+ return NULL;
+}
+
+static void
+rdf_section_data_destroy(void *data)
+{
+ rdf_section_data *rsd = (rdf_section_data *)data;
+ if (rsd->raw_data)
+ yasm_xfree(rsd->raw_data);
+ yasm_xfree(data);
+}
+
+static void
+rdf_section_data_print(void *data, FILE *f, int indent_level)
+{
+ rdf_section_data *rsd = (rdf_section_data *)data;
+
+ fprintf(f, "%*ssym=\n", indent_level, "");
+ yasm_symrec_print(rsd->sym, f, indent_level+1);
+ fprintf(f, "%*sscnum=%ld\n", indent_level, "", rsd->scnum);
+ fprintf(f, "%*stype=0x%x\n", indent_level, "", rsd->type);
+ fprintf(f, "%*sreserved=0x%x\n", indent_level, "", rsd->reserved);
+ fprintf(f, "%*ssize=%ld\n", indent_level, "", rsd->size);
+}
+
+static void
+rdf_symrec_data_destroy(void *data)
+{
+ yasm_xfree(data);
+}
+
+static void
+rdf_symrec_data_print(void *data, FILE *f, int indent_level)
+{
+ rdf_symrec_data *rsymd = (rdf_symrec_data *)data;
+
+ fprintf(f, "%*ssymtab segment=%u\n", indent_level, "", rsymd->segment);
+}
+
+static void
+rdf_objfmt_add_libmodule(yasm_object *object, char *name, int lib)
+{
+ yasm_objfmt_rdf *objfmt_rdf = (yasm_objfmt_rdf *)object->objfmt;
+ xdf_str *str;
+
+ /* Add to list */
+ str = yasm_xmalloc(sizeof(xdf_str));
+ str->str = name;
+ if (lib)
+ STAILQ_INSERT_TAIL(&objfmt_rdf->library_names, str, link);
+ else
+ STAILQ_INSERT_TAIL(&objfmt_rdf->module_names, str, link);
+
+ if (strlen(str->str) > MODLIB_NAME_MAX-1) {
+ yasm_warn_set(YASM_WARN_GENERAL,
+ N_("name too long, truncating to %d bytes"),
+ MODLIB_NAME_MAX);
+ str->str[MODLIB_NAME_MAX-1] = '\0';
+ }
+}
+
+static void
+dir_library(yasm_object *object, yasm_valparamhead *valparams,
+ yasm_valparamhead *objext_valparams, unsigned long line)
+{
+ yasm_valparam *vp = yasm_vps_first(valparams);
+ rdf_objfmt_add_libmodule(object, yasm__xstrdup(yasm_vp_string(vp)), 1);
+}
+
+static void
+dir_module(yasm_object *object, yasm_valparamhead *valparams,
+ yasm_valparamhead *objext_valparams, unsigned long line)
+{
+ yasm_valparam *vp = yasm_vps_first(valparams);
+ rdf_objfmt_add_libmodule(object, yasm__xstrdup(yasm_vp_string(vp)), 0);
+}
+
+/* Define valid debug formats to use with this object format */
+static const char *rdf_objfmt_dbgfmt_keywords[] = {
+ "null",
+ NULL
+};
+
+static const yasm_directive rdf_objfmt_directives[] = {
+ { "library", "nasm", dir_library, YASM_DIR_ARG_REQUIRED },
+ { "module", "nasm", dir_module, YASM_DIR_ARG_REQUIRED },
+ { NULL, NULL, NULL, 0 }
+};
+
+static const char *rdf_nasm_stdmac[] = {
+ "%imacro library 1+.nolist",
+ "[library %1]",
+ "%endmacro",
+ "%imacro module 1+.nolist",
+ "[module %1]",
+ "%endmacro",
+ NULL
+};
+
+static const yasm_stdmac rdf_objfmt_stdmacs[] = {
+ { "nasm", "nasm", rdf_nasm_stdmac },
+ { NULL, NULL, NULL }
+};
+
+/* Define objfmt structure -- see objfmt.h for details */
+yasm_objfmt_module yasm_rdf_LTX_objfmt = {
+ "Relocatable Dynamic Object File Format (RDOFF) v2.0",
+ "rdf",
+ "rdf",
+ 32,
+ 0,
+ rdf_objfmt_dbgfmt_keywords,
+ "null",
+ rdf_objfmt_directives,
+ rdf_objfmt_stdmacs,
+ rdf_objfmt_create,
+ rdf_objfmt_output,
+ rdf_objfmt_destroy,
+ rdf_objfmt_add_default_section,
+ rdf_objfmt_init_new_section,
+ rdf_objfmt_section_switch,
+ rdf_objfmt_get_special_sym
+};
diff --git a/contrib/tools/yasm/modules/objfmts/xdf/xdf-objfmt.c b/contrib/tools/yasm/modules/objfmts/xdf/xdf-objfmt.c
index 9ad0e60afa..b2ac442511 100644
--- a/contrib/tools/yasm/modules/objfmts/xdf/xdf-objfmt.c
+++ b/contrib/tools/yasm/modules/objfmts/xdf/xdf-objfmt.c
@@ -1,842 +1,842 @@
-/*
- * Extended Dynamic Object format
- *
- * Copyright (C) 2004-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>
-
-#include <libyasm.h>
-
-
-#define REGULAR_OUTBUF_SIZE 1024
-
-#define XDF_MAGIC 0x87654322
-
-#define XDF_SYM_EXTERN 1
-#define XDF_SYM_GLOBAL 2
-#define XDF_SYM_EQU 4
-
-typedef struct xdf_reloc {
- yasm_reloc reloc;
- /*@null@*/ yasm_symrec *base; /* base symbol (for WRT) */
- enum {
- XDF_RELOC_REL = 1, /* relative to segment */
- XDF_RELOC_WRT = 2, /* relative to symbol */
- XDF_RELOC_RIP = 4, /* RIP-relative */
- XDF_RELOC_SEG = 8 /* segment containing symbol */
- } type; /* type of relocation */
- enum {
- XDF_RELOC_8 = 1,
- XDF_RELOC_16 = 2,
- XDF_RELOC_32 = 4,
- XDF_RELOC_64 = 8
- } size; /* size of relocation */
- unsigned int shift; /* relocation shift (0,4,8,16,24,32) */
-} xdf_reloc;
-
-typedef struct xdf_section_data {
- /*@dependent@*/ yasm_symrec *sym; /* symbol created for this section */
- yasm_intnum *addr; /* starting memory address */
- yasm_intnum *vaddr; /* starting virtual address */
- long scnum; /* section number (0=first section) */
- enum {
- XDF_SECT_ABSOLUTE = 0x01,
- XDF_SECT_FLAT = 0x02,
- XDF_SECT_BSS = 0x04,
- XDF_SECT_EQU = 0x08,
- XDF_SECT_USE_16 = 0x10,
- XDF_SECT_USE_32 = 0x20,
- XDF_SECT_USE_64 = 0x40
- } flags; /* section flags */
- unsigned long scnptr; /* file ptr to raw data */
- unsigned long size; /* size of raw data (section data) in bytes */
- unsigned long relptr; /* file ptr to relocation */
- unsigned long nreloc; /* number of relocation entries >64k -> error */
-} xdf_section_data;
-
-typedef struct xdf_symrec_data {
- unsigned long index; /* assigned XDF symbol table index */
-} xdf_symrec_data;
-
-typedef struct yasm_objfmt_xdf {
- yasm_objfmt_base objfmt; /* base structure */
-
- long parse_scnum; /* sect numbering in parser */
-} yasm_objfmt_xdf;
-
-typedef struct xdf_objfmt_output_info {
- yasm_object *object;
- yasm_objfmt_xdf *objfmt_xdf;
- yasm_errwarns *errwarns;
- /*@dependent@*/ FILE *f;
- /*@only@*/ unsigned char *buf;
- yasm_section *sect;
- /*@dependent@*/ xdf_section_data *xsd;
-
- unsigned long indx; /* current symbol index */
- int all_syms; /* outputting all symbols? */
- unsigned long strtab_offset; /* current string table offset */
-} xdf_objfmt_output_info;
-
-static void xdf_section_data_destroy(/*@only@*/ void *d);
-static void xdf_section_data_print(void *data, FILE *f, int indent_level);
-
-static const yasm_assoc_data_callback xdf_section_data_cb = {
- xdf_section_data_destroy,
- xdf_section_data_print
-};
-
-static void xdf_symrec_data_destroy(/*@only@*/ void *d);
-static void xdf_symrec_data_print(void *data, FILE *f, int indent_level);
-
-static const yasm_assoc_data_callback xdf_symrec_data_cb = {
- xdf_symrec_data_destroy,
- xdf_symrec_data_print
-};
-
-yasm_objfmt_module yasm_xdf_LTX_objfmt;
-
-
-static yasm_objfmt *
-xdf_objfmt_create(yasm_object *object)
-{
- yasm_objfmt_xdf *objfmt_xdf = yasm_xmalloc(sizeof(yasm_objfmt_xdf));
-
- /* Only support x86 arch */
- if (yasm__strcasecmp(yasm_arch_keyword(object->arch), "x86") != 0) {
- yasm_xfree(objfmt_xdf);
- return NULL;
- }
-
- /* Support x86 and amd64 machines of x86 arch */
- if (yasm__strcasecmp(yasm_arch_get_machine(object->arch), "x86") &&
- yasm__strcasecmp(yasm_arch_get_machine(object->arch), "amd64")) {
- yasm_xfree(objfmt_xdf);
- return NULL;
- }
-
- objfmt_xdf->parse_scnum = 0; /* section numbering starts at 0 */
-
- objfmt_xdf->objfmt.module = &yasm_xdf_LTX_objfmt;
-
- return (yasm_objfmt *)objfmt_xdf;
-}
-
-static int
-xdf_objfmt_output_value(yasm_value *value, unsigned char *buf,
- unsigned int destsize, unsigned long offset,
- yasm_bytecode *bc, int warn, /*@null@*/ void *d)
-{
- /*@null@*/ xdf_objfmt_output_info *info = (xdf_objfmt_output_info *)d;
- /*@dependent@*/ /*@null@*/ yasm_intnum *intn;
- unsigned long intn_minus;
- int retval;
- unsigned int valsize = value->size;
-
- assert(info != NULL);
-
- if (value->abs)
- value->abs = yasm_expr_simplify(value->abs, 1);
-
- /* Try to output constant and PC-relative section-local first.
- * Note this does NOT output any value with a SEG, WRT, external,
- * cross-section, or non-PC-relative reference (those are handled below).
- */
- switch (yasm_value_output_basic(value, buf, destsize, bc, warn,
- info->object->arch)) {
- case -1:
- return 1;
- case 0:
- break;
- default:
- return 0;
- }
-
- if (value->section_rel) {
- yasm_error_set(YASM_ERROR_TOO_COMPLEX,
- N_("xdf: relocation too complex"));
- return 1;
- }
-
- intn_minus = 0;
- if (value->rel) {
- xdf_reloc *reloc;
-
- reloc = yasm_xmalloc(sizeof(xdf_reloc));
- reloc->reloc.addr = yasm_intnum_create_uint(bc->offset + offset);
- reloc->reloc.sym = value->rel;
- reloc->base = NULL;
- reloc->size = valsize/8;
- reloc->shift = value->rshift;
-
- if (value->seg_of)
- reloc->type = XDF_RELOC_SEG;
- else if (value->wrt) {
- reloc->base = value->wrt;
- reloc->type = XDF_RELOC_WRT;
- } else if (value->curpos_rel) {
- reloc->type = XDF_RELOC_RIP;
- /* Adjust to start of section, so subtract out the bytecode
- * offset.
- */
- intn_minus = bc->offset;
- } else
- reloc->type = XDF_RELOC_REL;
- info->xsd->nreloc++;
- yasm_section_add_reloc(info->sect, (yasm_reloc *)reloc, yasm_xfree);
- }
-
- if (intn_minus > 0) {
- intn = yasm_intnum_create_uint(intn_minus);
- yasm_intnum_calc(intn, YASM_EXPR_NEG, NULL);
- } else
- intn = yasm_intnum_create_uint(0);
-
- if (value->abs) {
- yasm_intnum *intn2 = yasm_expr_get_intnum(&value->abs, 0);
- if (!intn2) {
- yasm_error_set(YASM_ERROR_TOO_COMPLEX,
- N_("xdf: relocation too complex"));
- yasm_intnum_destroy(intn);
- return 1;
- }
- yasm_intnum_calc(intn, YASM_EXPR_ADD, intn2);
- }
-
- retval = yasm_arch_intnum_tobytes(info->object->arch, intn, buf, destsize,
- valsize, 0, bc, warn);
- yasm_intnum_destroy(intn);
- return retval;
-}
-
-static int
-xdf_objfmt_output_bytecode(yasm_bytecode *bc, /*@null@*/ void *d)
-{
- /*@null@*/ xdf_objfmt_output_info *info = (xdf_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,
- xdf_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;
- }
-
- info->xsd->size += size;
-
- /* 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: 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;
-}
-
-static int
-xdf_objfmt_output_section(yasm_section *sect, /*@null@*/ void *d)
-{
- /*@null@*/ xdf_objfmt_output_info *info = (xdf_objfmt_output_info *)d;
- /*@dependent@*/ /*@null@*/ xdf_section_data *xsd;
- long pos;
- xdf_reloc *reloc;
-
- assert(info != NULL);
- xsd = yasm_section_get_data(sect, &xdf_section_data_cb);
- assert(xsd != NULL);
-
- if (xsd->flags & XDF_SECT_BSS) {
- /* Don't output BSS sections.
- * TODO: Check for non-reserve bytecodes?
- */
- pos = 0; /* position = 0 because it's not in the file */
- xsd->size = yasm_bc_next_offset(yasm_section_bcs_last(sect));
- } else {
- pos = ftell(info->f);
- if (pos == -1) {
- yasm__fatal(N_("could not get file position on output file"));
- /*@notreached@*/
- return 1;
- }
-
- info->sect = sect;
- info->xsd = xsd;
- yasm_section_bcs_traverse(sect, info->errwarns, info,
- xdf_objfmt_output_bytecode);
-
- /* Sanity check final section size */
- if (xsd->size != yasm_bc_next_offset(yasm_section_bcs_last(sect)))
- yasm_internal_error(
- N_("xdf: section computed size did not match actual size"));
- }
-
- /* Empty? Go on to next section */
- if (xsd->size == 0)
- return 0;
-
- xsd->scnptr = (unsigned long)pos;
-
- /* No relocations to output? Go on to next section */
- if (xsd->nreloc == 0)
- return 0;
-
- pos = ftell(info->f);
- if (pos == -1) {
- yasm__fatal(N_("could not get file position on output file"));
- /*@notreached@*/
- return 1;
- }
- xsd->relptr = (unsigned long)pos;
-
- reloc = (xdf_reloc *)yasm_section_relocs_first(sect);
- while (reloc) {
- unsigned char *localbuf = info->buf;
- /*@null@*/ xdf_symrec_data *xsymd;
-
- xsymd = yasm_symrec_get_data(reloc->reloc.sym, &xdf_symrec_data_cb);
- if (!xsymd)
- yasm_internal_error(
- N_("xdf: no symbol data for relocated symbol"));
-
- yasm_intnum_get_sized(reloc->reloc.addr, localbuf, 4, 32, 0, 0, 0);
- localbuf += 4; /* address of relocation */
- YASM_WRITE_32_L(localbuf, xsymd->index); /* relocated symbol */
- if (reloc->base) {
- xsymd = yasm_symrec_get_data(reloc->base, &xdf_symrec_data_cb);
- if (!xsymd)
- yasm_internal_error(
- N_("xdf: no symbol data for relocated base symbol"));
- YASM_WRITE_32_L(localbuf, xsymd->index); /* base symbol */
- } else {
- if (reloc->type == XDF_RELOC_WRT)
- yasm_internal_error(
- N_("xdf: no base symbol for WRT relocation"));
- YASM_WRITE_32_L(localbuf, 0); /* no base symbol */
- }
- YASM_WRITE_8(localbuf, reloc->type); /* type of relocation */
- YASM_WRITE_8(localbuf, reloc->size); /* size of relocation */
- YASM_WRITE_8(localbuf, reloc->shift); /* relocation shift */
- YASM_WRITE_8(localbuf, 0); /* flags */
- fwrite(info->buf, 16, 1, info->f);
-
- reloc = (xdf_reloc *)yasm_section_reloc_next((yasm_reloc *)reloc);
- }
-
- return 0;
-}
-
-static int
-xdf_objfmt_output_secthead(yasm_section *sect, /*@null@*/ void *d)
-{
- /*@null@*/ xdf_objfmt_output_info *info = (xdf_objfmt_output_info *)d;
- /*@dependent@*/ /*@null@*/ xdf_section_data *xsd;
- /*@null@*/ xdf_symrec_data *xsymd;
- unsigned char *localbuf;
-
- assert(info != NULL);
- xsd = yasm_section_get_data(sect, &xdf_section_data_cb);
- assert(xsd != NULL);
-
- localbuf = info->buf;
- xsymd = yasm_symrec_get_data(xsd->sym, &xdf_symrec_data_cb);
- assert(xsymd != NULL);
-
- YASM_WRITE_32_L(localbuf, xsymd->index); /* section name symbol */
- if (xsd->addr) {
- yasm_intnum_get_sized(xsd->addr, localbuf, 8, 64, 0, 0, 0);
- localbuf += 8; /* physical address */
- } else {
- YASM_WRITE_32_L(localbuf, 0);
- YASM_WRITE_32_L(localbuf, 0);
- }
- if (xsd->vaddr) {
- yasm_intnum_get_sized(xsd->vaddr, localbuf, 8, 64, 0, 0, 0);
- localbuf += 8; /* virtual address */
- } else if (xsd->addr) {
- yasm_intnum_get_sized(xsd->addr, localbuf, 8, 64, 0, 0, 0);
- localbuf += 8; /* VA=PA */
- } else {
- YASM_WRITE_32_L(localbuf, 0);
- YASM_WRITE_32_L(localbuf, 0);
- }
- YASM_WRITE_16_L(localbuf, yasm_section_get_align(sect)); /* alignment */
- YASM_WRITE_16_L(localbuf, xsd->flags); /* flags */
- YASM_WRITE_32_L(localbuf, xsd->scnptr); /* file ptr to data */
- YASM_WRITE_32_L(localbuf, xsd->size); /* section size */
- YASM_WRITE_32_L(localbuf, xsd->relptr); /* file ptr to relocs */
- YASM_WRITE_32_L(localbuf, xsd->nreloc); /* num of relocation entries */
- fwrite(info->buf, 40, 1, info->f);
-
- return 0;
-}
-
-static int
-xdf_objfmt_count_sym(yasm_symrec *sym, /*@null@*/ void *d)
-{
- /*@null@*/ xdf_objfmt_output_info *info = (xdf_objfmt_output_info *)d;
- yasm_sym_vis vis = yasm_symrec_get_visibility(sym);
- assert(info != NULL);
- if (vis & YASM_SYM_COMMON) {
- yasm_error_set(YASM_ERROR_GENERAL,
- N_("XDF object format does not support common variables"));
- yasm_errwarn_propagate(info->errwarns, yasm_symrec_get_decl_line(sym));
- return 0;
- }
- if (info->all_syms ||
- (vis != YASM_SYM_LOCAL && !(vis & YASM_SYM_DLOCAL))) {
- /* Save index in symrec data */
- xdf_symrec_data *sym_data = yasm_xmalloc(sizeof(xdf_symrec_data));
- sym_data->index = info->indx;
- yasm_symrec_add_data(sym, &xdf_symrec_data_cb, sym_data);
-
- info->indx++;
- }
- return 0;
-}
-
-static int
-xdf_objfmt_output_sym(yasm_symrec *sym, /*@null@*/ void *d)
-{
- /*@null@*/ xdf_objfmt_output_info *info = (xdf_objfmt_output_info *)d;
- yasm_sym_vis vis = yasm_symrec_get_visibility(sym);
-
- assert(info != NULL);
-
- if (info->all_syms || vis != YASM_SYM_LOCAL) {
- /*@only@*/ char *name = yasm_symrec_get_global_name(sym, info->object);
- const yasm_expr *equ_val;
- const yasm_intnum *intn;
- size_t len = strlen(name);
- unsigned long value = 0;
- long scnum = -3; /* -3 = debugging symbol */
- /*@dependent@*/ /*@null@*/ yasm_section *sect;
- /*@dependent@*/ /*@null@*/ yasm_bytecode *precbc;
- unsigned long flags = 0;
- unsigned char *localbuf;
-
- if (vis & YASM_SYM_GLOBAL)
- flags = XDF_SYM_GLOBAL;
-
- /* Look at symrec for value/scnum/etc. */
- if (yasm_symrec_get_label(sym, &precbc)) {
- if (precbc)
- sect = yasm_bc_get_section(precbc);
- else
- sect = NULL;
- /* it's a label: get value and offset.
- * If there is not a section, leave as debugging symbol.
- */
- if (sect) {
- /*@dependent@*/ /*@null@*/ xdf_section_data *csectd;
- csectd = yasm_section_get_data(sect, &xdf_section_data_cb);
- if (csectd)
- scnum = csectd->scnum;
- else
- yasm_internal_error(N_("didn't understand section"));
- if (precbc)
- value += yasm_bc_next_offset(precbc);
- }
- } else if ((equ_val = yasm_symrec_get_equ(sym))) {
- yasm_expr *equ_val_copy = yasm_expr_copy(equ_val);
- intn = yasm_expr_get_intnum(&equ_val_copy, 1);
- if (!intn) {
- if (vis & YASM_SYM_GLOBAL) {
- yasm_error_set(YASM_ERROR_NOT_CONSTANT,
- N_("global EQU value not an integer expression"));
- yasm_errwarn_propagate(info->errwarns, equ_val->line);
- }
- } else
- value = yasm_intnum_get_uint(intn);
- yasm_expr_destroy(equ_val_copy);
-
- flags |= XDF_SYM_EQU;
- scnum = -2; /* -2 = absolute symbol */
- } else {
- if (vis & YASM_SYM_EXTERN) {
- flags = XDF_SYM_EXTERN;
- scnum = -1;
- }
- }
-
- localbuf = info->buf;
- YASM_WRITE_32_L(localbuf, scnum); /* section number */
- YASM_WRITE_32_L(localbuf, value); /* value */
- YASM_WRITE_32_L(localbuf, info->strtab_offset);
- info->strtab_offset += (unsigned long)(len+1);
- YASM_WRITE_32_L(localbuf, flags); /* flags */
- fwrite(info->buf, 16, 1, info->f);
- yasm_xfree(name);
- }
- return 0;
-}
-
-static int
-xdf_objfmt_output_str(yasm_symrec *sym, /*@null@*/ void *d)
-{
- /*@null@*/ xdf_objfmt_output_info *info = (xdf_objfmt_output_info *)d;
- yasm_sym_vis vis = yasm_symrec_get_visibility(sym);
-
- assert(info != NULL);
-
- if (info->all_syms || vis != YASM_SYM_LOCAL) {
- /*@only@*/ char *name = yasm_symrec_get_global_name(sym, info->object);
- size_t len = strlen(name);
- fwrite(name, len+1, 1, info->f);
- yasm_xfree(name);
- }
- return 0;
-}
-
-static void
-xdf_objfmt_output(yasm_object *object, FILE *f, int all_syms,
- yasm_errwarns *errwarns)
-{
- yasm_objfmt_xdf *objfmt_xdf = (yasm_objfmt_xdf *)object->objfmt;
- xdf_objfmt_output_info info;
- unsigned char *localbuf;
- unsigned long symtab_count = 0;
-
- info.object = object;
- info.objfmt_xdf = objfmt_xdf;
- info.errwarns = errwarns;
- info.f = f;
- info.buf = yasm_xmalloc(REGULAR_OUTBUF_SIZE);
-
- /* Allocate space for headers by seeking forward */
- if (fseek(f, (long)(16+40*(objfmt_xdf->parse_scnum)), SEEK_SET) < 0) {
- yasm__fatal(N_("could not seek on output file"));
- /*@notreached@*/
- return;
- }
-
- /* Get number of symbols */
- info.indx = 0;
- info.all_syms = 1; /* force all syms into symbol table */
- yasm_symtab_traverse(object->symtab, &info, xdf_objfmt_count_sym);
- symtab_count = info.indx;
-
- /* Get file offset of start of string table */
- info.strtab_offset = 16+40*(objfmt_xdf->parse_scnum)+16*symtab_count;
-
- /* Output symbol table */
- yasm_symtab_traverse(object->symtab, &info, xdf_objfmt_output_sym);
-
- /* Output string table */
- yasm_symtab_traverse(object->symtab, &info, xdf_objfmt_output_str);
-
- /* Section data/relocs */
- if (yasm_object_sections_traverse(object, &info,
- xdf_objfmt_output_section))
- return;
-
- /* Write headers */
- if (fseek(f, 0, SEEK_SET) < 0) {
- yasm__fatal(N_("could not seek on output file"));
- /*@notreached@*/
- return;
- }
-
- localbuf = info.buf;
- YASM_WRITE_32_L(localbuf, XDF_MAGIC); /* magic number */
- YASM_WRITE_32_L(localbuf, objfmt_xdf->parse_scnum); /* number of sects */
- YASM_WRITE_32_L(localbuf, symtab_count); /* number of symtabs */
- /* size of sect headers + symbol table + strings */
- YASM_WRITE_32_L(localbuf, info.strtab_offset-16);
- fwrite(info.buf, 16, 1, f);
-
- yasm_object_sections_traverse(object, &info, xdf_objfmt_output_secthead);
-
- yasm_xfree(info.buf);
-}
-
-static void
-xdf_objfmt_destroy(yasm_objfmt *objfmt)
-{
- yasm_xfree(objfmt);
-}
-
-static void
-xdf_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_xdf *objfmt_xdf = (yasm_objfmt_xdf *)object->objfmt;
- xdf_section_data *data;
- yasm_symrec *sym;
-
- data = yasm_xmalloc(sizeof(xdf_section_data));
- data->scnum = objfmt_xdf->parse_scnum++;
- data->flags = 0;
- data->addr = NULL;
- data->vaddr = NULL;
- data->scnptr = 0;
- data->size = 0;
- data->relptr = 0;
- data->nreloc = 0;
- yasm_section_add_data(sect, &xdf_section_data_cb, data);
-
- sym = yasm_symtab_define_label(object->symtab, sectname,
- yasm_section_bcs_first(sect), 1, line);
- data->sym = sym;
-}
-
-static yasm_section *
-xdf_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;
-}
-
-static int
-xdf_helper_use(void *obj, yasm_valparam *vp, unsigned long line, void *d,
- uintptr_t bits)
-{
- yasm_object *object = (yasm_object *)obj;
- unsigned long *flags = (unsigned long *)d;
- *flags &= ~(XDF_SECT_USE_16|XDF_SECT_USE_32|XDF_SECT_USE_64);
- switch (bits) {
- case 16: *flags |= XDF_SECT_USE_16; break;
- case 32: *flags |= XDF_SECT_USE_32; break;
- case 64: *flags |= XDF_SECT_USE_64; break;
- };
- yasm_arch_set_var(object->arch, "mode_bits", bits);
- return 0;
-}
-
-static /*@observer@*/ /*@null@*/ yasm_section *
-xdf_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;
- int resonly = 0;
- xdf_section_data *xsd;
- unsigned long align = 0;
-
- struct xdf_section_switch_data {
- /*@only@*/ /*@null@*/ yasm_intnum *absaddr;
- /*@only@*/ /*@null@*/ yasm_intnum *vaddr;
- /*@only@*/ /*@null@*/ yasm_intnum *align_intn;
- unsigned long flags;
- } data;
-
- static const yasm_dir_help help[] = {
- { "use16", 0, xdf_helper_use,
- offsetof(struct xdf_section_switch_data, flags), 16 },
- { "use32", 0, xdf_helper_use,
- offsetof(struct xdf_section_switch_data, flags), 32 },
- { "use64", 0, xdf_helper_use,
- offsetof(struct xdf_section_switch_data, flags), 64 },
- { "bss", 0, yasm_dir_helper_flag_or,
- offsetof(struct xdf_section_switch_data, flags), XDF_SECT_BSS },
- { "flat", 0, yasm_dir_helper_flag_or,
- offsetof(struct xdf_section_switch_data, flags), XDF_SECT_FLAT },
- { "absolute", 1, yasm_dir_helper_intn,
- offsetof(struct xdf_section_switch_data, absaddr), 0 },
- { "virtual", 1, yasm_dir_helper_intn,
- offsetof(struct xdf_section_switch_data, vaddr), 0 },
- { "align", 1, yasm_dir_helper_intn,
- offsetof(struct xdf_section_switch_data, align_intn), 0 }
- };
-
- data.absaddr = NULL;
- data.vaddr = NULL;
- data.align_intn = NULL;
- data.flags = 0;
-
- vp = yasm_vps_first(valparams);
- sectname = yasm_vp_string(vp);
- if (!sectname)
- return NULL;
- vp = yasm_vps_next(vp);
-
- 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.absaddr)
- data.flags |= XDF_SECT_ABSOLUTE;
- if (data.align_intn) {
- align = yasm_intnum_get_uint(data.align_intn);
- yasm_intnum_destroy(data.align_intn);
-
- /* 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");
- if (data.vaddr)
- yasm_intnum_destroy(data.vaddr);
- if (data.absaddr)
- yasm_intnum_destroy(data.absaddr);
- return NULL;
- }
-
- /* Check to see if alignment is supported size */
- if (align > 4096) {
- yasm_error_set(YASM_ERROR_VALUE,
- N_("XDF does not support alignments > 4096"));
- if (data.vaddr)
- yasm_intnum_destroy(data.vaddr);
- if (data.absaddr)
- yasm_intnum_destroy(data.absaddr);
- return NULL;
- }
- }
-
- retval = yasm_object_get_general(object, sectname, align, 1, resonly,
- &isnew, line);
-
- xsd = yasm_section_get_data(retval, &xdf_section_data_cb);
-
- if (isnew || yasm_section_is_default(retval)) {
- yasm_section_set_default(retval, 0);
- xsd->flags = data.flags;
- if (data.absaddr) {
- if (xsd->addr)
- yasm_intnum_destroy(xsd->addr);
- xsd->addr = data.absaddr;
- }
- if (data.vaddr) {
- if (xsd->vaddr)
- yasm_intnum_destroy(xsd->vaddr);
- xsd->vaddr = data.vaddr;
- }
- yasm_section_set_align(retval, align, line);
- } else if (flags_override)
- yasm_warn_set(YASM_WARN_GENERAL,
- N_("section flags ignored on section redeclaration"));
- return retval;
-}
-
-static /*@observer@*/ /*@null@*/ yasm_symrec *
-xdf_objfmt_get_special_sym(yasm_object *object, const char *name,
- const char *parser)
-{
- return NULL;
-}
-
-static void
-xdf_section_data_destroy(void *data)
-{
- xdf_section_data *xsd = (xdf_section_data *)data;
- if (xsd->addr)
- yasm_intnum_destroy(xsd->addr);
- if (xsd->vaddr)
- yasm_intnum_destroy(xsd->vaddr);
- yasm_xfree(data);
-}
-
-static void
-xdf_section_data_print(void *data, FILE *f, int indent_level)
-{
- xdf_section_data *xsd = (xdf_section_data *)data;
-
- fprintf(f, "%*ssym=\n", indent_level, "");
- yasm_symrec_print(xsd->sym, f, indent_level+1);
- fprintf(f, "%*sscnum=%ld\n", indent_level, "", xsd->scnum);
- fprintf(f, "%*sflags=0x%x\n", indent_level, "", xsd->flags);
- fprintf(f, "%*saddr=", indent_level, "");
- yasm_intnum_print(xsd->addr, f);
- fprintf(f, "%*svaddr=", indent_level, "");
- yasm_intnum_print(xsd->vaddr, f);
- fprintf(f, "%*sscnptr=0x%lx\n", indent_level, "", xsd->scnptr);
- fprintf(f, "%*ssize=%ld\n", indent_level, "", xsd->size);
- fprintf(f, "%*srelptr=0x%lx\n", indent_level, "", xsd->relptr);
- fprintf(f, "%*snreloc=%ld\n", indent_level, "", xsd->nreloc);
-}
-
-static void
-xdf_symrec_data_destroy(void *data)
-{
- yasm_xfree(data);
-}
-
-static void
-xdf_symrec_data_print(void *data, FILE *f, int indent_level)
-{
- xdf_symrec_data *xsd = (xdf_symrec_data *)data;
-
- fprintf(f, "%*ssymtab index=%lu\n", indent_level, "", xsd->index);
-}
-
-/* Define valid debug formats to use with this object format */
-static const char *xdf_objfmt_dbgfmt_keywords[] = {
- "null",
- NULL
-};
-
-/* Define objfmt structure -- see objfmt.h for details */
-yasm_objfmt_module yasm_xdf_LTX_objfmt = {
- "Extended Dynamic Object",
- "xdf",
- "xdf",
- 32,
- 0,
- xdf_objfmt_dbgfmt_keywords,
- "null",
- NULL, /* no directives */
- NULL, /* no standard macros */
- xdf_objfmt_create,
- xdf_objfmt_output,
- xdf_objfmt_destroy,
- xdf_objfmt_add_default_section,
- xdf_objfmt_init_new_section,
- xdf_objfmt_section_switch,
- xdf_objfmt_get_special_sym
-};
+/*
+ * Extended Dynamic Object format
+ *
+ * Copyright (C) 2004-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>
+
+#include <libyasm.h>
+
+
+#define REGULAR_OUTBUF_SIZE 1024
+
+#define XDF_MAGIC 0x87654322
+
+#define XDF_SYM_EXTERN 1
+#define XDF_SYM_GLOBAL 2
+#define XDF_SYM_EQU 4
+
+typedef struct xdf_reloc {
+ yasm_reloc reloc;
+ /*@null@*/ yasm_symrec *base; /* base symbol (for WRT) */
+ enum {
+ XDF_RELOC_REL = 1, /* relative to segment */
+ XDF_RELOC_WRT = 2, /* relative to symbol */
+ XDF_RELOC_RIP = 4, /* RIP-relative */
+ XDF_RELOC_SEG = 8 /* segment containing symbol */
+ } type; /* type of relocation */
+ enum {
+ XDF_RELOC_8 = 1,
+ XDF_RELOC_16 = 2,
+ XDF_RELOC_32 = 4,
+ XDF_RELOC_64 = 8
+ } size; /* size of relocation */
+ unsigned int shift; /* relocation shift (0,4,8,16,24,32) */
+} xdf_reloc;
+
+typedef struct xdf_section_data {
+ /*@dependent@*/ yasm_symrec *sym; /* symbol created for this section */
+ yasm_intnum *addr; /* starting memory address */
+ yasm_intnum *vaddr; /* starting virtual address */
+ long scnum; /* section number (0=first section) */
+ enum {
+ XDF_SECT_ABSOLUTE = 0x01,
+ XDF_SECT_FLAT = 0x02,
+ XDF_SECT_BSS = 0x04,
+ XDF_SECT_EQU = 0x08,
+ XDF_SECT_USE_16 = 0x10,
+ XDF_SECT_USE_32 = 0x20,
+ XDF_SECT_USE_64 = 0x40
+ } flags; /* section flags */
+ unsigned long scnptr; /* file ptr to raw data */
+ unsigned long size; /* size of raw data (section data) in bytes */
+ unsigned long relptr; /* file ptr to relocation */
+ unsigned long nreloc; /* number of relocation entries >64k -> error */
+} xdf_section_data;
+
+typedef struct xdf_symrec_data {
+ unsigned long index; /* assigned XDF symbol table index */
+} xdf_symrec_data;
+
+typedef struct yasm_objfmt_xdf {
+ yasm_objfmt_base objfmt; /* base structure */
+
+ long parse_scnum; /* sect numbering in parser */
+} yasm_objfmt_xdf;
+
+typedef struct xdf_objfmt_output_info {
+ yasm_object *object;
+ yasm_objfmt_xdf *objfmt_xdf;
+ yasm_errwarns *errwarns;
+ /*@dependent@*/ FILE *f;
+ /*@only@*/ unsigned char *buf;
+ yasm_section *sect;
+ /*@dependent@*/ xdf_section_data *xsd;
+
+ unsigned long indx; /* current symbol index */
+ int all_syms; /* outputting all symbols? */
+ unsigned long strtab_offset; /* current string table offset */
+} xdf_objfmt_output_info;
+
+static void xdf_section_data_destroy(/*@only@*/ void *d);
+static void xdf_section_data_print(void *data, FILE *f, int indent_level);
+
+static const yasm_assoc_data_callback xdf_section_data_cb = {
+ xdf_section_data_destroy,
+ xdf_section_data_print
+};
+
+static void xdf_symrec_data_destroy(/*@only@*/ void *d);
+static void xdf_symrec_data_print(void *data, FILE *f, int indent_level);
+
+static const yasm_assoc_data_callback xdf_symrec_data_cb = {
+ xdf_symrec_data_destroy,
+ xdf_symrec_data_print
+};
+
+yasm_objfmt_module yasm_xdf_LTX_objfmt;
+
+
+static yasm_objfmt *
+xdf_objfmt_create(yasm_object *object)
+{
+ yasm_objfmt_xdf *objfmt_xdf = yasm_xmalloc(sizeof(yasm_objfmt_xdf));
+
+ /* Only support x86 arch */
+ if (yasm__strcasecmp(yasm_arch_keyword(object->arch), "x86") != 0) {
+ yasm_xfree(objfmt_xdf);
+ return NULL;
+ }
+
+ /* Support x86 and amd64 machines of x86 arch */
+ if (yasm__strcasecmp(yasm_arch_get_machine(object->arch), "x86") &&
+ yasm__strcasecmp(yasm_arch_get_machine(object->arch), "amd64")) {
+ yasm_xfree(objfmt_xdf);
+ return NULL;
+ }
+
+ objfmt_xdf->parse_scnum = 0; /* section numbering starts at 0 */
+
+ objfmt_xdf->objfmt.module = &yasm_xdf_LTX_objfmt;
+
+ return (yasm_objfmt *)objfmt_xdf;
+}
+
+static int
+xdf_objfmt_output_value(yasm_value *value, unsigned char *buf,
+ unsigned int destsize, unsigned long offset,
+ yasm_bytecode *bc, int warn, /*@null@*/ void *d)
+{
+ /*@null@*/ xdf_objfmt_output_info *info = (xdf_objfmt_output_info *)d;
+ /*@dependent@*/ /*@null@*/ yasm_intnum *intn;
+ unsigned long intn_minus;
+ int retval;
+ unsigned int valsize = value->size;
+
+ assert(info != NULL);
+
+ if (value->abs)
+ value->abs = yasm_expr_simplify(value->abs, 1);
+
+ /* Try to output constant and PC-relative section-local first.
+ * Note this does NOT output any value with a SEG, WRT, external,
+ * cross-section, or non-PC-relative reference (those are handled below).
+ */
+ switch (yasm_value_output_basic(value, buf, destsize, bc, warn,
+ info->object->arch)) {
+ case -1:
+ return 1;
+ case 0:
+ break;
+ default:
+ return 0;
+ }
+
+ if (value->section_rel) {
+ yasm_error_set(YASM_ERROR_TOO_COMPLEX,
+ N_("xdf: relocation too complex"));
+ return 1;
+ }
+
+ intn_minus = 0;
+ if (value->rel) {
+ xdf_reloc *reloc;
+
+ reloc = yasm_xmalloc(sizeof(xdf_reloc));
+ reloc->reloc.addr = yasm_intnum_create_uint(bc->offset + offset);
+ reloc->reloc.sym = value->rel;
+ reloc->base = NULL;
+ reloc->size = valsize/8;
+ reloc->shift = value->rshift;
+
+ if (value->seg_of)
+ reloc->type = XDF_RELOC_SEG;
+ else if (value->wrt) {
+ reloc->base = value->wrt;
+ reloc->type = XDF_RELOC_WRT;
+ } else if (value->curpos_rel) {
+ reloc->type = XDF_RELOC_RIP;
+ /* Adjust to start of section, so subtract out the bytecode
+ * offset.
+ */
+ intn_minus = bc->offset;
+ } else
+ reloc->type = XDF_RELOC_REL;
+ info->xsd->nreloc++;
+ yasm_section_add_reloc(info->sect, (yasm_reloc *)reloc, yasm_xfree);
+ }
+
+ if (intn_minus > 0) {
+ intn = yasm_intnum_create_uint(intn_minus);
+ yasm_intnum_calc(intn, YASM_EXPR_NEG, NULL);
+ } else
+ intn = yasm_intnum_create_uint(0);
+
+ if (value->abs) {
+ yasm_intnum *intn2 = yasm_expr_get_intnum(&value->abs, 0);
+ if (!intn2) {
+ yasm_error_set(YASM_ERROR_TOO_COMPLEX,
+ N_("xdf: relocation too complex"));
+ yasm_intnum_destroy(intn);
+ return 1;
+ }
+ yasm_intnum_calc(intn, YASM_EXPR_ADD, intn2);
+ }
+
+ retval = yasm_arch_intnum_tobytes(info->object->arch, intn, buf, destsize,
+ valsize, 0, bc, warn);
+ yasm_intnum_destroy(intn);
+ return retval;
+}
+
+static int
+xdf_objfmt_output_bytecode(yasm_bytecode *bc, /*@null@*/ void *d)
+{
+ /*@null@*/ xdf_objfmt_output_info *info = (xdf_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,
+ xdf_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;
+ }
+
+ info->xsd->size += size;
+
+ /* 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: 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;
+}
+
+static int
+xdf_objfmt_output_section(yasm_section *sect, /*@null@*/ void *d)
+{
+ /*@null@*/ xdf_objfmt_output_info *info = (xdf_objfmt_output_info *)d;
+ /*@dependent@*/ /*@null@*/ xdf_section_data *xsd;
+ long pos;
+ xdf_reloc *reloc;
+
+ assert(info != NULL);
+ xsd = yasm_section_get_data(sect, &xdf_section_data_cb);
+ assert(xsd != NULL);
+
+ if (xsd->flags & XDF_SECT_BSS) {
+ /* Don't output BSS sections.
+ * TODO: Check for non-reserve bytecodes?
+ */
+ pos = 0; /* position = 0 because it's not in the file */
+ xsd->size = yasm_bc_next_offset(yasm_section_bcs_last(sect));
+ } else {
+ pos = ftell(info->f);
+ if (pos == -1) {
+ yasm__fatal(N_("could not get file position on output file"));
+ /*@notreached@*/
+ return 1;
+ }
+
+ info->sect = sect;
+ info->xsd = xsd;
+ yasm_section_bcs_traverse(sect, info->errwarns, info,
+ xdf_objfmt_output_bytecode);
+
+ /* Sanity check final section size */
+ if (xsd->size != yasm_bc_next_offset(yasm_section_bcs_last(sect)))
+ yasm_internal_error(
+ N_("xdf: section computed size did not match actual size"));
+ }
+
+ /* Empty? Go on to next section */
+ if (xsd->size == 0)
+ return 0;
+
+ xsd->scnptr = (unsigned long)pos;
+
+ /* No relocations to output? Go on to next section */
+ if (xsd->nreloc == 0)
+ return 0;
+
+ pos = ftell(info->f);
+ if (pos == -1) {
+ yasm__fatal(N_("could not get file position on output file"));
+ /*@notreached@*/
+ return 1;
+ }
+ xsd->relptr = (unsigned long)pos;
+
+ reloc = (xdf_reloc *)yasm_section_relocs_first(sect);
+ while (reloc) {
+ unsigned char *localbuf = info->buf;
+ /*@null@*/ xdf_symrec_data *xsymd;
+
+ xsymd = yasm_symrec_get_data(reloc->reloc.sym, &xdf_symrec_data_cb);
+ if (!xsymd)
+ yasm_internal_error(
+ N_("xdf: no symbol data for relocated symbol"));
+
+ yasm_intnum_get_sized(reloc->reloc.addr, localbuf, 4, 32, 0, 0, 0);
+ localbuf += 4; /* address of relocation */
+ YASM_WRITE_32_L(localbuf, xsymd->index); /* relocated symbol */
+ if (reloc->base) {
+ xsymd = yasm_symrec_get_data(reloc->base, &xdf_symrec_data_cb);
+ if (!xsymd)
+ yasm_internal_error(
+ N_("xdf: no symbol data for relocated base symbol"));
+ YASM_WRITE_32_L(localbuf, xsymd->index); /* base symbol */
+ } else {
+ if (reloc->type == XDF_RELOC_WRT)
+ yasm_internal_error(
+ N_("xdf: no base symbol for WRT relocation"));
+ YASM_WRITE_32_L(localbuf, 0); /* no base symbol */
+ }
+ YASM_WRITE_8(localbuf, reloc->type); /* type of relocation */
+ YASM_WRITE_8(localbuf, reloc->size); /* size of relocation */
+ YASM_WRITE_8(localbuf, reloc->shift); /* relocation shift */
+ YASM_WRITE_8(localbuf, 0); /* flags */
+ fwrite(info->buf, 16, 1, info->f);
+
+ reloc = (xdf_reloc *)yasm_section_reloc_next((yasm_reloc *)reloc);
+ }
+
+ return 0;
+}
+
+static int
+xdf_objfmt_output_secthead(yasm_section *sect, /*@null@*/ void *d)
+{
+ /*@null@*/ xdf_objfmt_output_info *info = (xdf_objfmt_output_info *)d;
+ /*@dependent@*/ /*@null@*/ xdf_section_data *xsd;
+ /*@null@*/ xdf_symrec_data *xsymd;
+ unsigned char *localbuf;
+
+ assert(info != NULL);
+ xsd = yasm_section_get_data(sect, &xdf_section_data_cb);
+ assert(xsd != NULL);
+
+ localbuf = info->buf;
+ xsymd = yasm_symrec_get_data(xsd->sym, &xdf_symrec_data_cb);
+ assert(xsymd != NULL);
+
+ YASM_WRITE_32_L(localbuf, xsymd->index); /* section name symbol */
+ if (xsd->addr) {
+ yasm_intnum_get_sized(xsd->addr, localbuf, 8, 64, 0, 0, 0);
+ localbuf += 8; /* physical address */
+ } else {
+ YASM_WRITE_32_L(localbuf, 0);
+ YASM_WRITE_32_L(localbuf, 0);
+ }
+ if (xsd->vaddr) {
+ yasm_intnum_get_sized(xsd->vaddr, localbuf, 8, 64, 0, 0, 0);
+ localbuf += 8; /* virtual address */
+ } else if (xsd->addr) {
+ yasm_intnum_get_sized(xsd->addr, localbuf, 8, 64, 0, 0, 0);
+ localbuf += 8; /* VA=PA */
+ } else {
+ YASM_WRITE_32_L(localbuf, 0);
+ YASM_WRITE_32_L(localbuf, 0);
+ }
+ YASM_WRITE_16_L(localbuf, yasm_section_get_align(sect)); /* alignment */
+ YASM_WRITE_16_L(localbuf, xsd->flags); /* flags */
+ YASM_WRITE_32_L(localbuf, xsd->scnptr); /* file ptr to data */
+ YASM_WRITE_32_L(localbuf, xsd->size); /* section size */
+ YASM_WRITE_32_L(localbuf, xsd->relptr); /* file ptr to relocs */
+ YASM_WRITE_32_L(localbuf, xsd->nreloc); /* num of relocation entries */
+ fwrite(info->buf, 40, 1, info->f);
+
+ return 0;
+}
+
+static int
+xdf_objfmt_count_sym(yasm_symrec *sym, /*@null@*/ void *d)
+{
+ /*@null@*/ xdf_objfmt_output_info *info = (xdf_objfmt_output_info *)d;
+ yasm_sym_vis vis = yasm_symrec_get_visibility(sym);
+ assert(info != NULL);
+ if (vis & YASM_SYM_COMMON) {
+ yasm_error_set(YASM_ERROR_GENERAL,
+ N_("XDF object format does not support common variables"));
+ yasm_errwarn_propagate(info->errwarns, yasm_symrec_get_decl_line(sym));
+ return 0;
+ }
+ if (info->all_syms ||
+ (vis != YASM_SYM_LOCAL && !(vis & YASM_SYM_DLOCAL))) {
+ /* Save index in symrec data */
+ xdf_symrec_data *sym_data = yasm_xmalloc(sizeof(xdf_symrec_data));
+ sym_data->index = info->indx;
+ yasm_symrec_add_data(sym, &xdf_symrec_data_cb, sym_data);
+
+ info->indx++;
+ }
+ return 0;
+}
+
+static int
+xdf_objfmt_output_sym(yasm_symrec *sym, /*@null@*/ void *d)
+{
+ /*@null@*/ xdf_objfmt_output_info *info = (xdf_objfmt_output_info *)d;
+ yasm_sym_vis vis = yasm_symrec_get_visibility(sym);
+
+ assert(info != NULL);
+
+ if (info->all_syms || vis != YASM_SYM_LOCAL) {
+ /*@only@*/ char *name = yasm_symrec_get_global_name(sym, info->object);
+ const yasm_expr *equ_val;
+ const yasm_intnum *intn;
+ size_t len = strlen(name);
+ unsigned long value = 0;
+ long scnum = -3; /* -3 = debugging symbol */
+ /*@dependent@*/ /*@null@*/ yasm_section *sect;
+ /*@dependent@*/ /*@null@*/ yasm_bytecode *precbc;
+ unsigned long flags = 0;
+ unsigned char *localbuf;
+
+ if (vis & YASM_SYM_GLOBAL)
+ flags = XDF_SYM_GLOBAL;
+
+ /* Look at symrec for value/scnum/etc. */
+ if (yasm_symrec_get_label(sym, &precbc)) {
+ if (precbc)
+ sect = yasm_bc_get_section(precbc);
+ else
+ sect = NULL;
+ /* it's a label: get value and offset.
+ * If there is not a section, leave as debugging symbol.
+ */
+ if (sect) {
+ /*@dependent@*/ /*@null@*/ xdf_section_data *csectd;
+ csectd = yasm_section_get_data(sect, &xdf_section_data_cb);
+ if (csectd)
+ scnum = csectd->scnum;
+ else
+ yasm_internal_error(N_("didn't understand section"));
+ if (precbc)
+ value += yasm_bc_next_offset(precbc);
+ }
+ } else if ((equ_val = yasm_symrec_get_equ(sym))) {
+ yasm_expr *equ_val_copy = yasm_expr_copy(equ_val);
+ intn = yasm_expr_get_intnum(&equ_val_copy, 1);
+ if (!intn) {
+ if (vis & YASM_SYM_GLOBAL) {
+ yasm_error_set(YASM_ERROR_NOT_CONSTANT,
+ N_("global EQU value not an integer expression"));
+ yasm_errwarn_propagate(info->errwarns, equ_val->line);
+ }
+ } else
+ value = yasm_intnum_get_uint(intn);
+ yasm_expr_destroy(equ_val_copy);
+
+ flags |= XDF_SYM_EQU;
+ scnum = -2; /* -2 = absolute symbol */
+ } else {
+ if (vis & YASM_SYM_EXTERN) {
+ flags = XDF_SYM_EXTERN;
+ scnum = -1;
+ }
+ }
+
+ localbuf = info->buf;
+ YASM_WRITE_32_L(localbuf, scnum); /* section number */
+ YASM_WRITE_32_L(localbuf, value); /* value */
+ YASM_WRITE_32_L(localbuf, info->strtab_offset);
+ info->strtab_offset += (unsigned long)(len+1);
+ YASM_WRITE_32_L(localbuf, flags); /* flags */
+ fwrite(info->buf, 16, 1, info->f);
+ yasm_xfree(name);
+ }
+ return 0;
+}
+
+static int
+xdf_objfmt_output_str(yasm_symrec *sym, /*@null@*/ void *d)
+{
+ /*@null@*/ xdf_objfmt_output_info *info = (xdf_objfmt_output_info *)d;
+ yasm_sym_vis vis = yasm_symrec_get_visibility(sym);
+
+ assert(info != NULL);
+
+ if (info->all_syms || vis != YASM_SYM_LOCAL) {
+ /*@only@*/ char *name = yasm_symrec_get_global_name(sym, info->object);
+ size_t len = strlen(name);
+ fwrite(name, len+1, 1, info->f);
+ yasm_xfree(name);
+ }
+ return 0;
+}
+
+static void
+xdf_objfmt_output(yasm_object *object, FILE *f, int all_syms,
+ yasm_errwarns *errwarns)
+{
+ yasm_objfmt_xdf *objfmt_xdf = (yasm_objfmt_xdf *)object->objfmt;
+ xdf_objfmt_output_info info;
+ unsigned char *localbuf;
+ unsigned long symtab_count = 0;
+
+ info.object = object;
+ info.objfmt_xdf = objfmt_xdf;
+ info.errwarns = errwarns;
+ info.f = f;
+ info.buf = yasm_xmalloc(REGULAR_OUTBUF_SIZE);
+
+ /* Allocate space for headers by seeking forward */
+ if (fseek(f, (long)(16+40*(objfmt_xdf->parse_scnum)), SEEK_SET) < 0) {
+ yasm__fatal(N_("could not seek on output file"));
+ /*@notreached@*/
+ return;
+ }
+
+ /* Get number of symbols */
+ info.indx = 0;
+ info.all_syms = 1; /* force all syms into symbol table */
+ yasm_symtab_traverse(object->symtab, &info, xdf_objfmt_count_sym);
+ symtab_count = info.indx;
+
+ /* Get file offset of start of string table */
+ info.strtab_offset = 16+40*(objfmt_xdf->parse_scnum)+16*symtab_count;
+
+ /* Output symbol table */
+ yasm_symtab_traverse(object->symtab, &info, xdf_objfmt_output_sym);
+
+ /* Output string table */
+ yasm_symtab_traverse(object->symtab, &info, xdf_objfmt_output_str);
+
+ /* Section data/relocs */
+ if (yasm_object_sections_traverse(object, &info,
+ xdf_objfmt_output_section))
+ return;
+
+ /* Write headers */
+ if (fseek(f, 0, SEEK_SET) < 0) {
+ yasm__fatal(N_("could not seek on output file"));
+ /*@notreached@*/
+ return;
+ }
+
+ localbuf = info.buf;
+ YASM_WRITE_32_L(localbuf, XDF_MAGIC); /* magic number */
+ YASM_WRITE_32_L(localbuf, objfmt_xdf->parse_scnum); /* number of sects */
+ YASM_WRITE_32_L(localbuf, symtab_count); /* number of symtabs */
+ /* size of sect headers + symbol table + strings */
+ YASM_WRITE_32_L(localbuf, info.strtab_offset-16);
+ fwrite(info.buf, 16, 1, f);
+
+ yasm_object_sections_traverse(object, &info, xdf_objfmt_output_secthead);
+
+ yasm_xfree(info.buf);
+}
+
+static void
+xdf_objfmt_destroy(yasm_objfmt *objfmt)
+{
+ yasm_xfree(objfmt);
+}
+
+static void
+xdf_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_xdf *objfmt_xdf = (yasm_objfmt_xdf *)object->objfmt;
+ xdf_section_data *data;
+ yasm_symrec *sym;
+
+ data = yasm_xmalloc(sizeof(xdf_section_data));
+ data->scnum = objfmt_xdf->parse_scnum++;
+ data->flags = 0;
+ data->addr = NULL;
+ data->vaddr = NULL;
+ data->scnptr = 0;
+ data->size = 0;
+ data->relptr = 0;
+ data->nreloc = 0;
+ yasm_section_add_data(sect, &xdf_section_data_cb, data);
+
+ sym = yasm_symtab_define_label(object->symtab, sectname,
+ yasm_section_bcs_first(sect), 1, line);
+ data->sym = sym;
+}
+
+static yasm_section *
+xdf_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;
+}
+
+static int
+xdf_helper_use(void *obj, yasm_valparam *vp, unsigned long line, void *d,
+ uintptr_t bits)
+{
+ yasm_object *object = (yasm_object *)obj;
+ unsigned long *flags = (unsigned long *)d;
+ *flags &= ~(XDF_SECT_USE_16|XDF_SECT_USE_32|XDF_SECT_USE_64);
+ switch (bits) {
+ case 16: *flags |= XDF_SECT_USE_16; break;
+ case 32: *flags |= XDF_SECT_USE_32; break;
+ case 64: *flags |= XDF_SECT_USE_64; break;
+ };
+ yasm_arch_set_var(object->arch, "mode_bits", bits);
+ return 0;
+}
+
+static /*@observer@*/ /*@null@*/ yasm_section *
+xdf_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;
+ int resonly = 0;
+ xdf_section_data *xsd;
+ unsigned long align = 0;
+
+ struct xdf_section_switch_data {
+ /*@only@*/ /*@null@*/ yasm_intnum *absaddr;
+ /*@only@*/ /*@null@*/ yasm_intnum *vaddr;
+ /*@only@*/ /*@null@*/ yasm_intnum *align_intn;
+ unsigned long flags;
+ } data;
+
+ static const yasm_dir_help help[] = {
+ { "use16", 0, xdf_helper_use,
+ offsetof(struct xdf_section_switch_data, flags), 16 },
+ { "use32", 0, xdf_helper_use,
+ offsetof(struct xdf_section_switch_data, flags), 32 },
+ { "use64", 0, xdf_helper_use,
+ offsetof(struct xdf_section_switch_data, flags), 64 },
+ { "bss", 0, yasm_dir_helper_flag_or,
+ offsetof(struct xdf_section_switch_data, flags), XDF_SECT_BSS },
+ { "flat", 0, yasm_dir_helper_flag_or,
+ offsetof(struct xdf_section_switch_data, flags), XDF_SECT_FLAT },
+ { "absolute", 1, yasm_dir_helper_intn,
+ offsetof(struct xdf_section_switch_data, absaddr), 0 },
+ { "virtual", 1, yasm_dir_helper_intn,
+ offsetof(struct xdf_section_switch_data, vaddr), 0 },
+ { "align", 1, yasm_dir_helper_intn,
+ offsetof(struct xdf_section_switch_data, align_intn), 0 }
+ };
+
+ data.absaddr = NULL;
+ data.vaddr = NULL;
+ data.align_intn = NULL;
+ data.flags = 0;
+
+ vp = yasm_vps_first(valparams);
+ sectname = yasm_vp_string(vp);
+ if (!sectname)
+ return NULL;
+ vp = yasm_vps_next(vp);
+
+ 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.absaddr)
+ data.flags |= XDF_SECT_ABSOLUTE;
+ if (data.align_intn) {
+ align = yasm_intnum_get_uint(data.align_intn);
+ yasm_intnum_destroy(data.align_intn);
+
+ /* 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");
+ if (data.vaddr)
+ yasm_intnum_destroy(data.vaddr);
+ if (data.absaddr)
+ yasm_intnum_destroy(data.absaddr);
+ return NULL;
+ }
+
+ /* Check to see if alignment is supported size */
+ if (align > 4096) {
+ yasm_error_set(YASM_ERROR_VALUE,
+ N_("XDF does not support alignments > 4096"));
+ if (data.vaddr)
+ yasm_intnum_destroy(data.vaddr);
+ if (data.absaddr)
+ yasm_intnum_destroy(data.absaddr);
+ return NULL;
+ }
+ }
+
+ retval = yasm_object_get_general(object, sectname, align, 1, resonly,
+ &isnew, line);
+
+ xsd = yasm_section_get_data(retval, &xdf_section_data_cb);
+
+ if (isnew || yasm_section_is_default(retval)) {
+ yasm_section_set_default(retval, 0);
+ xsd->flags = data.flags;
+ if (data.absaddr) {
+ if (xsd->addr)
+ yasm_intnum_destroy(xsd->addr);
+ xsd->addr = data.absaddr;
+ }
+ if (data.vaddr) {
+ if (xsd->vaddr)
+ yasm_intnum_destroy(xsd->vaddr);
+ xsd->vaddr = data.vaddr;
+ }
+ yasm_section_set_align(retval, align, line);
+ } else if (flags_override)
+ yasm_warn_set(YASM_WARN_GENERAL,
+ N_("section flags ignored on section redeclaration"));
+ return retval;
+}
+
+static /*@observer@*/ /*@null@*/ yasm_symrec *
+xdf_objfmt_get_special_sym(yasm_object *object, const char *name,
+ const char *parser)
+{
+ return NULL;
+}
+
+static void
+xdf_section_data_destroy(void *data)
+{
+ xdf_section_data *xsd = (xdf_section_data *)data;
+ if (xsd->addr)
+ yasm_intnum_destroy(xsd->addr);
+ if (xsd->vaddr)
+ yasm_intnum_destroy(xsd->vaddr);
+ yasm_xfree(data);
+}
+
+static void
+xdf_section_data_print(void *data, FILE *f, int indent_level)
+{
+ xdf_section_data *xsd = (xdf_section_data *)data;
+
+ fprintf(f, "%*ssym=\n", indent_level, "");
+ yasm_symrec_print(xsd->sym, f, indent_level+1);
+ fprintf(f, "%*sscnum=%ld\n", indent_level, "", xsd->scnum);
+ fprintf(f, "%*sflags=0x%x\n", indent_level, "", xsd->flags);
+ fprintf(f, "%*saddr=", indent_level, "");
+ yasm_intnum_print(xsd->addr, f);
+ fprintf(f, "%*svaddr=", indent_level, "");
+ yasm_intnum_print(xsd->vaddr, f);
+ fprintf(f, "%*sscnptr=0x%lx\n", indent_level, "", xsd->scnptr);
+ fprintf(f, "%*ssize=%ld\n", indent_level, "", xsd->size);
+ fprintf(f, "%*srelptr=0x%lx\n", indent_level, "", xsd->relptr);
+ fprintf(f, "%*snreloc=%ld\n", indent_level, "", xsd->nreloc);
+}
+
+static void
+xdf_symrec_data_destroy(void *data)
+{
+ yasm_xfree(data);
+}
+
+static void
+xdf_symrec_data_print(void *data, FILE *f, int indent_level)
+{
+ xdf_symrec_data *xsd = (xdf_symrec_data *)data;
+
+ fprintf(f, "%*ssymtab index=%lu\n", indent_level, "", xsd->index);
+}
+
+/* Define valid debug formats to use with this object format */
+static const char *xdf_objfmt_dbgfmt_keywords[] = {
+ "null",
+ NULL
+};
+
+/* Define objfmt structure -- see objfmt.h for details */
+yasm_objfmt_module yasm_xdf_LTX_objfmt = {
+ "Extended Dynamic Object",
+ "xdf",
+ "xdf",
+ 32,
+ 0,
+ xdf_objfmt_dbgfmt_keywords,
+ "null",
+ NULL, /* no directives */
+ NULL, /* no standard macros */
+ xdf_objfmt_create,
+ xdf_objfmt_output,
+ xdf_objfmt_destroy,
+ xdf_objfmt_add_default_section,
+ xdf_objfmt_init_new_section,
+ xdf_objfmt_section_switch,
+ xdf_objfmt_get_special_sym
+};