]> granicus.if.org Git - yasm/commitdiff
* expr.c (yasm_expr_extract_symrec): Add "relocate" parameter. Use it to
authorPeter Johnson <peter@tortall.net>
Mon, 27 Sep 2004 04:15:12 +0000 (04:15 -0000)
committerPeter Johnson <peter@tortall.net>
Mon, 27 Sep 2004 04:15:12 +0000 (04:15 -0000)
control whether the symbol is replaced with the symbol's value (old
behavior), or just replace it with 0 (new optional behavior).  The old
behavior is enabled by setting relocate=1.
* expr.h (yasm_expr_extract_symrec): Likewise (and document new behavior).
* elf-objfmt.c (elf_objfmt_output_expr): Use new function (with relocate=1).
* coff-objfmt.c (coff_objfmt_output_expr): Likewise.

* expr.c (yasm_expr_extract_segment): Renamed to yasm_expr_extract_segoff, a
more approprate name given what operator it looks at.
* expr.h (yasm_expr_extract_segment): Likewise.
* x86bc.c (x86_bc_jmp_tobytes): Use new function name.

* expr.c (yasm_expr_extract_seg): New function to remove SEG unary operator.
* expr.h (yasm_expr_extract_seg): Likewise.

* expr.c (yasm_expr_extract_shr): New function to split SHR operator into
left and right halves.
* expr.h (yasm_expr_extract_shr): Likewise.

* xdf.h: New header file describing the newly added Extended Dynamic Object
Format (XDF).  Note: GCC-only code.
* xdfdump.c: New utility that uses the format described in xdf.h to
completely dump an XDF file.  Note: non-portable code (runs correctly on
little endian machines only).
Neither of these files are currently included in the distribution.

* xdf-objfmt.c: New YASM objfmt module to output XDF format object files.
* modules/objfmts/xdf/Makefile.inc: Add to build.
* modules/objfmts/Makefile.inc: Likewise.

The XDF object format is a blend between COFF and OMF.  It is a very simple
object format intended for use by operating system loaders or similar types
of targets.  It allows shifted relocations (useful for static interrupt or
page tables), both flat and segment-relative, and the use of the SEG, WRT,
and x86 JMP FAR notations.

Test cases will be committed soon.

svn path=/trunk/yasm/; revision=1149

libyasm/expr.c
libyasm/expr.h
modules/arch/x86/x86bc.c
modules/objfmts/Makefile.inc
modules/objfmts/coff/coff-objfmt.c
modules/objfmts/elf/elf-objfmt.c
modules/objfmts/xdf/Makefile.inc [new file with mode: 0644]
modules/objfmts/xdf/xdf-objfmt.c [new file with mode: 0644]
tools/xdf/xdf.h [new file with mode: 0644]
tools/xdf/xdfdump.c [new file with mode: 0644]

index 1f417d4be533752343911fd01813e086bdab433c..89dce55510b212e1d59cf295fde511bbb94f3c5b 100644 (file)
@@ -985,7 +985,8 @@ yasm_expr__traverse_leaves_in(yasm_expr *e, void *d,
 }
 
 yasm_symrec *
