Home | History | Annotate | Download | only in xdf
      1 /*
      2  * Extended Dynamic Object format
      3  *
      4  *  Copyright (C) 2004-2007  Peter Johnson
      5  *
      6  * Redistribution and use in source and binary forms, with or without
      7  * modification, are permitted provided that the following conditions
      8  * are met:
      9  * 1. Redistributions of source code must retain the above copyright
     10  *    notice, this list of conditions and the following disclaimer.
     11  * 2. Redistributions in binary form must reproduce the above copyright
     12  *    notice, this list of conditions and the following disclaimer in the
     13  *    documentation and/or other materials provided with the distribution.
     14  *
     15  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND OTHER CONTRIBUTORS ``AS IS''
     16  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
     17  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
     18  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR OTHER CONTRIBUTORS BE
     19  * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
     20  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
     21  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
     22  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
     23  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
     24  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
     25  * POSSIBILITY OF SUCH DAMAGE.
     26  */
     27 #include <util.h>
     28 
     29 #include <libyasm.h>
     30 
     31 
     32 #define REGULAR_OUTBUF_SIZE     1024
     33 
     34 #define XDF_MAGIC       0x87654322
     35 
     36 #define XDF_SYM_EXTERN  1
     37 #define XDF_SYM_GLOBAL  2
     38 #define XDF_SYM_EQU     4
     39 
     40 typedef struct xdf_reloc {
     41     yasm_reloc reloc;
     42     /*@null@*/ yasm_symrec *base;   /* base symbol (for WRT) */
     43     enum {
     44         XDF_RELOC_REL = 1,          /* relative to segment */
     45         XDF_RELOC_WRT = 2,          /* relative to symbol */
     46         XDF_RELOC_RIP = 4,          /* RIP-relative */
     47         XDF_RELOC_SEG = 8           /* segment containing symbol */
     48     } type;                         /* type of relocation */
     49     enum {
     50         XDF_RELOC_8  = 1,
     51         XDF_RELOC_16 = 2,
     52         XDF_RELOC_32 = 4,
     53         XDF_RELOC_64 = 8
     54     } size;                         /* size of relocation */
     55     unsigned int shift;             /* relocation shift (0,4,8,16,24,32) */
     56 } xdf_reloc;
     57 
     58 typedef struct xdf_section_data {
     59     /*@dependent@*/ yasm_symrec *sym;   /* symbol created for this section */
     60     yasm_intnum *addr;      /* starting memory address */
     61     yasm_intnum *vaddr;     /* starting virtual address */
     62     long scnum;             /* section number (0=first section) */
     63     enum {
     64         XDF_SECT_ABSOLUTE = 0x01,
     65         XDF_SECT_FLAT = 0x02,
     66         XDF_SECT_BSS = 0x04,
     67         XDF_SECT_EQU = 0x08,
     68         XDF_SECT_USE_16 = 0x10,
     69         XDF_SECT_USE_32 = 0x20,
     70         XDF_SECT_USE_64 = 0x40
     71     } flags;                /* section flags */
     72     unsigned long scnptr;   /* file ptr to raw data */
     73     unsigned long size;     /* size of raw data (section data) in bytes */
     74     unsigned long relptr;   /* file ptr to relocation */
     75     unsigned long nreloc;   /* number of relocation entries >64k -> error */
     76 } xdf_section_data;
     77 
     78 typedef struct xdf_symrec_data {
     79     unsigned long index;                /* assigned XDF symbol table index */
     80 } xdf_symrec_data;
     81 
     82 typedef struct yasm_objfmt_xdf {
     83     yasm_objfmt_base objfmt;                /* base structure */
     84 
     85     long parse_scnum;               /* sect numbering in parser */
     86 } yasm_objfmt_xdf;
     87 
     88 typedef struct xdf_objfmt_output_info {
     89     yasm_object *object;
     90     yasm_objfmt_xdf *objfmt_xdf;
     91     yasm_errwarns *errwarns;
     92     /*@dependent@*/ FILE *f;
     93     /*@only@*/ unsigned char *buf;
     94     yasm_section *sect;
     95     /*@dependent@*/ xdf_section_data *xsd;
     96 
     97     unsigned long indx;             /* current symbol index */
     98     int all_syms;                   /* outputting all symbols? */
     99     unsigned long strtab_offset;    /* current string table offset */
    100 } xdf_objfmt_output_info;
    101 
    102 static void xdf_section_data_destroy(/*@only@*/ void *d);
    103 static void xdf_section_data_print(void *data, FILE *f, int indent_level);
    104 
    105 static const yasm_assoc_data_callback xdf_section_data_cb = {
    106     xdf_section_data_destroy,
    107     xdf_section_data_print
    108 };
    109 
    110 static void xdf_symrec_data_destroy(/*@only@*/ void *d);
    111 static void xdf_symrec_data_print(void *data, FILE *f, int indent_level);
    112 
    113 static const yasm_assoc_data_callback xdf_symrec_data_cb = {
    114     xdf_symrec_data_destroy,
    115     xdf_symrec_data_print
    116 };
    117 
    118 yasm_objfmt_module yasm_xdf_LTX_objfmt;
    119 
    120 
    121 static yasm_objfmt *
    122 xdf_objfmt_create(yasm_object *object)
    123 {
    124     yasm_objfmt_xdf *objfmt_xdf = yasm_xmalloc(sizeof(yasm_objfmt_xdf));
    125 
    126     /* Only support x86 arch */
    127     if (yasm__strcasecmp(yasm_arch_keyword(object->arch), "x86") != 0) {
    128         yasm_xfree(objfmt_xdf);
    129         return NULL;
    130     }
    131 
    132     /* Support x86 and amd64 machines of x86 arch */
    133     if (yasm__strcasecmp(yasm_arch_get_machine(object->arch), "x86") &&
    134         yasm__strcasecmp(yasm_arch_get_machine(object->arch), "amd64")) {
    135         yasm_xfree(objfmt_xdf);
    136         return NULL;
    137     }
    138 
    139     objfmt_xdf->parse_scnum = 0;    /* section numbering starts at 0 */
    140 
    141     objfmt_xdf->objfmt.module = &yasm_xdf_LTX_objfmt;
    142 
    143     return (yasm_objfmt *)objfmt_xdf;
    144 }
    145 
    146 static int
    147 xdf_objfmt_output_value(yasm_value *value, unsigned char *buf,
    148                         unsigned int destsize, unsigned long offset,
    149                         yasm_bytecode *bc, int warn, /*@null@*/ void *d)
    150 {
    151     /*@null@*/ xdf_objfmt_output_info *info = (xdf_objfmt_output_info *)d;
    152     yasm_objfmt_xdf *objfmt_xdf;
    153     /*@dependent@*/ /*@null@*/ yasm_intnum *intn;
    154     unsigned long intn_minus;
    155     int retval;
    156     unsigned int valsize = value->size;
    157 
    158     assert(info != NULL);
    159     objfmt_xdf = info->objfmt_xdf;
    160 
    161     if (value->abs)
    162         value->abs = yasm_expr_simplify(value->abs, 1);
    163 
    164     /* Try to output constant and PC-relative section-local first.
    165      * Note this does NOT output any value with a SEG, WRT, external,
    166      * cross-section, or non-PC-relative reference (those are handled below).
    167      */
    168     switch (yasm_value_output_basic(value, buf, destsize, bc, warn,
    169                                     info->object->arch)) {
    170         case -1:
    171             return 1;
    172         case 0:
    173             break;
    174         default:
    175             return 0;
    176     }
    177 
    178     if (value->section_rel) {
    179         yasm_error_set(YASM_ERROR_TOO_COMPLEX,
    180                        N_("xdf: relocation too complex"));
    181         return 1;
    182     }
    183 
    184     intn_minus = 0;
    185     if (value->rel) {
    186         xdf_reloc *reloc;
    187 
    188         reloc = yasm_xmalloc(sizeof(xdf_reloc));
    189         reloc->reloc.addr = yasm_intnum_create_uint(bc->offset + offset);
    190         reloc->reloc.sym = value->rel;
    191         reloc->base = NULL;
    192         reloc->size = valsize/8;
    193         reloc->shift = value->rshift;
    194 
    195         if (value->seg_of)
    196             reloc->type = XDF_RELOC_SEG;
    197         else if (value->wrt) {
    198             reloc->base = value->wrt;
    199             reloc->type = XDF_RELOC_WRT;
    200         } else if (value->curpos_rel) {
    201             reloc->type = XDF_RELOC_RIP;
    202             /* Adjust to start of section, so subtract out the bytecode
    203              * offset.
    204              */
    205             intn_minus = bc->offset;
    206         } else
    207             reloc->type = XDF_RELOC_REL;
    208         info->xsd->nreloc++;
    209         yasm_section_add_reloc(info->sect, (yasm_reloc *)reloc, yasm_xfree);
    210     }
    211 
    212     if (intn_minus > 0) {
    213         intn = yasm_intnum_create_uint(intn_minus);
    214         yasm_intnum_calc(intn, YASM_EXPR_NEG, NULL);
    215     } else
    216         intn = yasm_intnum_create_uint(0);
    217 
    218     if (value->abs) {
    219         yasm_intnum *intn2 = yasm_expr_get_intnum(&value->abs, 0);
    220         if (!intn2) {
    221             yasm_error_set(YASM_ERROR_TOO_COMPLEX,
    222                            N_("xdf: relocation too complex"));
    223             yasm_intnum_destroy(intn);
    224             return 1;
    225         }
    226         yasm_intnum_calc(intn, YASM_EXPR_ADD, intn2);
    227     }
    228 
    229     retval = yasm_arch_intnum_tobytes(info->object->arch, intn, buf, destsize,
    230                                       valsize, 0, bc, warn);
    231     yasm_intnum_destroy(intn);
    232     return retval;
    233 }
    234 
    235 static int
    236 xdf_objfmt_output_bytecode(yasm_bytecode *bc, /*@null@*/ void *d)
    237 {
    238     /*@null@*/ xdf_objfmt_output_info *info = (xdf_objfmt_output_info *)d;
    239     /*@null@*/ /*@only@*/ unsigned char *bigbuf;
    240     unsigned long size = REGULAR_OUTBUF_SIZE;
    241     int gap;
    242 
    243     assert(info != NULL);
    244 
    245     bigbuf = yasm_bc_tobytes(bc, info->buf, &size, &gap, info,
    246                              xdf_objfmt_output_value, NULL);
    247 
    248     /* Don't bother doing anything else if size ended up being 0. */
    249     if (size == 0) {
    250         if (bigbuf)
    251             yasm_xfree(bigbuf);
    252         return 0;
    253     }
    254 
    255     info->xsd->size += size;
    256 
    257     /* Warn that gaps are converted to 0 and write out the 0's. */
    258     if (gap) {
    259         unsigned long left;
    260         yasm_warn_set(YASM_WARN_UNINIT_CONTENTS,
    261                       N_("uninitialized space: zeroing"));
    262         /* Write out in chunks */
    263         memset(info->buf, 0, REGULAR_OUTBUF_SIZE);
    264         left = size;
    265         while (left > REGULAR_OUTBUF_SIZE) {
    266             fwrite(info->buf, REGULAR_OUTBUF_SIZE, 1, info->f);
    267             left -= REGULAR_OUTBUF_SIZE;
    268         }
    269         fwrite(info->buf, left, 1, info->f);
    270     } else {
    271         /* Output buf (or bigbuf if non-NULL) to file */
    272         fwrite(bigbuf ? bigbuf : info->buf, (size_t)size, 1, info->f);
    273     }
    274 
    275     /* If bigbuf was allocated, free it */
    276     if (bigbuf)
    277         yasm_xfree(bigbuf);
    278 
    279     return 0;
    280 }
    281 
    282 static int
    283 xdf_objfmt_output_section(yasm_section *sect, /*@null@*/ void *d)
    284 {
    285     /*@null@*/ xdf_objfmt_output_info *info = (xdf_objfmt_output_info *)d;
    286     /*@dependent@*/ /*@null@*/ xdf_section_data *xsd;
    287     long pos;
    288     xdf_reloc *reloc;
    289 
    290     assert(info != NULL);
    291     xsd = yasm_section_get_data(sect, &xdf_section_data_cb);
    292     assert(xsd != NULL);
    293 
    294     if (xsd->flags & XDF_SECT_BSS) {
    295         /* Don't output BSS sections.
    296          * TODO: Check for non-reserve bytecodes?
    297          */
    298         pos = 0;    /* position = 0 because it's not in the file */
    299         xsd->size = yasm_bc_next_offset(yasm_section_bcs_last(sect));
    300     } else {
    301         pos = ftell(info->f);
    302         if (pos == -1) {
    303             yasm__fatal(N_("could not get file position on output file"));
    304             /*@notreached@*/
    305             return 1;
    306         }
    307 
    308         info->sect = sect;
    309         info->xsd = xsd;
    310         yasm_section_bcs_traverse(sect, info->errwarns, info,
    311                                   xdf_objfmt_output_bytecode);
    312 
    313         /* Sanity check final section size */
    314         if (xsd->size != yasm_bc_next_offset(yasm_section_bcs_last(sect)))
    315             yasm_internal_error(
    316                 N_("xdf: section computed size did not match actual size"));
    317     }
    318 
    319     /* Empty?  Go on to next section */
    320     if (xsd->size == 0)
    321         return 0;
    322 
    323     xsd->scnptr = (unsigned long)pos;
    324 
    325     /* No relocations to output?  Go on to next section */
    326     if (xsd->nreloc == 0)
    327         return 0;
    328 
    329     pos = ftell(info->f);
    330     if (pos == -1) {
    331         yasm__fatal(N_("could not get file position on output file"));
    332         /*@notreached@*/
    333         return 1;
    334     }
    335     xsd->relptr = (unsigned long)pos;
    336 
    337     reloc = (xdf_reloc *)yasm_section_relocs_first(sect);
    338     while (reloc) {
    339         unsigned char *localbuf = info->buf;
    340         /*@null@*/ xdf_symrec_data *xsymd;
    341 
    342         xsymd = yasm_symrec_get_data(reloc->reloc.sym, &xdf_symrec_data_cb);
    343         if (!xsymd)
    344             yasm_internal_error(
    345                 N_("xdf: no symbol data for relocated symbol"));
    346 
    347         yasm_intnum_get_sized(reloc->reloc.addr, localbuf, 4, 32, 0, 0, 0);
    348         localbuf += 4;                          /* address of relocation */
    349         YASM_WRITE_32_L(localbuf, xsymd->index);    /* relocated symbol */
    350         if (reloc->base) {
    351             xsymd = yasm_symrec_get_data(reloc->base, &xdf_symrec_data_cb);
    352             if (!xsymd)
    353                 yasm_internal_error(
    354                     N_("xdf: no symbol data for relocated base symbol"));
    355             YASM_WRITE_32_L(localbuf, xsymd->index); /* base symbol */
    356         } else {
    357             if (reloc->type == XDF_RELOC_WRT)
    358                 yasm_internal_error(
    359                     N_("xdf: no base symbol for WRT relocation"));
    360             YASM_WRITE_32_L(localbuf, 0);           /* no base symbol */
    361         }
    362         YASM_WRITE_8(localbuf, reloc->type);        /* type of relocation */
    363         YASM_WRITE_8(localbuf, reloc->size);        /* size of relocation */
    364         YASM_WRITE_8(localbuf, reloc->shift);       /* relocation shift */
    365         YASM_WRITE_8(localbuf, 0);                  /* flags */
    366         fwrite(info->buf, 16, 1, info->f);
    367 
    368         reloc = (xdf_reloc *)yasm_section_reloc_next((yasm_reloc *)reloc);
    369     }
    370 
    371     return 0;
    372 }
    373 
    374 static int
    375 xdf_objfmt_output_secthead(yasm_section *sect, /*@null@*/ void *d)
    376 {
    377     /*@null@*/ xdf_objfmt_output_info *info = (xdf_objfmt_output_info *)d;
    378     yasm_objfmt_xdf *objfmt_xdf;
    379     /*@dependent@*/ /*@null@*/ xdf_section_data *xsd;
    380     /*@null@*/ xdf_symrec_data *xsymd;
    381     unsigned char *localbuf;
    382 
    383     assert(info != NULL);
    384     objfmt_xdf = info->objfmt_xdf;
    385     xsd = yasm_section_get_data(sect, &xdf_section_data_cb);
    386     assert(xsd != NULL);
    387 
    388     localbuf = info->buf;
    389     xsymd = yasm_symrec_get_data(xsd->sym, &xdf_symrec_data_cb);
    390     assert(xsymd != NULL);
    391 
    392     YASM_WRITE_32_L(localbuf, xsymd->index);    /* section name symbol */
    393     if (xsd->addr) {
    394         yasm_intnum_get_sized(xsd->addr, localbuf, 8, 64, 0, 0, 0);
    395         localbuf += 8;                          /* physical address */
    396     } else {
    397         YASM_WRITE_32_L(localbuf, 0);
    398         YASM_WRITE_32_L(localbuf, 0);
    399     }
    400     if (xsd->vaddr) {
    401         yasm_intnum_get_sized(xsd->vaddr, localbuf, 8, 64, 0, 0, 0);
    402         localbuf += 8;                          /* virtual address */
    403     } else if (xsd->addr) {
    404         yasm_intnum_get_sized(xsd->addr, localbuf, 8, 64, 0, 0, 0);
    405         localbuf += 8;                          /* VA=PA */
    406     } else {
    407         YASM_WRITE_32_L(localbuf, 0);
    408         YASM_WRITE_32_L(localbuf, 0);
    409     }
    410     YASM_WRITE_16_L(localbuf, yasm_section_get_align(sect)); /* alignment */
    411     YASM_WRITE_16_L(localbuf, xsd->flags);      /* flags */
    412     YASM_WRITE_32_L(localbuf, xsd->scnptr);     /* file ptr to data */
    413     YASM_WRITE_32_L(localbuf, xsd->size);       /* section size */
    414     YASM_WRITE_32_L(localbuf, xsd->relptr);     /* file ptr to relocs */
    415     YASM_WRITE_32_L(localbuf, xsd->nreloc); /* num of relocation entries */
    416     fwrite(info->buf, 40, 1, info->f);
    417 
    418     return 0;
    419 }
    420 
    421 static int
    422 xdf_objfmt_count_sym(yasm_symrec *sym, /*@null@*/ void *d)
    423 {
    424     /*@null@*/ xdf_objfmt_output_info *info = (xdf_objfmt_output_info *)d;
    425     yasm_sym_vis vis = yasm_symrec_get_visibility(sym);
    426     assert(info != NULL);
    427     if (vis & YASM_SYM_COMMON) {
    428         yasm_error_set(YASM_ERROR_GENERAL,
    429             N_("XDF object format does not support common variables"));
    430         yasm_errwarn_propagate(info->errwarns, yasm_symrec_get_decl_line(sym));
    431         return 0;
    432     }
    433     if (info->all_syms ||
    434         (vis != YASM_SYM_LOCAL && !(vis & YASM_SYM_DLOCAL))) {
    435         /* Save index in symrec data */
    436         xdf_symrec_data *sym_data = yasm_xmalloc(sizeof(xdf_symrec_data));
    437         sym_data->index = info->indx;
    438         yasm_symrec_add_data(sym, &xdf_symrec_data_cb, sym_data);
    439 
    440         info->indx++;
    441     }
    442     return 0;
    443 }
    444 
    445 static int
    446 xdf_objfmt_output_sym(yasm_symrec *sym, /*@null@*/ void *d)
    447 {
    448     /*@null@*/ xdf_objfmt_output_info *info = (xdf_objfmt_output_info *)d;
    449     yasm_sym_vis vis = yasm_symrec_get_visibility(sym);
    450 
    451     assert(info != NULL);
    452 
    453     if (info->all_syms || vis != YASM_SYM_LOCAL) {
    454         /*@only@*/ char *name = yasm_symrec_get_global_name(sym, info->object);
    455         const yasm_expr *equ_val;
    456         const yasm_intnum *intn;
    457         size_t len = strlen(name);
    458         unsigned long value = 0;
    459         long scnum = -3;        /* -3 = debugging symbol */
    460         /*@dependent@*/ /*@null@*/ yasm_section *sect;
    461         /*@dependent@*/ /*@null@*/ yasm_bytecode *precbc;
    462         unsigned long flags = 0;
    463         unsigned char *localbuf;
    464 
    465         if (vis & YASM_SYM_GLOBAL)
    466             flags = XDF_SYM_GLOBAL;
    467 
    468         /* Look at symrec for value/scnum/etc. */
    469         if (yasm_symrec_get_label(sym, &precbc)) {
    470             if (precbc)
    471                 sect = yasm_bc_get_section(precbc);
    472             else
    473                 sect = NULL;
    474             /* it's a label: get value and offset.
    475              * If there is not a section, leave as debugging symbol.
    476              */
    477             if (sect) {
    478                 /*@dependent@*/ /*@null@*/ xdf_section_data *csectd;
    479                 csectd = yasm_section_get_data(sect, &xdf_section_data_cb);
    480                 if (csectd)
    481                     scnum = csectd->scnum;
    482                 else
    483                     yasm_internal_error(N_("didn't understand section"));
    484                 if (precbc)
    485                     value += yasm_bc_next_offset(precbc);
    486             }
    487         } else if ((equ_val = yasm_symrec_get_equ(sym))) {
    488             yasm_expr *equ_val_copy = yasm_expr_copy(equ_val);
    489             intn = yasm_expr_get_intnum(&equ_val_copy, 1);
    490             if (!intn) {
    491                 if (vis & YASM_SYM_GLOBAL) {
    492                     yasm_error_set(YASM_ERROR_NOT_CONSTANT,
    493                         N_("global EQU value not an integer expression"));
    494                     yasm_errwarn_propagate(info->errwarns, equ_val->line);
    495                 }
    496             } else
    497                 value = yasm_intnum_get_uint(intn);
    498             yasm_expr_destroy(equ_val_copy);
    499 
    500             flags |= XDF_SYM_EQU;
    501             scnum = -2;     /* -2 = absolute symbol */
    502         } else {
    503             if (vis & YASM_SYM_EXTERN) {
    504                 flags = XDF_SYM_EXTERN;
    505                 scnum = -1;
    506             }
    507         }
    508 
    509         localbuf = info->buf;
    510         YASM_WRITE_32_L(localbuf, scnum);       /* section number */
    511         YASM_WRITE_32_L(localbuf, value);       /* value */
    512         YASM_WRITE_32_L(localbuf, info->strtab_offset);
    513         info->strtab_offset += (unsigned long)(len+1);
    514         YASM_WRITE_32_L(localbuf, flags);       /* flags */
    515         fwrite(info->buf, 16, 1, info->f);
    516         yasm_xfree(name);
    517     }
    518     return 0;
    519 }
    520 
    521 static int
    522 xdf_objfmt_output_str(yasm_symrec *sym, /*@null@*/ void *d)
    523 {
    524     /*@null@*/ xdf_objfmt_output_info *info = (xdf_objfmt_output_info *)d;
    525     yasm_sym_vis vis = yasm_symrec_get_visibility(sym);
    526 
    527     assert(info != NULL);
    528 
    529     if (info->all_syms || vis != YASM_SYM_LOCAL) {
    530         /*@only@*/ char *name = yasm_symrec_get_global_name(sym, info->object);
    531         size_t len = strlen(name);
    532         fwrite(name, len+1, 1, info->f);
    533         yasm_xfree(name);
    534     }
    535     return 0;
    536 }
    537 
    538 static void
    539 xdf_objfmt_output(yasm_object *object, FILE *f, int all_syms,
    540                   yasm_errwarns *errwarns)
    541 {
    542     yasm_objfmt_xdf *objfmt_xdf = (yasm_objfmt_xdf *)object->objfmt;
    543     xdf_objfmt_output_info info;
    544     unsigned char *localbuf;
    545     unsigned long symtab_count = 0;
    546 
    547     info.object = object;
    548     info.objfmt_xdf = objfmt_xdf;
    549     info.errwarns = errwarns;
    550     info.f = f;
    551     info.buf = yasm_xmalloc(REGULAR_OUTBUF_SIZE);
    552 
    553     /* Allocate space for headers by seeking forward */
    554     if (fseek(f, (long)(16+40*(objfmt_xdf->parse_scnum)), SEEK_SET) < 0) {
    555         yasm__fatal(N_("could not seek on output file"));
    556         /*@notreached@*/
    557         return;
    558     }
    559 
    560     /* Get number of symbols */
    561     info.indx = 0;
    562     info.all_syms = 1;  /* force all syms into symbol table */
    563     yasm_symtab_traverse(object->symtab, &info, xdf_objfmt_count_sym);
    564     symtab_count = info.indx;
    565 
    566     /* Get file offset of start of string table */
    567     info.strtab_offset = 16+40*(objfmt_xdf->parse_scnum)+16*symtab_count;
    568 
    569     /* Output symbol table */
    570     yasm_symtab_traverse(object->symtab, &info, xdf_objfmt_output_sym);
    571 
    572     /* Output string table */
    573     yasm_symtab_traverse(object->symtab, &info, xdf_objfmt_output_str);
    574 
    575     /* Section data/relocs */
    576     if (yasm_object_sections_traverse(object, &info,
    577                                       xdf_objfmt_output_section))
    578         return;
    579 
    580     /* Write headers */
    581     if (fseek(f, 0, SEEK_SET) < 0) {
    582         yasm__fatal(N_("could not seek on output file"));
    583         /*@notreached@*/
    584         return;
    585     }
    586 
    587     localbuf = info.buf;
    588     YASM_WRITE_32_L(localbuf, XDF_MAGIC);       /* magic number */
    589     YASM_WRITE_32_L(localbuf, objfmt_xdf->parse_scnum); /* number of sects */
    590     YASM_WRITE_32_L(localbuf, symtab_count);            /* number of symtabs */
    591     /* size of sect headers + symbol table + strings */
    592     YASM_WRITE_32_L(localbuf, info.strtab_offset-16);
    593     fwrite(info.buf, 16, 1, f);
    594 
    595     yasm_object_sections_traverse(object, &info, xdf_objfmt_output_secthead);
    596 
    597     yasm_xfree(info.buf);
    598 }
    599 
    600 static void
    601 xdf_objfmt_destroy(yasm_objfmt *objfmt)
    602 {
    603     yasm_xfree(objfmt);
    604 }
    605 
    606 static void
    607 xdf_objfmt_init_new_section(yasm_section *sect, unsigned long line)
    608 {
    609     yasm_object *object = yasm_section_get_object(sect);
    610     const char *sectname = yasm_section_get_name(sect);
    611     yasm_objfmt_xdf *objfmt_xdf = (yasm_objfmt_xdf *)object->objfmt;
    612     xdf_section_data *data;
    613     yasm_symrec *sym;
    614 
    615     data = yasm_xmalloc(sizeof(xdf_section_data));
    616     data->scnum = objfmt_xdf->parse_scnum++;
    617     data->flags = 0;
    618     data->addr = NULL;
    619     data->vaddr = NULL;
    620     data->scnptr = 0;
    621     data->size = 0;
    622     data->relptr = 0;
    623     data->nreloc = 0;
    624     yasm_section_add_data(sect, &xdf_section_data_cb, data);
    625 
    626     sym = yasm_symtab_define_label(object->symtab, sectname,
    627                                    yasm_section_bcs_first(sect), 1, line);
    628     data->sym = sym;
    629 }
    630 
    631 static yasm_section *
    632 xdf_objfmt_add_default_section(yasm_object *object)
    633 {
    634     yasm_section *retval;
    635     int isnew;
    636 
    637     retval = yasm_object_get_general(object, ".text", 0, 1, 0, &isnew, 0);
    638     if (isnew)
    639         yasm_section_set_default(retval, 1);
    640     return retval;
    641 }
    642 
    643 static int
    644 xdf_helper_use(void *obj, yasm_valparam *vp, unsigned long line, void *d,
    645                uintptr_t bits)
    646 {
    647     yasm_object *object = (yasm_object *)obj;
    648     unsigned long *flags = (unsigned long *)d;
    649     *flags &= ~(XDF_SECT_USE_16|XDF_SECT_USE_32|XDF_SECT_USE_64);
    650     switch (bits) {
    651         case 16: *flags |= XDF_SECT_USE_16; break;
    652         case 32: *flags |= XDF_SECT_USE_32; break;
    653         case 64: *flags |= XDF_SECT_USE_64; break;
    654     };
    655     yasm_arch_set_var(object->arch, "mode_bits", bits);
    656     return 0;
    657 }
    658 
    659 static /*@observer@*/ /*@null@*/ yasm_section *
    660 xdf_objfmt_section_switch(yasm_object *object, yasm_valparamhead *valparams,
    661                           /*@unused@*/ /*@null@*/
    662                           yasm_valparamhead *objext_valparams,
    663                           unsigned long line)
    664 {
    665     yasm_valparam *vp;
    666     yasm_section *retval;
    667     int isnew;
    668     int flags_override = 0;
    669     const char *sectname;
    670     int resonly = 0;
    671     xdf_section_data *xsd;
    672     unsigned long align = 0;
    673 
    674     struct xdf_section_switch_data {
    675         /*@only@*/ /*@null@*/ yasm_intnum *absaddr;
    676         /*@only@*/ /*@null@*/ yasm_intnum *vaddr;
    677         /*@only@*/ /*@null@*/ yasm_intnum *align_intn;
    678         unsigned long flags;
    679     } data;
    680 
    681     static const yasm_dir_help help[] = {
    682         { "use16", 0, xdf_helper_use,
    683           offsetof(struct xdf_section_switch_data, flags), 16 },
    684         { "use32", 0, xdf_helper_use,
    685           offsetof(struct xdf_section_switch_data, flags), 32 },
    686         { "use64", 0, xdf_helper_use,
    687           offsetof(struct xdf_section_switch_data, flags), 64 },
    688         { "bss", 0, yasm_dir_helper_flag_or,
    689           offsetof(struct xdf_section_switch_data, flags), XDF_SECT_BSS },
    690         { "flat", 0, yasm_dir_helper_flag_or,
    691           offsetof(struct xdf_section_switch_data, flags), XDF_SECT_FLAT },
    692         { "absolute", 1, yasm_dir_helper_intn,
    693           offsetof(struct xdf_section_switch_data, absaddr), 0 },
    694         { "virtual", 1, yasm_dir_helper_intn,
    695           offsetof(struct xdf_section_switch_data, vaddr), 0 },
    696         { "align", 1, yasm_dir_helper_intn,
    697           offsetof(struct xdf_section_switch_data, align_intn), 0 }
    698     };
    699 
    700     data.absaddr = NULL;
    701     data.vaddr = NULL;
    702     data.align_intn = NULL;
    703     data.flags = 0;
    704 
    705     vp = yasm_vps_first(valparams);
    706     sectname = yasm_vp_string(vp);
    707     if (!sectname)
    708         return NULL;
    709     vp = yasm_vps_next(vp);
    710 
    711     flags_override = yasm_dir_helper(object, vp, line, help, NELEMS(help),
    712                                      &data, yasm_dir_helper_valparam_warn);
    713     if (flags_override < 0)
    714         return NULL;    /* error occurred */
    715 
    716     if (data.absaddr)
    717         data.flags |= XDF_SECT_ABSOLUTE;
    718     if (data.align_intn) {
    719         align = yasm_intnum_get_uint(data.align_intn);
    720         yasm_intnum_destroy(data.align_intn);
    721 
    722         /* Alignments must be a power of two. */
    723         if (!is_exp2(align)) {
    724             yasm_error_set(YASM_ERROR_VALUE,
    725                            N_("argument to `%s' is not a power of two"),
    726                            "align");
    727             if (data.vaddr)
    728                 yasm_intnum_destroy(data.vaddr);
    729             if (data.absaddr)
    730                 yasm_intnum_destroy(data.absaddr);
    731             return NULL;
    732         }
    733 
    734         /* Check to see if alignment is supported size */
    735         if (align > 4096) {
    736             yasm_error_set(YASM_ERROR_VALUE,
    737                            N_("XDF does not support alignments > 4096"));
    738             if (data.vaddr)
    739                 yasm_intnum_destroy(data.vaddr);
    740             if (data.absaddr)
    741                 yasm_intnum_destroy(data.absaddr);
    742             return NULL;
    743         }
    744     }
    745 
    746     retval = yasm_object_get_general(object, sectname, align, 1, resonly,
    747                                      &isnew, line);
    748 
    749     xsd = yasm_section_get_data(retval, &xdf_section_data_cb);
    750 
    751     if (isnew || yasm_section_is_default(retval)) {
    752         yasm_section_set_default(retval, 0);
    753         xsd->flags = data.flags;
    754         if (data.absaddr) {
    755             if (xsd->addr)
    756                 yasm_intnum_destroy(xsd->addr);
    757             xsd->addr = data.absaddr;
    758         }
    759         if (data.vaddr) {
    760             if (xsd->vaddr)
    761                 yasm_intnum_destroy(xsd->vaddr);
    762             xsd->vaddr = data.vaddr;
    763         }
    764         yasm_section_set_align(retval, align, line);
    765     } else if (flags_override)
    766         yasm_warn_set(YASM_WARN_GENERAL,
    767                       N_("section flags ignored on section redeclaration"));
    768     return retval;
    769 }
    770 
    771 static /*@observer@*/ /*@null@*/ yasm_symrec *
    772 xdf_objfmt_get_special_sym(yasm_object *object, const char *name,
    773                            const char *parser)
    774 {
    775     return NULL;
    776 }
    777 
    778 static void
    779 xdf_section_data_destroy(void *data)
    780 {
    781     xdf_section_data *xsd = (xdf_section_data *)data;
    782     if (xsd->addr)
    783         yasm_intnum_destroy(xsd->addr);
    784     if (xsd->vaddr)
    785         yasm_intnum_destroy(xsd->vaddr);
    786     yasm_xfree(data);
    787 }
    788 
    789 static void
    790 xdf_section_data_print(void *data, FILE *f, int indent_level)
    791 {
    792     xdf_section_data *xsd = (xdf_section_data *)data;
    793 
    794     fprintf(f, "%*ssym=\n", indent_level, "");
    795     yasm_symrec_print(xsd->sym, f, indent_level+1);
    796     fprintf(f, "%*sscnum=%ld\n", indent_level, "", xsd->scnum);
    797     fprintf(f, "%*sflags=0x%x\n", indent_level, "", xsd->flags);
    798     fprintf(f, "%*saddr=", indent_level, "");
    799     yasm_intnum_print(xsd->addr, f);
    800     fprintf(f, "%*svaddr=", indent_level, "");
    801     yasm_intnum_print(xsd->vaddr, f);
    802     fprintf(f, "%*sscnptr=0x%lx\n", indent_level, "", xsd->scnptr);
    803     fprintf(f, "%*ssize=%ld\n", indent_level, "", xsd->size);
    804     fprintf(f, "%*srelptr=0x%lx\n", indent_level, "", xsd->relptr);
    805     fprintf(f, "%*snreloc=%ld\n", indent_level, "", xsd->nreloc);
    806 }
    807 
    808 static void
    809 xdf_symrec_data_destroy(void *data)
    810 {
    811     yasm_xfree(data);
    812 }
    813 
    814 static void
    815 xdf_symrec_data_print(void *data, FILE *f, int indent_level)
    816 {
    817     xdf_symrec_data *xsd = (xdf_symrec_data *)data;
    818 
    819     fprintf(f, "%*ssymtab index=%lu\n", indent_level, "", xsd->index);
    820 }
    821 
    822 /* Define valid debug formats to use with this object format */
    823 static const char *xdf_objfmt_dbgfmt_keywords[] = {
    824     "null",
    825     NULL
    826 };
    827 
    828 /* Define objfmt structure -- see objfmt.h for details */
    829 yasm_objfmt_module yasm_xdf_LTX_objfmt = {
    830     "Extended Dynamic Object",
    831     "xdf",
    832     "xdf",
    833     32,
    834     0,
    835     xdf_objfmt_dbgfmt_keywords,
    836     "null",
    837     NULL,       /* no directives */
    838     NULL,       /* no standard macros */
    839     xdf_objfmt_create,
    840     xdf_objfmt_output,
    841     xdf_objfmt_destroy,
    842     xdf_objfmt_add_default_section,
    843     xdf_objfmt_init_new_section,
    844     xdf_objfmt_section_switch,
    845     xdf_objfmt_get_special_sym
    846 };
    847