-yasm_expr_extract_symrec(yasm_expr **ep, yasm_calc_bc_dist_func calc_bc_dist)
+yasm_expr_extract_symrec(yasm_expr **ep, int relocate,
+                        yasm_calc_bc_dist_func calc_bc_dist)
 {
     yasm_symrec *sym = NULL;
     int i, symterm = -1;
@@ -1015,7 +1016,7 @@ yasm_expr_extract_symrec(yasm_expr **ep, yasm_calc_bc_dist_func calc_bc_dist)
        /*@dependent@*/ /*@null@*/ yasm_bytecode *precbc;
        /*@null@*/ yasm_intnum *intn;
 
-       if (yasm_symrec_get_label(sym, &precbc)) {
+       if (relocate && yasm_symrec_get_label(sym, &precbc)) {
            intn = calc_bc_dist(yasm_section_bcs_first(
                                    yasm_bc_get_section(precbc)), precbc);
            if (!intn)
@@ -1029,7 +1030,22 @@ yasm_expr_extract_symrec(yasm_expr **ep, yasm_calc_bc_dist_func calc_bc_dist)
 }
 
 yasm_expr *
-yasm_expr_extract_segment(yasm_expr **ep)
+yasm_expr_extract_seg(yasm_expr **ep)
+{
+    yasm_expr *e = *ep;
+
+    /* If not SEG, we can't do this transformation */
+    if (e->op != YASM_EXPR_SEG)
+       return NULL;
+
+    /* Remove the SEG by changing the expression into an IDENT */
+    e->op = YASM_EXPR_IDENT;
+
+    return e;
+}
+
+yasm_expr *
+yasm_expr_extract_segoff(yasm_expr **ep)
 {
     yasm_expr *retval;
     yasm_expr *e = *ep;
@@ -1085,6 +1101,34 @@ yasm_expr_extract_wrt(yasm_expr **ep)
     return retval;
 }
 
+yasm_expr *
+yasm_expr_extract_shr(yasm_expr **ep)
+{
+    yasm_expr *retval;
+    yasm_expr *e = *ep;
+
+    /* If not SHR, we can't do this transformation */
+    if (e->op != YASM_EXPR_SHR)
+       return NULL;
+
+    /* Extract the right side portion out to its own expression */
+    if (e->terms[1].type == YASM_EXPR_EXPR)
+       retval = e->terms[1].data.expn;
+    else {
+       /* Need to build IDENT expression to hold non-expression contents */
+       retval = yasm_xmalloc(sizeof(yasm_expr));
+       retval->op = YASM_EXPR_IDENT;
+       retval->numterms = 1;
+       retval->terms[0] = e->terms[1]; /* structure copy */
+    }
+
+    /* Delete the right side portion by changing the expr into an IDENT */
+    e->op = YASM_EXPR_IDENT;
+    e->numterms = 1;
+
+    return retval;
+}
+
 /*@-unqualifiedtrans -nullderef -nullstate -onlytrans@*/
 const yasm_intnum *
 yasm_expr_get_intnum(yasm_expr **ep, yasm_calc_bc_dist_func calc_bc_dist)
index f79981da0806ed0a4af0b184c9f54748c44391d9..1c38e34ede5be83608535e0c03d32a968616d569 100644 (file)
@@ -169,15 +169,25 @@ SLIST_HEAD(yasm__exprhead, yasm__exprentry);
 #define yasm_expr_simplify(e, cbd) \
     yasm_expr__level_tree(e, 1, 1, cbd, NULL, NULL, NULL)
 
-/** Extract a single symbol out of an expression.  Replaces it with the
- * symbol's value (if it's a label).
+/** Extract a single symbol out of an expression.  Replaces it with 0, or
+ * optionally the symbol's value (if it's a label).
  * \param ep           expression (pointer to)
+ * \param relocate     replace symbol with value (if label) if nonzero
  * \param calc_bc_dist bytecode distance-calculation function
  * \return NULL if unable to extract a symbol (too complex of expr, none
  *         present, etc); otherwise returns the extracted symbol.
  */
 /*@dependent@*/ /*@null@*/ yasm_symrec *yasm_expr_extract_symrec
-    (yasm_expr **ep, yasm_calc_bc_dist_func calc_bc_dist);
+    (yasm_expr **ep, int relocate, yasm_calc_bc_dist_func calc_bc_dist);
+
+/** Remove the SEG unary operator if present, leaving the lower level
+ * expression.
+ * \param ep           expression (pointer to)
+ * \param simplify     if nonzero, simplify the expression first
+ * \return NULL if the expression does not have a top-level operator of SEG;
+ * otherwise the modified input expression (without the SEG).
+ */
+/*@only@*/ /*@null@*/ yasm_expr *yasm_expr_extract_seg(yasm_expr **ep);
 
 /** Extract the segment portion of a SEG:OFF expression, leaving the offset.
  * \param ep           expression (pointer to)
@@ -186,7 +196,7 @@ SLIST_HEAD(yasm__exprhead, yasm__exprentry);
  *         expression is modified such that on return, it's the offset
  *         expression.
  */
-/*@only@*/ /*@null@*/ yasm_expr *yasm_expr_extract_segment(yasm_expr **ep);
+/*@only@*/ /*@null@*/ yasm_expr *yasm_expr_extract_segoff(yasm_expr **ep);
 
 /** Extract the right portion (y) of a x WRT y expression, leaving the left
  * portion (x).
@@ -198,6 +208,16 @@ SLIST_HEAD(yasm__exprhead, yasm__exprentry);
  */
 /*@only@*/ /*@null@*/ yasm_expr *yasm_expr_extract_wrt(yasm_expr **ep);
 
+/** Extract the right portion (y) of a x SHR y expression, leaving the left
+ * portion (x).
+ * \param ep           expression (pointer to)
+ * \return NULL if unable to extract (YASM_EXPR_SHR not the top-level
+ *         operator), otherwise the right side of the SHR expression.  The
+ *         input expression is modified such that on return, it's the left side
+ *         of the SHR expression.
+ */
+/*@only@*/ /*@null@*/ yasm_expr *yasm_expr_extract_shr(yasm_expr **ep);
+
 /** Get the integer value of an expression if it's just an integer.
  * \param ep           expression (pointer to)
  * \param calc_bc_dist bytecode distance-calculation function
index 14ef1bea4ab2e2d69bcc3816cdf0373c1f3722c3..fa32ac7929491e1d28529baf10021673186bfc2a 100644 (file)
@@ -1139,7 +1139,7 @@ x86_bc_jmp_tobytes(yasm_bytecode *bc, unsigned char **bufp, void *d,
 
            /* Absolute displacement: segment and offset */
            jmp->target = yasm_expr_simplify(jmp->target, NULL);
-           targetseg = yasm_expr_extract_segment(&jmp->target);
+           targetseg = yasm_expr_extract_segoff(&jmp->target);
            if (!targetseg)
                yasm_internal_error(N_("could not extract segment for far jump"));
            i = (opersize == 16) ? 2 : 4;
index 46dc6b0adb608b5a6791e3302caf6c86df4912af..01c963b3fa30913b279c4b390348aa6c83c199bb 100644 (file)
@@ -6,6 +6,7 @@ EXTRA_DIST += modules/objfmts/elf/Makefile.inc
 #!EXTRA_DIST += modules/objfmts/omf/Makefile.inc
 EXTRA_DIST += modules/objfmts/coff/Makefile.inc
 EXTRA_DIST += modules/objfmts/win32/Makefile.inc
+EXTRA_DIST += modules/objfmts/xdf/Makefile.inc
 
 include modules/objfmts/dbg/Makefile.inc
 include modules/objfmts/bin/Makefile.inc
@@ -13,3 +14,4 @@ include modules/objfmts/elf/Makefile.inc
 #!include modules/objfmts/omf/Makefile.inc
 include modules/objfmts/coff/Makefile.inc
 include modules/objfmts/win32/Makefile.inc
+include modules/objfmts/xdf/Makefile.inc
index 6a8d298baef8dd5691e04d7fd0771a3cc8a506aa..b30ff0aaec7a30230be3e29f2a3a3273dfede399 100644 (file)
@@ -388,7 +388,7 @@ coff_objfmt_output_expr(yasm_expr **ep, unsigned char *buf, size_t destsize,
     }
 
     /* Handle integer expressions, with relocation if necessary */
-    sym = yasm_expr_extract_symrec(ep, yasm_common_calc_bc_dist);
+    sym = yasm_expr_extract_symrec(ep, 1, yasm_common_calc_bc_dist);
     if (sym) {
        coff_reloc *reloc;
        yasm_sym_vis vis;
index 80f073ed04447fa611f51ff00234e00e66f2f3ea..48875be451883aeb0214241ac37ad3c424731a16 100644 (file)
@@ -255,7 +255,7 @@ elf_objfmt_output_expr(yasm_expr **ep, unsigned char *buf, size_t destsize,
     }
 
     /* Handle integer expressions, with relocation if necessary */
-    sym = yasm_expr_extract_symrec(ep, yasm_common_calc_bc_dist);
+    sym = yasm_expr_extract_symrec(ep, 1, yasm_common_calc_bc_dist);
     if (sym) {
        elf_reloc_entry *reloc;
        yasm_sym_vis vis;
diff --git a/modules/objfmts/xdf/Makefile.inc b/modules/objfmts/xdf/Makefile.inc
new file mode 100644 (file)
index 0000000..9f87998
--- /dev/null
@@ -0,0 +1,12 @@
+# $Id$
+
+pkglib_LTLIBRARIES += objfmt_xdf.la
+
+objfmt_xdf_la_SOURCES = modules/objfmts/xdf/xdf-objfmt.c
+objfmt_xdf_la_LDFLAGS = -module -avoid-version -no-undefined
+objfmt_xdf_la_LIBADD = libyasm.la
+YASM_MODULES += -dlopen objfmt_xdf.la
+
+#EXTRA_DIST += modules/objfmts/xdf/tests/Makefile.inc
+
+#include modules/objfmts/xdf/tests/Makefile.inc
diff --git a/modules/objfmts/xdf/xdf-objfmt.c b/modules/objfmts/xdf/xdf-objfmt.c
new file mode 100644 (file)
index 0000000..24dc3dc
--- /dev/null
@@ -0,0 +1,944 @@
+/*
+ * Extended Dynamic Object format
+ *
+ *  Copyright (C) 2004  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>
+/*@unused@*/ RCSID("$Id$");
+
+#define YASM_LIB_INTERNAL
+#define YASM_BC_INTERNAL
+#define YASM_EXPR_INTERNAL
+#include <libyasm.h>
+
+
+#define REGULAR_OUTBUF_SIZE    1024
+
+#define XDF_MAGIC      0x87654321
+
+#define XDF_SYM_EXTERN 1
+#define XDF_SYM_GLOBAL 2
+#define XDF_SYM_EQU    4
+
+typedef STAILQ_HEAD(xdf_reloc_head, xdf_reloc) xdf_reloc_head;
+
+typedef struct xdf_reloc {
+    STAILQ_ENTRY(xdf_reloc) link;  /* internal link, not in file */
+    unsigned long addr;                    /* offset of relocation within section */
+    yasm_symrec *sym;              /* relocated symbol */
+    /*@null@*/ yasm_symrec *base;   /* base symbol (for WRT) */
+    enum {
+       XDF_RELOC_FLAT = 1,         /* relative to 0 */
+       XDF_RELOC_REL = 2,          /* relative to segment */
+       XDF_RELOC_WRT = 4,          /* relative to symbol */
+       XDF_RELOC_RIP = 8,          /* RIP-relative */
+       XDF_RELOC_SEG = 16          /* 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 */
+    long scnum;                    /* section number (0=first section) */
+    unsigned int align;            /* section alignment (0-4096) */
+    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 */
+    /*@owned@*/ xdf_reloc_head relocs;
+} xdf_section_data;
+
+typedef struct xdf_symrec_data {
+    unsigned long index;               /* assigned XDF symbol table index */
+} xdf_symrec_data;
+
+typedef struct xdf_symtab_entry {
+    STAILQ_ENTRY(xdf_symtab_entry) link;
+    /*@dependent@*/ yasm_symrec *sym;
+} xdf_symtab_entry;
+typedef STAILQ_HEAD(xdf_symtab_head, xdf_symtab_entry) xdf_symtab_head;
+
+typedef struct yasm_objfmt_xdf {
+    yasm_objfmt_base objfmt;               /* base structure */
+
+    long parse_scnum;              /* sect numbering in parser */
+    xdf_symtab_head xdf_symtab;            /* symbol table of indexed syms */
+
+    yasm_object *object;
+    yasm_symtab *symtab;
+    /*@dependent@*/ yasm_arch *arch;
+} yasm_objfmt_xdf;
+
+typedef struct xdf_objfmt_output_info {
+    yasm_objfmt_xdf *objfmt_xdf;
+    /*@dependent@*/ FILE *f;
+    /*@only@*/ unsigned char *buf;
+    yasm_section *sect;
+    /*@dependent@*/ xdf_section_data *xsd;
+} 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 /*@dependent@*/ xdf_symtab_entry *
+xdf_objfmt_symtab_append(yasm_objfmt_xdf *objfmt_xdf, yasm_symrec *sym)
+{
+    /*@null@*/ /*@dependent@*/ xdf_symrec_data *sym_data_prev;
+    xdf_symrec_data *sym_data;
+    xdf_symtab_entry *entry;
+    unsigned long indx;
+
+    if (STAILQ_EMPTY(&objfmt_xdf->xdf_symtab))
+       indx = 0;
+    else {
+       entry = STAILQ_LAST(&objfmt_xdf->xdf_symtab, xdf_symtab_entry, link);
+       sym_data_prev = yasm_symrec_get_data(entry->sym, &xdf_symrec_data_cb);
+       assert(sym_data_prev != NULL);
+       indx = sym_data_prev->index + 1;
+    }
+
+    sym_data = yasm_xmalloc(sizeof(xdf_symrec_data));
+    sym_data->index = indx;
+    yasm_symrec_add_data(sym, &xdf_symrec_data_cb, sym_data);
+
+    entry = yasm_xmalloc(sizeof(xdf_symtab_entry));
+    entry->sym = sym;
+    STAILQ_INSERT_TAIL(&objfmt_xdf->xdf_symtab, entry, link);
+
+    return entry;
+}
+
+static int
+xdf_objfmt_append_local_sym(yasm_symrec *sym, /*@unused@*/ /*@null@*/ void *d)
+{
+    /*@null@*/ yasm_objfmt_xdf *objfmt_xdf = (yasm_objfmt_xdf *)d;
+    assert(objfmt_xdf != NULL);
+    if (!yasm_symrec_get_data(sym, &xdf_symrec_data_cb))
+       xdf_objfmt_symtab_append(objfmt_xdf, sym);
+    return 1;
+}
+
+static yasm_objfmt *
+xdf_objfmt_create(const char *in_filename, yasm_object *object, yasm_arch *a)
+{
+    yasm_objfmt_xdf *objfmt_xdf = yasm_xmalloc(sizeof(yasm_objfmt_xdf));
+
+    objfmt_xdf->object = object;
+    objfmt_xdf->symtab = yasm_object_get_symtab(object);
+    objfmt_xdf->arch = a;
+
+    /* Only support x86 arch */
+    if (yasm__strcasecmp(yasm_arch_keyword(a), "x86") != 0) {
+       yasm_xfree(objfmt_xdf);
+       return NULL;
+    }
+
+    /* Support x86 and amd64 machines of x86 arch */
+    if (yasm__strcasecmp(yasm_arch_get_machine(a), "x86") &&
+       yasm__strcasecmp(yasm_arch_get_machine(a), "amd64")) {
+       yasm_xfree(objfmt_xdf);
+       return NULL;
+    }
+
+    objfmt_xdf->parse_scnum = 0;    /* section numbering starts at 0 */
+    STAILQ_INIT(&objfmt_xdf->xdf_symtab);
+
+    objfmt_xdf->objfmt.module = &yasm_xdf_LTX_objfmt;
+
+    return (yasm_objfmt *)objfmt_xdf;
+}
+
+static int
+xdf_objfmt_output_expr(yasm_expr **ep, unsigned char *buf, size_t destsize,
+                       size_t valsize, int shift, unsigned long offset,
+                       yasm_bytecode *bc, int rel, int warn,
+                       /*@null@*/ void *d)
+{
+    /*@null@*/ xdf_objfmt_output_info *info = (xdf_objfmt_output_info *)d;
+    yasm_objfmt_xdf *objfmt_xdf;
+    /*@dependent@*/ /*@null@*/ const yasm_intnum *intn;
+    /*@dependent@*/ /*@null@*/ const yasm_floatnum *flt;
+    /*@dependent@*/ /*@null@*/ yasm_symrec *sym;
+    yasm_expr *shr_expr;
+    yasm_expr *wrt_expr;
+    unsigned int shr = 0;
+    unsigned int seg = 0;
+
+    assert(info != NULL);
+    objfmt_xdf = info->objfmt_xdf;
+
+    *ep = yasm_expr_simplify(*ep, yasm_common_calc_bc_dist);
+
+    /* Handle floating point expressions */
+    flt = yasm_expr_get_floatnum(ep);
+    if (flt) {
+       if (shift < 0)
+           yasm_internal_error(N_("attempting to negative shift a float"));
+       return yasm_arch_floatnum_tobytes(objfmt_xdf->arch, flt, buf,
+                                         destsize, valsize,
+                                         (unsigned int)shift, warn, bc->line);
+    }
+
+    /* Check for a right shift value */
+    shr_expr = yasm_expr_extract_shr(ep);
+    if (shr_expr) {
+       /*@dependent@*/ /*@null@*/ const yasm_intnum *shr_intn;
+       shr_intn = yasm_expr_get_intnum(&shr_expr, NULL);
+       if (!shr_intn) {
+           yasm__error(bc->line, N_("shift expression too complex"));
+           return 1;
+       }
+       shr = yasm_intnum_get_uint(shr_intn);
+    }
+
+    /* Check for a segment relocation */
+    if (yasm_expr_extract_seg(ep))
+       seg = 1;
+
+    /* Check for a WRT relocation */
+    wrt_expr = yasm_expr_extract_wrt(ep);
+
+    /* Handle integer expressions, with relocation if necessary */
+    sym = yasm_expr_extract_symrec(ep, 0, yasm_common_calc_bc_dist);
+    if (sym) {
+       xdf_reloc *reloc;
+
+       reloc = yasm_xmalloc(sizeof(xdf_reloc));
+       reloc->addr = bc->offset + offset;
+       reloc->sym = sym;
+       reloc->base = NULL;
+       reloc->size = valsize/8;
+       reloc->shift = shr;
+
+       if (seg)
+           reloc->type = XDF_RELOC_SEG;
+       else if (wrt_expr) {
+           reloc->base = yasm_expr_extract_symrec(&wrt_expr, 0,
+                                                  yasm_common_calc_bc_dist);
+           if (!reloc->base) {
+               yasm__error(bc->line, N_("WRT expression too complex"));
+               return 1;
+           }
+           reloc->type = XDF_RELOC_WRT;
+       } else if (rel) {
+           reloc->type = XDF_RELOC_RIP;
+           /* Need to reference to start of section, so add $$ in. */
+           *ep = yasm_expr_create(YASM_EXPR_ADD, yasm_expr_expr(*ep),
+               yasm_expr_sym(yasm_symtab_define_label2("$$",
+                   yasm_section_bcs_first(info->sect), 0, (*ep)->line)),
+               (*ep)->line);
+           *ep = yasm_expr_simplify(*ep, yasm_common_calc_bc_dist);
+       } else if (info->xsd->flags & XDF_SECT_FLAT)
+           reloc->type = XDF_RELOC_FLAT;
+       else
+           reloc->type = XDF_RELOC_REL;
+       info->xsd->nreloc++;
+       STAILQ_INSERT_TAIL(&info->xsd->relocs, reloc, link);
+    }
+    intn = yasm_expr_get_intnum(ep, NULL);
+    if (intn)
+       return yasm_arch_intnum_tobytes(objfmt_xdf->arch, intn, buf, destsize,
+                                       valsize, shift, bc, rel, warn,
+                                       bc->line);
+
+    /* Check for complex float expressions */
+    if (yasm_expr__contains(*ep, YASM_EXPR_FLOAT)) {
+       yasm__error(bc->line, N_("floating point expression too complex"));
+       return 1;
+    }
+
+    yasm__error(bc->line, N_("xdf: relocation too complex"));
+    return 1;
+}
+
+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;
+    unsigned long multiple;
+    unsigned long i;
+    int gap;
+
+    assert(info != NULL);
+
+    bigbuf = yasm_bc_tobytes(bc, info->buf, &size, &multiple, &gap, info,
+                            xdf_objfmt_output_expr, 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 += multiple*size;
+
+    /* Warn that gaps are converted to 0 and write out the 0's. */
+    if (gap) {
+       unsigned long left;
+       yasm__warning(YASM_WARN_GENERAL, bc->line,
+           N_("uninitialized space: zeroing"));
+       /* Write out in chunks */
+       memset(info->buf, 0, REGULAR_OUTBUF_SIZE);
+       left = multiple*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 multiple copies of buf (or bigbuf if non-NULL) to file */
+       for (i=0; i<multiple; i++)
+           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;
+    yasm_bytecode *last;
+
+    /* FIXME: Don't output absolute sections into the section table */
+    if (yasm_section_is_absolute(sect))
+       return 0;
+
+    assert(info != NULL);
+    xsd = yasm_section_get_data(sect, &xdf_section_data_cb);
+    assert(xsd != NULL);
+
+    last = yasm_section_bcs_last(sect);
+    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 = last->offset + last->len;
+    } 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, xdf_objfmt_output_bytecode);
+
+       /* Sanity check final section size */
+       if (xsd->size != (last->offset + last->len))
+           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;
+
+    STAILQ_FOREACH(reloc, &xsd->relocs, link) {
+       unsigned char *localbuf = info->buf;
+       /*@null@*/ xdf_symrec_data *xsymd;
+
+       xsymd = yasm_symrec_get_data(reloc->sym, &xdf_symrec_data_cb);
+       if (!xsymd)
+           yasm_internal_error(
+               N_("xdf: no symbol data for relocated symbol"));
+
+       YASM_WRITE_32_L(localbuf, reloc->addr);     /* 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);
+    }
+
+    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;
+    yasm_objfmt_xdf *objfmt_xdf;
+    /*@dependent@*/ /*@null@*/ xdf_section_data *xsd;
+    /*@null@*/ xdf_symrec_data *xsymd;
+    unsigned char *localbuf;
+
+    /* Don't output absolute sections into the section table */
+    if (yasm_section_is_absolute(sect))
+       return 0;
+
+    assert(info != NULL);
+    objfmt_xdf = info->objfmt_xdf;
+    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, 0);
+       localbuf += 8;                          /* physical address */
+    } else {
+       YASM_WRITE_32_L(localbuf, 0);
+       YASM_WRITE_32_L(localbuf, 0);
+    }
+    YASM_WRITE_16_L(localbuf, xsd->align);     /* 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, 32, 1, info->f);
+
+    return 0;
+}
+
+static void
+xdf_objfmt_output(yasm_objfmt *objfmt, FILE *f, const char *obj_filename,
+                  int all_syms, /*@unused@*/ yasm_dbgfmt *df)
+{
+    yasm_objfmt_xdf *objfmt_xdf = (yasm_objfmt_xdf *)objfmt;
+    xdf_objfmt_output_info info;
+    unsigned char *localbuf;
+    unsigned long symtab_count = 0;
+    unsigned long strtab_offset;
+    xdf_symtab_entry *entry;
+
+    info.objfmt_xdf = objfmt_xdf;
+    info.f = f;
+    info.buf = yasm_xmalloc(REGULAR_OUTBUF_SIZE);
+
+    /* Allocate space for headers by seeking forward */
+    if (fseek(f, (long)(16+32*(objfmt_xdf->parse_scnum)), SEEK_SET) < 0) {
+       yasm__fatal(N_("could not seek on output file"));
+       /*@notreached@*/
+       return;
+    }
+
+    /* Symbol table */
+    all_syms = 1;      /* force all syms into symbol table */
+    if (all_syms) {
+       /* Need to put all local syms into XDF symbol table */
+       yasm_symtab_traverse(objfmt_xdf->symtab, objfmt_xdf,
+                            xdf_objfmt_append_local_sym);
+    }
+
+    /* Get number of symbols */
+    if (STAILQ_EMPTY(&objfmt_xdf->xdf_symtab))
+       symtab_count = 0;
+    else {
+       /*@null@*/ /*@dependent@*/ xdf_symrec_data *sym_data_prev;
+       entry = STAILQ_LAST(&objfmt_xdf->xdf_symtab, xdf_symtab_entry, link);
+       sym_data_prev = yasm_symrec_get_data(entry->sym, &xdf_symrec_data_cb);
+       assert(sym_data_prev != NULL);
+       symtab_count = sym_data_prev->index + 1;
+    }
+
+    /* Get file offset of start of string table */
+    strtab_offset = 16+32*(objfmt_xdf->parse_scnum)+16*symtab_count;
+
+    STAILQ_FOREACH(entry, &objfmt_xdf->xdf_symtab, link) {
+       const char *name = yasm_symrec_get_name(entry->sym);
+       const yasm_expr *equ_val;
+       const yasm_intnum *intn;
+       size_t len = strlen(name);
+       /*@dependent@*/ /*@null@*/ xdf_symrec_data *xsymd;
+       unsigned long value = 0;
+       long scnum = -3;        /* -3 = debugging symbol */
+       /*@dependent@*/ /*@null@*/ yasm_section *sect;
+       /*@dependent@*/ /*@null@*/ yasm_bytecode *precbc;
+       yasm_sym_vis vis = yasm_symrec_get_visibility(entry->sym);
+       unsigned long flags = 0;
+
+       /* Get symrec's of_data (needed for storage class) */
+       xsymd = yasm_symrec_get_data(entry->sym, &xdf_symrec_data_cb);
+       if (!xsymd)
+           yasm_internal_error(N_("xdf: expected sym data to be present"));
+
+       if (vis & YASM_SYM_GLOBAL)
+           flags = XDF_SYM_GLOBAL;
+
+       /* Look at symrec for value/scnum/etc. */
+       if (yasm_symrec_get_label(entry->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 if (yasm_section_is_absolute(sect)) {
+                   yasm_expr *abs_start;
+
+                   abs_start = yasm_expr_copy(yasm_section_get_start(sect));
+                   intn = yasm_expr_get_intnum(&abs_start,
+                                               yasm_common_calc_bc_dist);
+                   if (!intn)
+                       yasm__error(abs_start->line,
+                           N_("absolute section start not an integer expression"));
+                   else
+                       value = yasm_intnum_get_uint(intn);
+                   yasm_expr_destroy(abs_start);
+
+                   flags |= XDF_SYM_EQU;
+                   scnum = -2; /* -2 = absolute symbol */
+               } else
+                   yasm_internal_error(N_("didn't understand section"));
+               if (precbc)
+                   value += precbc->offset + precbc->len;
+           }
+       } else if ((equ_val = yasm_symrec_get_equ(entry->sym))) {
+           yasm_expr *equ_val_copy = yasm_expr_copy(equ_val);
+           intn = yasm_expr_get_intnum(&equ_val_copy,
+                                       yasm_common_calc_bc_dist);
+           if (!intn) {
+               if (vis & YASM_SYM_GLOBAL)
+                   yasm__error(equ_val->line,
+                       N_("global EQU value not an integer expression"));
+           } 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, strtab_offset); /* string table offset */
+       strtab_offset += len+1;
+       YASM_WRITE_32_L(localbuf, flags);       /* flags */
+       fwrite(info.buf, 16, 1, f);
+    }
+
+    /* String table */
+    STAILQ_FOREACH(entry, &objfmt_xdf->xdf_symtab, link) {
+       const char *name = yasm_symrec_get_name(entry->sym);
+       size_t len = strlen(name);
+       fwrite(name, len+1, 1, f);
+    }
+
+    /* Section data/relocs */
+    if (yasm_object_sections_traverse(objfmt_xdf->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, strtab_offset-16);
+    fwrite(info.buf, 16, 1, f);
+
+    yasm_object_sections_traverse(objfmt_xdf->object, &info,
+                                 xdf_objfmt_output_secthead);
+
+    yasm_xfree(info.buf);
+}
+
+static void
+xdf_objfmt_destroy(yasm_objfmt *objfmt)
+{
+    yasm_objfmt_xdf *objfmt_xdf = (yasm_objfmt_xdf *)objfmt;
+    xdf_symtab_entry *entry1, *entry2;
+
+    /* Delete local symbol table */
+    entry1 = STAILQ_FIRST(&objfmt_xdf->xdf_symtab);
+    while (entry1 != NULL) {
+       entry2 = STAILQ_NEXT(entry1, link);
+       yasm_xfree(entry1);
+       entry1 = entry2;
+    }
+    yasm_xfree(objfmt);
+}
+
+static /*@observer@*/ /*@null@*/ yasm_section *
+xdf_objfmt_section_switch(yasm_objfmt *objfmt, yasm_valparamhead *valparams,
+                           /*@unused@*/ /*@null@*/
+                           yasm_valparamhead *objext_valparams,
+                           unsigned long line)
+{
+    yasm_objfmt_xdf *objfmt_xdf = (yasm_objfmt_xdf *)objfmt;
+    yasm_valparam *vp = yasm_vps_first(valparams);
+    yasm_section *retval;
+    int isnew;
+    /*@dependent@*/ /*@null@*/ const yasm_intnum *absaddr = NULL;
+    unsigned int addralign = 0;
+    unsigned long flags = 0;
+    int flags_override = 0;
+    char *sectname;
+    int resonly = 0;
+
+    if (!vp || vp->param || !vp->val)
+       return NULL;
+
+    sectname = vp->val;
+
+    while ((vp = yasm_vps_next(vp))) {
+       flags_override = 1;
+       if (yasm__strcasecmp(vp->val, "use16") == 0) {
+           flags &= ~(XDF_SECT_USE_32|XDF_SECT_USE_64);
+           flags |= XDF_SECT_USE_16;
+           yasm_arch_set_var(objfmt_xdf->arch, "mode_bits", 16);
+       } else if (yasm__strcasecmp(vp->val, "use32") == 0) {
+           flags &= ~(XDF_SECT_USE_16|XDF_SECT_USE_64);
+           flags |= XDF_SECT_USE_32;
+           yasm_arch_set_var(objfmt_xdf->arch, "mode_bits", 32);
+       } else if (yasm__strcasecmp(vp->val, "use64") == 0) {
+           flags &= ~(XDF_SECT_USE_16|XDF_SECT_USE_32);
+           flags |= XDF_SECT_USE_64;
+           yasm_arch_set_var(objfmt_xdf->arch, "mode_bits", 64);
+       } else if (yasm__strcasecmp(vp->val, "bss") == 0) {
+           flags |= XDF_SECT_BSS;
+       } else if (yasm__strcasecmp(vp->val, "flat") == 0) {
+           flags |= XDF_SECT_FLAT;
+       } else if (yasm__strcasecmp(vp->val, "absolute") == 0 && vp->param) {
+           flags |= XDF_SECT_ABSOLUTE;
+           absaddr = yasm_expr_get_intnum(&vp->param, NULL);
+           if (!absaddr) {
+               yasm__error(line, N_("argument to `%s' is not an integer"),
+                           vp->val);
+               return NULL;
+           }
+       } else if (yasm__strcasecmp(vp->val, "align") == 0 && vp->param) {
+           /*@dependent@*/ /*@null@*/ const yasm_intnum *align;
+           unsigned long bitcnt;
+
+           align = yasm_expr_get_intnum(&vp->param, NULL);
+           if (!align) {
+               yasm__error(line, N_("argument to `%s' is not a power of two"),
+                           vp->val);
+               return NULL;
+           }
+           addralign = yasm_intnum_get_uint(align);
+
+           /* Check to see if alignment is a power of two.
+            * This can be checked by seeing if only one bit is set.
+            */
+           BitCount(bitcnt, addralign);
+           if (bitcnt > 1) {
+               yasm__error(line, N_("argument to `%s' is not a power of two"),
+                           vp->val);
+               return NULL;
+           }
+
+           /* Check to see if alignment is supported size */
+           if (addralign > 4096) {
+               yasm__error(line,
+                           N_("XDF does not support alignments > 4096"));
+               return NULL;
+           }
+       } else
+           yasm__warning(YASM_WARN_GENERAL, line,
+                         N_("Unrecognized qualifier `%s'"), vp->val);
+    }
+
+    retval = yasm_object_get_general(objfmt_xdf->object, sectname, 0, resonly,
+                                    &isnew, line);
+
+    if (isnew) {
+       xdf_section_data *data;
+       yasm_symrec *sym;
+
+       data = yasm_xmalloc(sizeof(xdf_section_data));
+       data->scnum = objfmt_xdf->parse_scnum++;
+       data->align = addralign;
+       data->flags = flags;
+       if (absaddr)
+           data->addr = yasm_intnum_copy(absaddr);
+       else
+           data->addr = NULL;
+       data->scnptr = 0;
+       data->size = 0;
+       data->relptr = 0;
+       data->nreloc = 0;
+       STAILQ_INIT(&data->relocs);
+       yasm_section_add_data(retval, &xdf_section_data_cb, data);
+
+       sym =
+           yasm_symtab_define_label(objfmt_xdf->symtab, sectname,
+                                    yasm_section_bcs_first(retval), 1, line);
+       xdf_objfmt_symtab_append(objfmt_xdf, sym);
+       data->sym = sym;
+    } else if (flags_override)
+       yasm__warning(YASM_WARN_GENERAL, line,
+                     N_("section flags ignored on section redeclaration"));
+    return retval;
+}
+
+static void
+xdf_section_data_destroy(void *data)
+{
+    xdf_section_data *xsd = (xdf_section_data *)data;
+    xdf_reloc *r1, *r2;
+    if (xsd->addr)
+       yasm_intnum_destroy(xsd->addr);
+    r1 = STAILQ_FIRST(&xsd->relocs);
+    while (r1 != NULL) {
+       r2 = STAILQ_NEXT(r1, link);
+       yasm_xfree(r1);
+       r1 = r2;
+    }
+    yasm_xfree(data);
+}
+
+static void
+xdf_section_data_print(void *data, FILE *f, int indent_level)
+{
+    xdf_section_data *xsd = (xdf_section_data *)data;
+    xdf_reloc *reloc;
+    unsigned long relocnum = 0;
+
+    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, "%*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);
+    fprintf(f, "%*srelocs:\n", indent_level, "");
+    STAILQ_FOREACH(reloc, &xsd->relocs, link) {
+       fprintf(f, "%*sReloc %lu:\n", indent_level+1, "", relocnum++);
+       fprintf(f, "%*ssym=\n", indent_level+2, "");
+       yasm_symrec_print(reloc->sym, f, indent_level+3);
+       fprintf(f, "%*stype=", indent_level+2, "");
+       switch (reloc->type) {
+           case XDF_RELOC_FLAT:
+               printf("Flat");
+               break;
+           case XDF_RELOC_REL:
+               printf("Rel");
+               break;
+           case XDF_RELOC_WRT:
+               printf("WRT");
+               break;
+           case XDF_RELOC_RIP:
+               printf("RIP");
+               break;
+           case XDF_RELOC_SEG:
+               printf("Seg");
+               break;
+           default:
+               printf("Other");
+               break;
+       }
+       fprintf(f, "\n%*ssize=%d\n", indent_level+2, "", reloc->size);
+       fprintf(f, "%*sshift=%d\n", indent_level+2, "", reloc->shift);
+    }
+}
+
+static yasm_symrec *
+xdf_objfmt_extern_declare(yasm_objfmt *objfmt, const char *name, /*@unused@*/
+                          /*@null@*/ yasm_valparamhead *objext_valparams,
+                          unsigned long line)
+{
+    yasm_objfmt_xdf *objfmt_xdf = (yasm_objfmt_xdf *)objfmt;
+    yasm_symrec *sym;
+
+    sym = yasm_symtab_declare(objfmt_xdf->symtab, name, YASM_SYM_EXTERN,
+                             line);
+    xdf_objfmt_symtab_append(objfmt_xdf, sym);
+
+    return sym;
+}
+
+static yasm_symrec *
+xdf_objfmt_global_declare(yasm_objfmt *objfmt, const char *name, /*@unused@*/
+                          /*@null@*/ yasm_valparamhead *objext_valparams,
+                          unsigned long line)
+{
+    yasm_objfmt_xdf *objfmt_xdf = (yasm_objfmt_xdf *)objfmt;
+    yasm_symrec *sym;
+
+    sym = yasm_symtab_declare(objfmt_xdf->symtab, name, YASM_SYM_GLOBAL,
+                             line);
+    xdf_objfmt_symtab_append(objfmt_xdf, sym);
+
+    return sym;
+}
+
+static yasm_symrec *
+xdf_objfmt_common_declare(yasm_objfmt *objfmt, const char *name,
+                          /*@only@*/ yasm_expr *size, /*@unused@*/ /*@null@*/
+                          yasm_valparamhead *objext_valparams,
+                          unsigned long line)
+{
+    yasm_objfmt_xdf *objfmt_xdf = (yasm_objfmt_xdf *)objfmt;
+    yasm_symrec *sym;
+
+    yasm_expr_destroy(size);
+    yasm__error(line,
+       N_("XDF object format does not support common variables"));
+
+    sym = yasm_symtab_declare(objfmt_xdf->symtab, name, YASM_SYM_COMMON, line);
+    return sym;
+}
+
+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);
+}
+
+static int
+xdf_objfmt_directive(/*@unused@*/ yasm_objfmt *objfmt,
+                     /*@unused@*/ const char *name,
+                     /*@unused@*/ yasm_valparamhead *valparams,
+                     /*@unused@*/ /*@null@*/
+                     yasm_valparamhead *objext_valparams,
+                     /*@unused@*/ unsigned long line)
+{
+    return 1;  /* no objfmt directives */
+}
+
+
+/* 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 = {
+    YASM_OBJFMT_VERSION,
+    "Extended Dynamic Object",
+    "xdf",
+    "xdf",
+    ".text",
+    32,
+    xdf_objfmt_dbgfmt_keywords,
+    "null",
+    xdf_objfmt_create,
+    xdf_objfmt_output,
+    xdf_objfmt_destroy,
+    xdf_objfmt_section_switch,
+    xdf_objfmt_extern_declare,
+    xdf_objfmt_global_declare,
+    xdf_objfmt_common_declare,
+    xdf_objfmt_directive
+};
diff --git a/tools/xdf/xdf.h b/tools/xdf/xdf.h
new file mode 100644 (file)
index 0000000..d52bc75
--- /dev/null
@@ -0,0 +1,123 @@
+/* XDF - Extended Dynamic Object Format */
+/* Version 1.3 */
+/* $Id$ */
+
+/* FILE HEADER        */
+/* SECTION HEADERS [] */
+/* SYMBOL TABLE    [] */
+/* STRINGS            */
+/*                    */
+/* SECTION DATA       */
+/* SECTION REL     [] */
+/*                    */
+/* SECTION DATA       */
+/* SECTION REL     [] */
+/*                    */
+/* ...                */
+
+#ifndef XDF_H_INCLUDED
+#define XDF_H_INCLUDED
+
+typedef unsigned char      u8;
+typedef unsigned short     u16;
+typedef unsigned int       u32;
+typedef unsigned long long u64;
+
+typedef enum {
+
+  XDF_MAGIC = 0x87654321
+
+} xdf_magic;
+
+
+typedef enum {
+  
+  XDF_SECT_ABSOLUTE = 0x01,  /* Segment has an absolute offset */
+  XDF_SECT_FLAT     = 0x02,  /* Data displacements relative to 0, otherwise relative to segment */
+  XDF_SECT_BSS      = 0x04,  /* Segment has no data */
+
+  XDF_SECT_USE_16   = 0x10,
+  XDF_SECT_USE_32   = 0x20,
+  XDF_SECT_USE_64   = 0x40,
+
+} xdf_sect_flags;
+
+typedef enum {
+
+  XDF_SYM_EXTERN = 1,  /* External Symbol */
+  XDF_SYM_GLOBAL = 2,  /* Global Symbol   */
+  XDF_SYM_EQU    = 4,  /* EQUate Symbol (value, not address) */
+
+} xdf_sym_flags;
+
+typedef enum {
+
+  XDF_RELOC_FLAT = 1,  /* DISP = ADDRESS - 0                 (Relative to 0)                     */
+  XDF_RELOC_REL  = 2,  /* DISP = ADDRESS - SEGMENT           (Relative to a segment)             */
+  XDF_RELOC_WRT  = 4,  /* DISP = ADDRESS - SYMBOL            (Relative to a symbol)              */
+  XDF_RELOC_RIP  = 8,  /* DISP = ADDRESS - RIP - RELOC_SIZE  (Relative to end of an instruction) */
+  XDF_RELOC_SEG  = 16, /* DISP = SEGMENT/SELECTOR OF SYMBOL  (Not symbol itself, but which segment it's in) */
+
+} xdf_rtype;
+
+typedef enum {  
+
+  XDF_RELOC_8  = 1,         
+  XDF_RELOC_16 = 2,      
+  XDF_RELOC_32 = 4,      
+  XDF_RELOC_64 = 8,
+
+} xdf_rsize;
+
+
+typedef struct {      /* 16 bytes */
+
+  u32 f_magic;        /* magic number                                  */
+  u32 f_nsect;        /* number of sections                            */
+  u32 f_nsyms;        /* number of symtab entries                      */
+  u32 f_size;         /* size of sect headers + symbol table + strings */
+
+} FILE_HEADER;
+
+
+typedef struct {     /* 32 bytes */
+
+  u32 s_name_idx;    /* section name in symtab          */
+  u64 s_addr;        /* physical address                */
+  u16 s_align;       /* section alignment (0 ... 4096)  */
+  u16 s_flags;       /* flags                           */
+
+  u32 s_data_off;    /* file offset to section data     */
+  u32 s_data_size;   /* section data size               */  
+  u32 s_reltab_off;  /* file offset to relocation table */
+  u32 s_num_reloc;   /* number of relocations entries   */
+
+} SECTION_HEADER;
+
+
+typedef struct {     /* 16 bytes */
+
+  u32 e_sect_idx;    /* section index to which symbol belongs (-1 = EXTERN) */
+  u32 e_sect_off;    /* symbol offset into section data        */
+  u32 e_name_off;    /* file offset to null terminated strings */
+  u32 e_flags;       /* EXTERN, GLOBAL */
+
+} SYMBOL_ENTRY;
+
+
+typedef struct {     /* 16 bytes */
+
+  u32 r_off;         /* offset into current section          */
+  u32 r_targ_idx;    /* target symbol                        */
+  u32 r_base_idx;    /* base symbol if WRT                   */
+  u8  r_type;        /* type of relocation (ABS,SEG,RIP,WRT) */
+  u8  r_size;        /* size of relocation (1,2,4,8)         */
+  u8  r_shift;       /* relocation shift   (0,4,8,16,24,32)  */
+  u8  r_flags;       
+
+} RELOCATION_ENTRY;
+
+
+#endif /* XDF_H_INCLUDED */
+
+
diff --git a/tools/xdf/xdfdump.c b/tools/xdf/xdfdump.c
new file mode 100644 (file)
index 0000000..4e8ef65
--- /dev/null
@@ -0,0 +1,231 @@
+/* $Id$
+ * Extended Dynamic Object format dumper
+ *
+ *  Copyright (C) 2004  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 <stdio.h>
+#include <stdlib.h>
+
+#include "xdf.h"
+
+void
+print_file_header(const FILE_HEADER *filehead)
+{
+    printf("File Header:\n");
+    printf("\tMagic=0x%08X\n", filehead->f_magic);
+    printf("\tNumber of Sections=%d\n", filehead->f_nsect);
+    printf("\tNumber of Symbols=%d\n", filehead->f_nsyms);
+    printf("\tTotal Headers Size=%d\n", filehead->f_size);
+}
+
+const char *
+get_syment_name(const SYMBOL_ENTRY *syment, FILE *f)
+{
+    static char symname[256];
+    long oldpos = ftell(f);
+    fseek(f, syment->e_name_off, SEEK_SET);
+    fread(symname, 256, 1, f);
+    symname[255] = '\0';
+    fseek(f, oldpos, SEEK_SET);
+    return symname;
+}
+
+const char *
+get_sym_name(u32 idx, FILE *f, size_t symtab_off)
+{
+    SYMBOL_ENTRY syment;
+    long oldpos = ftell(f);
+    fseek(f, symtab_off+idx*sizeof(SYMBOL_ENTRY), SEEK_SET);
+    fread(&syment, sizeof(syment), 1, f);
+    fseek(f, oldpos, SEEK_SET);
+    return get_syment_name(&syment, f);
+}
+
+const char *
+get_sect_name(u32 idx, FILE *f, size_t symtab_off, size_t secttab_off)
+{
+    SECTION_HEADER secthead;
+    long oldpos = ftell(f);
+    fseek(f, secttab_off+idx*sizeof(SECTION_HEADER), SEEK_SET);
+    fread(&secthead, sizeof(secthead), 1, f);
+    fseek(f, oldpos, SEEK_SET);
+    return get_sym_name(secthead.s_name_idx, f, symtab_off);
+}
+
+void
+print_symbol(const SYMBOL_ENTRY *syment, FILE *f, size_t symtab_off,
+            size_t secttab_off)
+{
+    int first = 1;
+    printf("\tOffset=0x%08X Flags=", syment->e_sect_off);
+    if (syment->e_flags & XDF_SYM_EXTERN)
+       printf("%sEXTERN", first-->0?"":"|");
+    if (syment->e_flags & XDF_SYM_GLOBAL)
+       printf("%sGLOBAL", first-->0?"":"|");
+    if (syment->e_flags & XDF_SYM_EQU)
+       printf("%sEQU", first-->0?"":"|");
+    if (first>0)
+       printf("None");
+    printf(" Name=`%s' Section=", get_syment_name(syment, f));
+    if ((long)syment->e_sect_idx < 0)
+       printf("%d\n", syment->e_sect_idx);
+    else
+       printf("`%s' (%d)\n",
+              get_sect_name(syment->e_sect_idx, f, symtab_off, secttab_off),
+              syment->e_sect_idx);
+}
+
+void
+print_reloc(const RELOCATION_ENTRY *relocent, FILE *f, size_t symtab_off)
+{
+    const char *type = "UNK";
+    switch (relocent->r_type) {
+       case XDF_RELOC_FLAT:
+           type = "FLT";
+           break;
+       case XDF_RELOC_REL:
+           type = "REL";
+           break;
+       case XDF_RELOC_WRT:
+           type = "WRT";
+           break;
+       case XDF_RELOC_RIP:
+           type = "RIP";
+           break;
+       case XDF_RELOC_SEG:
+           type = "SEG";
+           break;
+    }
+    printf("\t Offset=0x%08X Type=%s Size=%d Shift=%d Target=`%s' (%d)", 
+          relocent->r_off, type, relocent->r_size, relocent->r_shift,
+          get_sym_name(relocent->r_targ_idx, f, symtab_off),
+          relocent->r_targ_idx);
+    if (relocent->r_type == XDF_RELOC_WRT)
+       printf(" Base=`%s' (%d)",
+          get_sym_name(relocent->r_base_idx, f, symtab_off),
+          relocent->r_base_idx);
+    printf("\n");
+}
+
+void
+print_section(const SECTION_HEADER *secthead, FILE *f, size_t symtab_off)
+{
+    int first = 1;
+    u32 i;
+    printf("Section `%s' (section name symtab %d):\n",
+          get_sym_name(secthead->s_name_idx, f, symtab_off),
+          secthead->s_name_idx);
+    printf("\tPhysical Address=0x%016llX\n", secthead->s_addr);
+    printf("\tAlign=%d\n", secthead->s_align);
+    printf("\tFlags=");
+    if (secthead->s_flags & XDF_SECT_ABSOLUTE)
+       printf("%sABSOLUTE", first-->0?"":"|");
+    if (secthead->s_flags & XDF_SECT_FLAT)
+       printf("%sFLAT", first-->0?"":"|");
+    if (secthead->s_flags & XDF_SECT_BSS)
+       printf("%sBSS", first-->0?"":"|");
+    if (secthead->s_flags & XDF_SECT_USE_16)
+       printf("%sUSE16", first-->0?"":"|");
+    if (secthead->s_flags & XDF_SECT_USE_32)
+       printf("%sUSE32", first-->0?"":"|");
+    if (secthead->s_flags & XDF_SECT_USE_64)
+       printf("%sUSE64", first-->0?"":"|");
+    if (first>0)
+       printf("None");
+    printf("\n\tData Offset=0x%08X\n", secthead->s_data_off);
+    printf("\tData Size=%d\n", secthead->s_data_size);
+    if (!(secthead->s_flags & XDF_SECT_BSS) && secthead->s_data_size > 0) {
+       printf("\tSection Data:");
+       long oldpos = ftell(f);
+       fseek(f, secthead->s_data_off, SEEK_SET);
+       for (i=0; i<secthead->s_data_size; i++) {
+           if (i % 16 == 0)
+               printf("\n\t\t%08X:", i);
+           if (i % 2 == 0)
+               printf(" ");
+           printf("%02X", fgetc(f));
+       }
+       printf("\n");
+       fseek(f, oldpos, SEEK_SET);
+    }
+    printf("\tReloc Table Offset=0x%08X\n", secthead->s_reltab_off);
+    printf("\tNum Relocs=%d\n", secthead->s_num_reloc);
+    if (secthead->s_num_reloc > 0) {
+       printf("\tRelocations:\n");
+       long oldpos = ftell(f);
+       fseek(f, secthead->s_reltab_off, SEEK_SET);
+       for (i=0; i<secthead->s_num_reloc; i++) {
+           RELOCATION_ENTRY relocent;
+           fread(&relocent, sizeof(relocent), 1, f);
+           print_reloc(&relocent, f, symtab_off);
+       }
+       fseek(f, oldpos, SEEK_SET);
+    }
+}
+
+int
+main(int argc, char **argv)
+{
+    FILE *f;
+    FILE_HEADER filehead;
+    size_t symtab_off;
+    u32 i;
+
+    if (argc != 2) {
+       fprintf(stderr, "Usage: %s <xdf>\n", argv[0]);
+       return EXIT_FAILURE;
+    }
+
+    f = fopen(argv[1], "rb");
+    if (!f) {
+       fprintf(stderr, "Could not open `%s'\n", argv[1]);
+       return EXIT_FAILURE;
+    }
+
+    fread(&filehead, sizeof(filehead), 1, f);
+
+    if (filehead.f_magic != XDF_MAGIC) {
+       fprintf(stderr, "Magic number mismatch (expected %08X, got %08X\n",
+               XDF_MAGIC, filehead.f_magic);
+       return EXIT_FAILURE;
+    }
+
+    print_file_header(&filehead);
+    symtab_off = sizeof(FILE_HEADER)+filehead.f_nsect*sizeof(SECTION_HEADER);
+    for (i=0; i<filehead.f_nsect; i++) {
+       SECTION_HEADER secthead;
+       fread(&secthead, sizeof(secthead), 1, f);
+       print_section(&secthead, f, symtab_off);
+    }
+
+    printf("Symbol Table:\n");
+    for (i=0; i<filehead.f_nsyms; i++) {
+       SYMBOL_ENTRY syment;
+       fread(&syment, sizeof(syment), 1, f);
+       print_symbol(&syment, f, symtab_off, sizeof(FILE_HEADER));
+    }
+
+    return EXIT_SUCCESS;
+}
+