]> granicus.if.org Git - yasm/commitdiff
Merge [1333]-[1543] (inclusive) into new-optimizer branch. This results in
authorPeter Johnson <peter@tortall.net>
Wed, 31 May 2006 06:13:01 +0000 (06:13 -0000)
committerPeter Johnson <peter@tortall.net>
Wed, 31 May 2006 06:13:01 +0000 (06:13 -0000)
a temporary regression of functionality but will yield some benefits later
on (chief among them is easier eventual merging back to the mainline!).

svn path=/branches/new-optimizer/; revision=1545

30 files changed:
1  2 
frontends/yasm/yasm.c
libyasm.h
libyasm/Makefile.inc
libyasm/arch.h
libyasm/bc-align.c
libyasm/bc-data.c
libyasm/bc-incbin.c
libyasm/bc-insn.c
libyasm/bc-int.h
libyasm/bc-org.c
libyasm/bc-reserve.c
libyasm/bytecode.c
libyasm/bytecode.h
libyasm/intnum.c
libyasm/intnum.h
libyasm/section.c
libyasm/section.h
modules/arch/lc3b/lc3barch.c
modules/arch/x86/x86arch.c
modules/arch/x86/x86arch.h
modules/arch/x86/x86bc.c
modules/arch/x86/x86expr.c
modules/arch/x86/x86id.c
modules/dbgfmts/Makefile.inc
modules/dbgfmts/codeview/cv-symline.c
modules/dbgfmts/codeview/cv-type.c
modules/dbgfmts/dwarf2/dwarf2-aranges.c
modules/dbgfmts/dwarf2/dwarf2-dbgfmt.c
modules/dbgfmts/dwarf2/dwarf2-info.c
modules/dbgfmts/dwarf2/dwarf2-line.c

index b00b62a5c0082581446929ea2cf682444f8f0247,f66e9c2625e9e51558939e38bcb08f7928b802fa..e32f136d416c1afe4a6b865168e3dc6470d9919a
@@@ -613,37 -627,20 +616,20 @@@ main(int argc, char *argv[]
      /* Check for undefined symbols */
      yasm_symtab_parser_finalize(yasm_object_get_symtab(object),
                                strcmp(cur_parser_module->keyword, "gas")==0,
-                               cur_objfmt);
-     if (yasm_get_num_errors(warning_error) > 0) {
-       yasm_errwarn_output_all(yasm_object_get_linemap(object), warning_error,
-                               print_yasm_error, print_yasm_warning);
-       cleanup(object);
-       return EXIT_FAILURE;
-     }
+                               cur_objfmt, errwarns);
+     check_errors(errwarns, object);
  
      /* Finalize parse */
-     yasm_object_finalize(object);
-     if (yasm_get_num_errors(warning_error) > 0) {
-       yasm_errwarn_output_all(yasm_object_get_linemap(object), warning_error,
-                               print_yasm_error, print_yasm_warning);
-       cleanup(object);
-       return EXIT_FAILURE;
-     }
+     yasm_object_finalize(object, errwarns);
+     check_errors(errwarns, object);
  
      /* Optimize */
 -    cur_optimizer_module->optimize(object, errwarns);
 +    yasm_object_optimize(object, cur_arch);
-     if (yasm_get_num_errors(warning_error) > 0) {
-       yasm_errwarn_output_all(yasm_object_get_linemap(object), warning_error,
-                               print_yasm_error, print_yasm_warning);
-       cleanup(object);
-       return EXIT_FAILURE;
-     }
+     check_errors(errwarns, object);
  
      /* generate any debugging information */
-     yasm_dbgfmt_generate(cur_dbgfmt);
+     yasm_dbgfmt_generate(cur_dbgfmt, errwarns);
+     check_errors(errwarns, object);
  
      /* open the object file for output (if not already opened by dbg objfmt) */
      if (!obj && strcmp(cur_objfmt_module->keyword, "dbg") != 0) {
diff --cc libyasm.h
Simple merge
index 09391eb88615a64b2989cd57e2ac1f4ba0ab9fb4,d411e71abd254a7808dd6c7a481315926d11656d..6582a57a58b27abc74e6167ebfda206cb839c8bc
@@@ -1,28 -1,33 +1,36 @@@
  # $Id$
  
+ libyasm_a_SOURCES += libyasm/arch.c
+ libyasm_a_SOURCES += libyasm/assocdat.c
+ libyasm_a_SOURCES += libyasm/bitvect.c
+ libyasm_a_SOURCES += libyasm/bc-align.c
+ libyasm_a_SOURCES += libyasm/bc-data.c
+ libyasm_a_SOURCES += libyasm/bc-incbin.c
+ libyasm_a_SOURCES += libyasm/bc-insn.c
+ libyasm_a_SOURCES += libyasm/bc-org.c
+ libyasm_a_SOURCES += libyasm/bc-reserve.c
  libyasm_a_SOURCES += libyasm/bytecode.c
+ libyasm_a_SOURCES += libyasm/errwarn.c
  libyasm_a_SOURCES += libyasm/expr.c
- libyasm_a_SOURCES += libyasm/symrec.c
  libyasm_a_SOURCES += libyasm/file.c
- libyasm_a_SOURCES += libyasm/section.c
- libyasm_a_SOURCES += libyasm/arch.c
- libyasm_a_SOURCES += libyasm/objfmt.c
- libyasm_a_SOURCES += libyasm/intnum.c
  libyasm_a_SOURCES += libyasm/floatnum.c
  libyasm_a_SOURCES += libyasm/hamt.c
- libyasm_a_SOURCES += libyasm/bitvect.c
- libyasm_a_SOURCES += libyasm/valparam.c
- libyasm_a_SOURCES += libyasm/errwarn.c
+ libyasm_a_SOURCES += libyasm/intnum.c
  libyasm_a_SOURCES += libyasm/linemgr.c
- libyasm_a_SOURCES += libyasm/assocdat.c
- libyasm_a_SOURCES += libyasm/xmalloc.c
- libyasm_a_SOURCES += libyasm/xstrdup.c
- libyasm_a_SOURCES += libyasm/strcasecmp.c
+ libyasm_a_SOURCES += libyasm/md5.c
  libyasm_a_SOURCES += libyasm/mergesort.c
+ libyasm_a_SOURCES += libyasm/phash.c
+ libyasm_a_SOURCES += libyasm/section.c
+ libyasm_a_SOURCES += libyasm/strcasecmp.c
  libyasm_a_SOURCES += libyasm/strsep.c
+ libyasm_a_SOURCES += libyasm/symrec.c
+ libyasm_a_SOURCES += libyasm/valparam.c
+ libyasm_a_SOURCES += libyasm/value.c
+ libyasm_a_SOURCES += libyasm/xmalloc.c
+ libyasm_a_SOURCES += libyasm/xstrdup.c
 +libyasm_a_SOURCES += libyasm/qq.c
 +libyasm_a_SOURCES += libyasm/stack.c
 +libyasm_a_SOURCES += libyasm/interval_tree.c
  libyasm_a_SOURCES += module.c
  
  module.c: $(top_srcdir)/libyasm/module.in genmodule$(EXEEXT) Makefile
@@@ -50,28 -61,23 +64,25 @@@ modinclude_HEADERS += libyasm/dbgfmt.
  modinclude_HEADERS += libyasm/errwarn.h
  modinclude_HEADERS += libyasm/expr.h
  modinclude_HEADERS += libyasm/expr-int.h
- modinclude_HEADERS += libyasm/symrec.h
- modinclude_HEADERS += libyasm/linemgr.h
- modinclude_HEADERS += libyasm/coretype.h
  modinclude_HEADERS += libyasm/file.h
- modinclude_HEADERS += libyasm/section.h
- modinclude_HEADERS += libyasm/arch.h
- modinclude_HEADERS += libyasm/dbgfmt.h
- modinclude_HEADERS += libyasm/objfmt.h
+ modinclude_HEADERS += libyasm/floatnum.h
+ modinclude_HEADERS += libyasm/hamt.h
+ modinclude_HEADERS += libyasm/intnum.h
+ modinclude_HEADERS += libyasm/linemgr.h
  modinclude_HEADERS += libyasm/listfmt.h
 -modinclude_HEADERS += libyasm/optimizer.h
+ modinclude_HEADERS += libyasm/md5.h
+ modinclude_HEADERS += libyasm/module.h
+ modinclude_HEADERS += libyasm/objfmt.h
  modinclude_HEADERS += libyasm/parser.h
+ modinclude_HEADERS += libyasm/phash.h
  modinclude_HEADERS += libyasm/preproc.h
- modinclude_HEADERS += libyasm/intnum.h
- modinclude_HEADERS += libyasm/floatnum.h
- modinclude_HEADERS += libyasm/hamt.h
- modinclude_HEADERS += libyasm/bitvect.h
+ modinclude_HEADERS += libyasm/section.h
+ modinclude_HEADERS += libyasm/symrec.h
  modinclude_HEADERS += libyasm/valparam.h
- modinclude_HEADERS += libyasm/compat-queue.h
- modinclude_HEADERS += libyasm/assocdat.h
- modinclude_HEADERS += libyasm/module.h
+ modinclude_HEADERS += libyasm/value.h
 +modinclude_HEADERS += libyasm/qq.h
 +modinclude_HEADERS += libyasm/stack.h
 +modinclude_HEADERS += libyasm/interval_tree.h
  
  EXTRA_DIST += libyasm/tests/Makefile.inc
  
diff --cc libyasm/arch.h
index 9e4efbb371dc8140e22115df0a0f02e47472c192,0d94c7b20ed1961aafba308c0b2925409dc5381d..99cc93fc32b8ef946e3d7dba203497e5d024dd1a
@@@ -248,11 -234,11 +234,17 @@@ typedef struct yasm_arch_module 
       */
      unsigned int wordsize;
  
 +    /** Long/short jump size descriminator.  Number of bytes (+/-) a short
 +     * jump can range over.  Used to size optimization FIFOs, so don't
 +     * make this extremely large (e.g. >1000).
 +     */
 +    const unsigned long jmpsize_threshold;
++
+     /** Worst case minimum instruction length in bytes.
+      * Call yasm_arch_min_insn_len() to get the minimum instruction length of
+      * a particular #yasm_arch.
+      */
+     unsigned int min_insn_len;
  } yasm_arch_module;
  
  #ifdef YASM_LIB_INTERNAL
@@@ -604,8 -520,8 +526,10 @@@ yasm_effaddr *yasm_arch_ea_create(yasm_
      (((yasm_arch_base *)arch)->module->keyword)
  #define yasm_arch_wordsize(arch) \
      (((yasm_arch_base *)arch)->module->wordsize)
 +#define yasm_arch_jmpsize_threshold(arch) \
 +    (((yasm_arch_base *)arch)->module->jmpsize_threshold)
+ #define yasm_arch_min_insn_len(arch) \
+     (((yasm_arch_base *)arch)->module->min_insn_len)
  
  #define yasm_arch_create(module, machine, parser, error) \
      module->create(machine, parser, error)
index 0000000000000000000000000000000000000000,ed2fab83f8f6191eabdcb27b6b2acf01af60036a..0506a506292fd92d3ca6c99bae2769fe96ae6806
mode 000000,100644..100644
--- /dev/null
@@@ -1,0 -1,224 +1,239 @@@
 -static yasm_bc_resolve_flags bc_align_resolve
 -    (yasm_bytecode *bc, int save, yasm_calc_bc_dist_func calc_bc_dist);
+ /*
+  * Align bytecode
+  *
+  *  Copyright (C) 2005-2006  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.
+  */
+ #define YASM_LIB_INTERNAL
+ #include "util.h"
+ /*@unused@*/ RCSID("$Id$");
+ #include "coretype.h"
+ #include "errwarn.h"
+ #include "intnum.h"
+ #include "expr.h"
+ #include "bytecode.h"
+ #include "bc-int.h"
+ typedef struct bytecode_align {
+     /*@only@*/ yasm_expr *boundary;   /* alignment boundary */
+     /* What to fill intervening locations with, NULL if using code_fill */
+     /*@only@*/ /*@null@*/ yasm_expr *fill;
+     /* Maximum number of bytes to skip, NULL if no maximum. */
+     /*@only@*/ /*@null@*/ yasm_expr *maxskip;
+     /* Code fill, NULL if using 0 fill */
+     /*@null@*/ const unsigned char **code_fill;
+ } bytecode_align;
+ static void bc_align_destroy(void *contents);
+ static void bc_align_print(const void *contents, FILE *f, int indent_level);
+ static void bc_align_finalize(yasm_bytecode *bc, yasm_bytecode *prev_bc);
 -    bc_align_resolve,
++static int bc_align_calc_len(yasm_bytecode *bc, yasm_bc_add_span_func add_span,
++                           void *add_span_data);
++static int bc_align_expand(yasm_bytecode *bc, int span, long old_val,
++                         long new_val, /*@out@*/ long *neg_thres,
++                         /*@out@*/ long *pos_thres);
+ static int bc_align_tobytes(yasm_bytecode *bc, unsigned char **bufp, void *d,
+                           yasm_output_value_func output_value,
+                           /*@null@*/ yasm_output_reloc_func output_reloc);
+ static const yasm_bytecode_callback bc_align_callback = {
+     bc_align_destroy,
+     bc_align_print,
+     bc_align_finalize,
 -static yasm_bc_resolve_flags
 -bc_align_resolve(yasm_bytecode *bc, int save,
 -               yasm_calc_bc_dist_func calc_bc_dist)
++    bc_align_calc_len,
++    bc_align_expand,
+     bc_align_tobytes,
+     0
+ };
+ static void
+ bc_align_destroy(void *contents)
+ {
+     bytecode_align *align = (bytecode_align *)contents;
+     if (align->boundary)
+       yasm_expr_destroy(align->boundary);
+     if (align->fill)
+       yasm_expr_destroy(align->fill);
+     if (align->maxskip)
+       yasm_expr_destroy(align->maxskip);
+     yasm_xfree(contents);
+ }
+ static void
+ bc_align_print(const void *contents, FILE *f, int indent_level)
+ {
+     const bytecode_align *align = (const bytecode_align *)contents;
+     fprintf(f, "%*s_Align_\n", indent_level, "");
+     fprintf(f, "%*sBoundary=", indent_level, "");
+     yasm_expr_print(align->boundary, f);
+     fprintf(f, "\n%*sFill=", indent_level, "");
+     yasm_expr_print(align->fill, f);
+     fprintf(f, "\n%*sMax Skip=", indent_level, "");
+     yasm_expr_print(align->maxskip, f);
+     fprintf(f, "\n");
+ }
+ static void
+ bc_align_finalize(yasm_bytecode *bc, yasm_bytecode *prev_bc)
+ {
+     bytecode_align *align = (bytecode_align *)bc->contents;
+     if (!yasm_expr_get_intnum(&align->boundary, NULL))
+       yasm_error_set(YASM_ERROR_NOT_CONSTANT,
+                      N_("align boundary must be a constant"));
+     if (align->fill && !yasm_expr_get_intnum(&align->fill, NULL))
+       yasm_error_set(YASM_ERROR_NOT_CONSTANT,
+                      N_("align fill must be a constant"));
+     if (align->maxskip && !yasm_expr_get_intnum(&align->maxskip, NULL))
+       yasm_error_set(YASM_ERROR_NOT_CONSTANT,
+                      N_("align maximum skip must be a constant"));
+ }
 -    return YASM_BC_RESOLVE_MIN_LEN;
++static int
++bc_align_calc_len(yasm_bytecode *bc, yasm_bc_add_span_func add_span,
++                void *add_span_data)
+ {
++    yasm_internal_error(N_("align not yet implemented"));
++#if 0
+     bytecode_align *align = (bytecode_align *)bc->contents;
+     unsigned long end;
+     unsigned long boundary =
+       yasm_intnum_get_uint(yasm_expr_get_intnum(&align->boundary, NULL));
+     if (boundary == 0) {
+       bc->len = 0;
+       return YASM_BC_RESOLVE_MIN_LEN;
+     }
+     end = bc->offset;
+     if (bc->offset & (boundary-1))
+       end = (bc->offset & ~(boundary-1)) + boundary;
+     bc->len = end - bc->offset;
+     if (align->maxskip) {
+       unsigned long maxskip =
+           yasm_intnum_get_uint(yasm_expr_get_intnum(&align->maxskip, NULL));
+       if ((end - bc->offset) > maxskip)
+           bc->len = 0;
+     }
++#endif
++    return 0;
++}
++
++static int
++bc_align_expand(yasm_bytecode *bc, int span, long old_val, long new_val,
++              /*@out@*/ long *neg_thres, /*@out@*/ long *pos_thres)
++{
++    yasm_internal_error(N_("align not yet implemented"));
++    return 0;
+ }
+ static int
+ bc_align_tobytes(yasm_bytecode *bc, unsigned char **bufp, void *d,
+                yasm_output_value_func output_value,
+                /*@unused@*/ yasm_output_reloc_func output_reloc)
+ {
+     bytecode_align *align = (bytecode_align *)bc->contents;
+     unsigned long len;
+     unsigned long boundary =
+       yasm_intnum_get_uint(yasm_expr_get_intnum(&align->boundary, NULL));
+     if (boundary == 0)
+       return 0;
+     else {
+       unsigned long end = bc->offset;
+       if (bc->offset & (boundary-1))
+           end = (bc->offset & ~(boundary-1)) + boundary;
+       len = end - bc->offset;
+       if (len == 0)
+           return 0;
+       if (align->maxskip) {
+           unsigned long maxskip =
+               yasm_intnum_get_uint(yasm_expr_get_intnum(&align->maxskip,
+                                                         NULL));
+           if (len > maxskip)
+               return 0;
+       }
+     }
+     if (align->fill) {
+       unsigned long v;
+       v = yasm_intnum_get_uint(yasm_expr_get_intnum(&align->fill, NULL));
+       memset(*bufp, (int)v, len);
+       *bufp += len;
+     } else if (align->code_fill) {
+       unsigned long maxlen = 15;
+       while (!align->code_fill[maxlen] && maxlen>0)
+           maxlen--;
+       if (maxlen == 0) {
+           yasm_error_set(YASM_ERROR_GENERAL,
+                          N_("could not find any code alignment size"));
+           return 1;
+       }
+       /* Fill with maximum code fill as much as possible */
+       while (len > maxlen) {
+           memcpy(*bufp, align->code_fill[maxlen], maxlen);
+           *bufp += maxlen;
+           len -= maxlen;
+       }
+       if (!align->code_fill[len]) {
+           yasm_error_set(YASM_ERROR_VALUE,
+                          N_("invalid alignment size %d"), len);
+           return 1;
+       }
+       /* Handle rest of code fill */
+       memcpy(*bufp, align->code_fill[len], len);
+       *bufp += len;
+     } else {
+       /* Just fill with 0 */
+       memset(*bufp, 0, len);
+       *bufp += len;
+     }
+     return 0;
+ }
+ yasm_bytecode *
+ yasm_bc_create_align(yasm_expr *boundary, yasm_expr *fill,
+                    yasm_expr *maxskip, const unsigned char **code_fill,
+                    unsigned long line)
+ {
+     bytecode_align *align = yasm_xmalloc(sizeof(bytecode_align));
+     align->boundary = boundary;
+     align->fill = fill;
+     align->maxskip = maxskip;
+     align->code_fill = code_fill;
+     return yasm_bc_create_common(&bc_align_callback, align, line);
+ }
index 0000000000000000000000000000000000000000,a253534d7b1ef0a92dde5513e950648da2230499..c6913bdce4839700efa295d4287276d74c5edec1
mode 000000,100644..100644
--- /dev/null
@@@ -1,0 -1,455 +1,456 @@@
 -static yasm_bc_resolve_flags bc_data_resolve
 -    (yasm_bytecode *bc, int save, yasm_calc_bc_dist_func calc_bc_dist);
+ /*
+  * Data (and LEB128) bytecode
+  *
+  *  Copyright (C) 2001-2006  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.
+  */
+ #define YASM_LIB_INTERNAL
+ #include "util.h"
+ /*@unused@*/ RCSID("$Id$");
+ #include "coretype.h"
+ #include "errwarn.h"
+ #include "intnum.h"
+ #include "expr.h"
+ #include "value.h"
+ #include "bytecode.h"
+ #include "arch.h"
+ #include "bc-int.h"
+ struct yasm_dataval {
+     /*@reldef@*/ STAILQ_ENTRY(yasm_dataval) link;
+     enum { DV_EMPTY, DV_VALUE, DV_RAW, DV_ULEB128, DV_SLEB128 } type;
+     union {
+       yasm_value val;
+       struct {
+           /*@only@*/ unsigned char *contents;
+           unsigned long len;
+       } raw;
+     } data;
+ };
+ typedef struct bytecode_data {
+     /* converted data (linked list) */
+     yasm_datavalhead datahead;
+ } bytecode_data;
+ static void bc_data_destroy(void *contents);
+ static void bc_data_print(const void *contents, FILE *f, int indent_level);
+ static void bc_data_finalize(yasm_bytecode *bc, yasm_bytecode *prev_bc);
 -    bc_data_resolve,
++static int bc_data_calc_len(yasm_bytecode *bc, yasm_bc_add_span_func add_span,
++                          void *add_span_data);
+ static int bc_data_tobytes(yasm_bytecode *bc, unsigned char **bufp, void *d,
+                          yasm_output_value_func output_value,
+                          /*@null@*/ yasm_output_reloc_func output_reloc);
+ static const yasm_bytecode_callback bc_data_callback = {
+     bc_data_destroy,
+     bc_data_print,
+     bc_data_finalize,
 -static yasm_bc_resolve_flags
 -bc_data_resolve(yasm_bytecode *bc, int save,
 -              yasm_calc_bc_dist_func calc_bc_dist)
++    bc_data_calc_len,
++    yasm_bc_expand_common,
+     bc_data_tobytes,
+     0
+ };
+ static void
+ bc_data_destroy(void *contents)
+ {
+     bytecode_data *bc_data = (bytecode_data *)contents;
+     yasm_dvs_destroy(&bc_data->datahead);
+     yasm_xfree(contents);
+ }
+ static void
+ bc_data_print(const void *contents, FILE *f, int indent_level)
+ {
+     const bytecode_data *bc_data = (const bytecode_data *)contents;
+     fprintf(f, "%*s_Data_\n", indent_level, "");
+     fprintf(f, "%*sElements:\n", indent_level+1, "");
+     yasm_dvs_print(&bc_data->datahead, f, indent_level+2);
+ }
+ static void
+ bc_data_finalize(yasm_bytecode *bc, yasm_bytecode *prev_bc)
+ {
+     bytecode_data *bc_data = (bytecode_data *)bc->contents;
+     yasm_dataval *dv;
+     yasm_intnum *intn;
+     /* Convert values from simple expr to value. */
+     STAILQ_FOREACH(dv, &bc_data->datahead, link) {
+       switch (dv->type) {
+           case DV_VALUE:
+               if (yasm_value_finalize(&dv->data.val)) {
+                   yasm_error_set(YASM_ERROR_TOO_COMPLEX,
+                                  N_("data expression too complex"));
+                   return;
+               }
+               break;
+           case DV_ULEB128:
+           case DV_SLEB128:
+               intn = yasm_expr_get_intnum(&dv->data.val.abs, NULL);
+               if (!intn) {
+                   yasm_error_set(YASM_ERROR_NOT_CONSTANT,
+                                  N_("LEB128 requires constant values"));
+                   return;
+               }
+               /* Warn for negative values in unsigned environment.
+                * This could be an error instead: the likelihood this is
+                * desired is very low!
+                */
+               if (yasm_intnum_sign(intn) == -1 && dv->type == DV_ULEB128)
+                   yasm_warn_set(YASM_WARN_GENERAL,
+                                 N_("negative value in unsigned LEB128"));
+               break;
+           default:
+               break;
+       }
+     }
+ }
 -    return YASM_BC_RESOLVE_MIN_LEN;
++static int
++bc_data_calc_len(yasm_bytecode *bc, yasm_bc_add_span_func add_span,
++               void *add_span_data)
+ {
+     bytecode_data *bc_data = (bytecode_data *)bc->contents;
+     yasm_dataval *dv;
+     yasm_intnum *intn;
+     /* Count up element sizes, rounding up string length. */
+     STAILQ_FOREACH(dv, &bc_data->datahead, link) {
+       switch (dv->type) {
+           case DV_EMPTY:
+               break;
+           case DV_VALUE:
+               bc->len += dv->data.val.size/8;
+               break;
+           case DV_RAW:
+               bc->len += dv->data.raw.len;
+               break;
+           case DV_ULEB128:
+           case DV_SLEB128:
+               intn = yasm_expr_get_intnum(&dv->data.val.abs, NULL);
+               if (!intn)
+                   yasm_internal_error(N_("non-constant in data_tobytes"));
+               bc->len +=
+                   yasm_intnum_size_leb128(intn, dv->type == DV_SLEB128);
+               break;
+       }
+     }
++    return 0;
+ }
+ static int
+ bc_data_tobytes(yasm_bytecode *bc, unsigned char **bufp, void *d,
+               yasm_output_value_func output_value,
+               /*@unused@*/ yasm_output_reloc_func output_reloc)
+ {
+     bytecode_data *bc_data = (bytecode_data *)bc->contents;
+     yasm_dataval *dv;
+     unsigned char *bufp_orig = *bufp;
+     yasm_intnum *intn;
+     unsigned int val_len;
+     STAILQ_FOREACH(dv, &bc_data->datahead, link) {
+       switch (dv->type) {
+           case DV_EMPTY:
+               break;
+           case DV_VALUE:
+               val_len = dv->data.val.size/8;
+               if (output_value(&dv->data.val, *bufp, val_len,
+                                (unsigned long)(*bufp-bufp_orig), bc, 1, d))
+                   return 1;
+               *bufp += val_len;
+               break;
+           case DV_RAW:
+               memcpy(*bufp, dv->data.raw.contents, dv->data.raw.len);
+               *bufp += dv->data.raw.len;
+               break;
+           case DV_ULEB128:
+           case DV_SLEB128:
+               intn = yasm_expr_get_intnum(&dv->data.val.abs, NULL);
+               if (!intn)
+                   yasm_internal_error(N_("non-constant in data_tobytes"));
+               *bufp +=
+                   yasm_intnum_get_leb128(intn, *bufp, dv->type == DV_SLEB128);
+       }
+     }
+     return 0;
+ }
+ yasm_bytecode *
+ yasm_bc_create_data(yasm_datavalhead *datahead, unsigned int size,
+                   int append_zero, yasm_arch *arch, unsigned long line)
+ {
+     bytecode_data *data = yasm_xmalloc(sizeof(bytecode_data));
+     yasm_bytecode *bc = yasm_bc_create_common(&bc_data_callback, data, line);
+     yasm_dataval *dv, *dv2, *dvo;
+     yasm_intnum *intn;
+     unsigned long len = 0, rlen, i;
+     yasm_dvs_initialize(&data->datahead);
+     /* Prescan input data for length, etc.  Careful: this needs to be
+      * precisely paired with the second loop.
+      */
+     STAILQ_FOREACH(dv, datahead, link) {
+       switch (dv->type) {
+           case DV_EMPTY:
+               break;
+           case DV_VALUE:
+           case DV_ULEB128:
+           case DV_SLEB128:
+               intn = yasm_expr_get_intnum(&dv->data.val.abs, NULL);
+               if (intn && dv->type == DV_VALUE && (arch || size == 1))
+                   len += size;
+               else if (intn && dv->type == DV_ULEB128)
+                   len += yasm_intnum_size_leb128(intn, 0);
+               else if (intn && dv->type == DV_SLEB128)
+                   len += yasm_intnum_size_leb128(intn, 1);
+               else {
+                   if (len > 0) {
+                       /* Create bytecode for all previous len */
+                       dvo = yasm_dv_create_raw(yasm_xmalloc(len), len);
+                       STAILQ_INSERT_TAIL(&data->datahead, dvo, link);
+                       len = 0;
+                   }
+                   /* Create bytecode for this value */
+                   dvo = yasm_xmalloc(sizeof(yasm_dataval));
+                   STAILQ_INSERT_TAIL(&data->datahead, dvo, link);
+               }
+               break;
+           case DV_RAW:
+               rlen = dv->data.raw.len;
+               /* find count, rounding up to nearest multiple of size */
+               rlen = (rlen + size - 1) / size;
+               len += rlen*size;
+               break;
+       }
+       if (append_zero)
+           len++;
+     }
+     /* Create final dataval for any trailing length */
+     if (len > 0) {
+       dvo = yasm_dv_create_raw(yasm_xmalloc(len), len);
+       STAILQ_INSERT_TAIL(&data->datahead, dvo, link);
+     }
+     /* Second iteration: copy data and delete input datavals. */
+     dv = STAILQ_FIRST(datahead);
+     dvo = STAILQ_FIRST(&data->datahead);
+     len = 0;
+     while (dv) {
+       switch (dv->type) {
+           case DV_EMPTY:
+               break;
+           case DV_VALUE:
+           case DV_ULEB128:
+           case DV_SLEB128:
+               intn = yasm_expr_get_intnum(&dv->data.val.abs, NULL);
+               if (intn && dv->type == DV_VALUE && (arch || size == 1)) {
+                   if (size == 1)
+                       yasm_intnum_get_sized(intn,
+                                             &dvo->data.raw.contents[len],
+                                             1, 8, 0, 0, 1);
+                   else
+                       yasm_arch_intnum_tobytes(arch, intn,
+                                                &dvo->data.raw.contents[len],
+                                                size, size*8, 0, bc, 1);
+                   yasm_value_delete(&dv->data.val);
+                   len += size;
+               } else if (intn && dv->type == DV_ULEB128) {
+                   len += yasm_intnum_get_leb128(intn,
+                                                 &dvo->data.raw.contents[len],
+                                                 0);
+               } else if (intn && dv->type == DV_SLEB128) {
+                   len += yasm_intnum_get_leb128(intn,
+                                                 &dvo->data.raw.contents[len],
+                                                 1);
+               } else {
+                   dvo->type = dv->type;
+                   dvo->data.val = dv->data.val;   /* structure copy */
+                   dvo->data.val.size = size*8;    /* remember size */
+                   dvo = STAILQ_NEXT(dvo, link);
+                   len = 0;
+               }
+               break;
+           case DV_RAW:
+               rlen = dv->data.raw.len;
+               memcpy(&dvo->data.raw.contents[len], dv->data.raw.contents,
+                      rlen);
+               yasm_xfree(dv->data.raw.contents);
+               len += rlen;
+               /* pad with 0's to nearest multiple of size */
+               rlen %= size;
+               if (rlen > 0) {
+                   rlen = size-rlen;
+                   for (i=0; i<rlen; i++)
+                       dvo->data.raw.contents[len++] = 0;
+               }
+               break;
+       }
+       if (append_zero)
+           dvo->data.raw.contents[len++] = 0;
+       dv2 = STAILQ_NEXT(dv, link);
+       yasm_xfree(dv);
+       dv = dv2;
+     }
+     return bc;
+ }
+ yasm_bytecode *
+ yasm_bc_create_leb128(yasm_datavalhead *datahead, int sign, unsigned long line)
+ {
+     yasm_dataval *dv;
+     /* Convert all values into LEB type, error on strings/raws */
+     STAILQ_FOREACH(dv, datahead, link) {
+       switch (dv->type) {
+           case DV_VALUE:
+               dv->type = sign ? DV_SLEB128 : DV_ULEB128;
+               break;
+           case DV_RAW:
+               yasm_error_set(YASM_ERROR_VALUE,
+                              N_("LEB128 does not allow string constants"));
+               break;
+           default:
+               break;
+       }
+     }
+     return yasm_bc_create_data(datahead, 0, 0, 0, line);
+ }
+ yasm_dataval *
+ yasm_dv_create_expr(yasm_expr *e)
+ {
+     yasm_dataval *retval = yasm_xmalloc(sizeof(yasm_dataval));
+     retval->type = DV_VALUE;
+     yasm_value_initialize(&retval->data.val, e, 0);
+     return retval;
+ }
+ yasm_dataval *
+ yasm_dv_create_raw(unsigned char *contents, unsigned long len)
+ {
+     yasm_dataval *retval = yasm_xmalloc(sizeof(yasm_dataval));
+     retval->type = DV_RAW;
+     retval->data.raw.contents = contents;
+     retval->data.raw.len = len;
+     return retval;
+ }
+ void
+ yasm_dvs_destroy(yasm_datavalhead *headp)
+ {
+     yasm_dataval *cur, *next;
+     cur = STAILQ_FIRST(headp);
+     while (cur) {
+       next = STAILQ_NEXT(cur, link);
+       switch (cur->type) {
+           case DV_VALUE:
+               yasm_value_delete(&cur->data.val);
+               break;
+           case DV_RAW:
+               yasm_xfree(cur->data.raw.contents);
+               break;
+           default:
+               break;
+       }
+       yasm_xfree(cur);
+       cur = next;
+     }
+     STAILQ_INIT(headp);
+ }
+ yasm_dataval *
+ yasm_dvs_append(yasm_datavalhead *headp, yasm_dataval *dv)
+ {
+     if (dv) {
+       STAILQ_INSERT_TAIL(headp, dv, link);
+       return dv;
+     }
+     return (yasm_dataval *)NULL;
+ }
+ void
+ yasm_dvs_print(const yasm_datavalhead *head, FILE *f, int indent_level)
+ {
+     yasm_dataval *cur;
+     unsigned long i;
+     STAILQ_FOREACH(cur, head, link) {
+       switch (cur->type) {
+           case DV_EMPTY:
+               fprintf(f, "%*sEmpty\n", indent_level, "");
+               break;
+           case DV_VALUE:
+               fprintf(f, "%*sValue:\n", indent_level, "");
+               yasm_value_print(&cur->data.val, f, indent_level+1);
+               break;
+           case DV_RAW:
+               fprintf(f, "%*sLength=%lu\n", indent_level, "",
+                       cur->data.raw.len);
+               fprintf(f, "%*sBytes=[", indent_level, "");
+               for (i=0; i<cur->data.raw.len; i++)
+                   fprintf(f, "0x%02x, ", cur->data.raw.contents[i]);
+               fprintf(f, "]\n");
+               break;
+           case DV_ULEB128:
+               fprintf(f, "%*sULEB128 value:\n", indent_level, "");
+               yasm_value_print(&cur->data.val, f, indent_level+1);
+               break;
+           case DV_SLEB128:
+               fprintf(f, "%*sSLEB128 value:\n", indent_level, "");
+               yasm_value_print(&cur->data.val, f, indent_level+1);
+               break;
+       }
+     }
+ }
+ /* Non-macro yasm_dvs_initialize() for non-YASM_LIB_INTERNAL users. */
+ #undef yasm_dvs_initialize
+ void
+ yasm_dvs_initialize(yasm_datavalhead *headp)
+ {
+     STAILQ_INIT(headp);
+ }
index 0000000000000000000000000000000000000000,fd7f79e3c2c869ad815ca066934dd8ed1bbe2430..7201f8df800928f018df9597abd7a722d22bec7a
mode 000000,100644..100644
--- /dev/null
@@@ -1,0 -1,271 +1,260 @@@
 -static yasm_bc_resolve_flags bc_incbin_resolve
 -    (yasm_bytecode *bc, int save, yasm_calc_bc_dist_func calc_bc_dist);
+ /*
+  * Incbin bytecode
+  *
+  *  Copyright (C) 2001-2006  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.
+  */
+ #define YASM_LIB_INTERNAL
+ #include "util.h"
+ /*@unused@*/ RCSID("$Id$");
+ #include "coretype.h"
+ #include "errwarn.h"
+ #include "intnum.h"
+ #include "expr.h"
+ #include "value.h"
+ #include "bytecode.h"
+ #include "bc-int.h"
+ typedef struct bytecode_incbin {
+     /*@only@*/ char *filename;                /* file to include data from */
+     /* starting offset to read from (NULL=0) */
+     /*@only@*/ /*@null@*/ yasm_expr *start;
+     /* maximum number of bytes to read (NULL=no limit) */
+     /*@only@*/ /*@null@*/ yasm_expr *maxlen;
+ } bytecode_incbin;
+ static void bc_incbin_destroy(void *contents);
+ static void bc_incbin_print(const void *contents, FILE *f, int indent_level);
+ static void bc_incbin_finalize(yasm_bytecode *bc, yasm_bytecode *prev_bc);
 -    bc_incbin_resolve,
++static int bc_incbin_calc_len(yasm_bytecode *bc, yasm_bc_add_span_func add_span,
++                            void *add_span_data);
+ static int bc_incbin_tobytes(yasm_bytecode *bc, unsigned char **bufp, void *d,
+                            yasm_output_value_func output_value,
+                            /*@null@*/ yasm_output_reloc_func output_reloc);
+ static const yasm_bytecode_callback bc_incbin_callback = {
+     bc_incbin_destroy,
+     bc_incbin_print,
+     bc_incbin_finalize,
 -static yasm_bc_resolve_flags
 -bc_incbin_resolve(yasm_bytecode *bc, int save,
 -                yasm_calc_bc_dist_func calc_bc_dist)
++    bc_incbin_calc_len,
++    yasm_bc_expand_common,
+     bc_incbin_tobytes,
+     0
+ };
+ static void
+ bc_incbin_destroy(void *contents)
+ {
+     bytecode_incbin *incbin = (bytecode_incbin *)contents;
+     yasm_xfree(incbin->filename);
+     yasm_expr_destroy(incbin->start);
+     yasm_expr_destroy(incbin->maxlen);
+     yasm_xfree(contents);
+ }
+ static void
+ bc_incbin_print(const void *contents, FILE *f, int indent_level)
+ {
+     const bytecode_incbin *incbin = (const bytecode_incbin *)contents;
+     fprintf(f, "%*s_IncBin_\n", indent_level, "");
+     fprintf(f, "%*sFilename=`%s'\n", indent_level, "",
+           incbin->filename);
+     fprintf(f, "%*sStart=", indent_level, "");
+     if (!incbin->start)
+       fprintf(f, "nil (0)");
+     else
+       yasm_expr_print(incbin->start, f);
+     fprintf(f, "%*sMax Len=", indent_level, "");
+     if (!incbin->maxlen)
+       fprintf(f, "nil (unlimited)");
+     else
+       yasm_expr_print(incbin->maxlen, f);
+     fprintf(f, "\n");
+ }
+ static void
+ bc_incbin_finalize(yasm_bytecode *bc, yasm_bytecode *prev_bc)
+ {
+     bytecode_incbin *incbin = (bytecode_incbin *)bc->contents;
+     yasm_value val;
+     if (yasm_value_finalize_expr(&val, incbin->start, 0))
+       yasm_error_set(YASM_ERROR_TOO_COMPLEX,
+                      N_("start expression too complex"));
+     else if (val.rel)
+       yasm_error_set(YASM_ERROR_NOT_ABSOLUTE,
+                      N_("start expression not absolute"));
+     incbin->start = val.abs;
+     if (yasm_value_finalize_expr(&val, incbin->maxlen, 0))
+       yasm_error_set(YASM_ERROR_TOO_COMPLEX,
+                      N_("maximum length expression too complex"));
+     else if (val.rel)
+       yasm_error_set(YASM_ERROR_NOT_ABSOLUTE,
+                      N_("maximum length expression not absolute"));
+     incbin->maxlen = val.abs;
+ }
 -    /*@null@*/ yasm_expr *temp;
 -    yasm_expr **tempp;
++static int
++bc_incbin_calc_len(yasm_bytecode *bc, yasm_bc_add_span_func add_span,
++                 void *add_span_data)
+ {
+     bytecode_incbin *incbin = (bytecode_incbin *)bc->contents;
+     FILE *f;
 -      if (save) {
 -          temp = NULL;
 -          tempp = &incbin->start;
 -      } else {
 -          temp = yasm_expr_copy(incbin->start);
 -          assert(temp != NULL);
 -          tempp = &temp;
 -      }
 -      num = yasm_expr_get_intnum(tempp, calc_bc_dist);
+     /*@dependent@*/ /*@null@*/ const yasm_intnum *num;
+     unsigned long start = 0, maxlen = 0xFFFFFFFFUL, flen;
+     /* Try to convert start to integer value */
+     if (incbin->start) {
 -      yasm_expr_destroy(temp);
 -      if (!num)
 -          return YASM_BC_RESOLVE_UNKNOWN_LEN;
++      num = yasm_expr_get_intnum(&incbin->start, NULL);
+       if (num)
+           start = yasm_intnum_get_uint(num);
 -      if (save) {
 -          temp = NULL;
 -          tempp = &incbin->maxlen;
 -      } else {
 -          temp = yasm_expr_copy(incbin->maxlen);
 -          assert(temp != NULL);
 -          tempp = &temp;
 -      }
 -      num = yasm_expr_get_intnum(tempp, calc_bc_dist);
++      if (!num) {
++          /* FIXME */
++          yasm_error_set(YASM_ERROR_NOT_IMPLEMENTED,
++                         N_("incbin does not yet understand non-constant"));
++          return -1;
++      }
+     }
+     /* Try to convert maxlen to integer value */
+     if (incbin->maxlen) {
 -      yasm_expr_destroy(temp);
 -      if (!num)
 -          return YASM_BC_RESOLVE_UNKNOWN_LEN;
++      num = yasm_expr_get_intnum(&incbin->maxlen, NULL);
+       if (num)
+           maxlen = yasm_intnum_get_uint(num);
 -      return YASM_BC_RESOLVE_ERROR | YASM_BC_RESOLVE_UNKNOWN_LEN;
++      if (!num) {
++          /* FIXME */
++          yasm_error_set(YASM_ERROR_NOT_IMPLEMENTED,
++                         N_("incbin does not yet understand non-constant"));
++          return -1;
++      }
+     }
+     /* FIXME: Search include path for filename.  Save full path back into
+      * filename if save is true.
+      */
+     /* Open file and determine its length */
+     f = fopen(incbin->filename, "rb");
+     if (!f) {
+       yasm_error_set(YASM_ERROR_IO,
+                      N_("`incbin': unable to open file `%s'"),
+                      incbin->filename);
 -      return YASM_BC_RESOLVE_ERROR | YASM_BC_RESOLVE_UNKNOWN_LEN;
++      return -1;
+     }
+     if (fseek(f, 0L, SEEK_END) < 0) {
+       yasm_error_set(YASM_ERROR_IO,
+                      N_("`incbin': unable to seek on file `%s'"),
+                      incbin->filename);
 -    return YASM_BC_RESOLVE_MIN_LEN;
++      return -1;
+     }
+     flen = (unsigned long)ftell(f);
+     fclose(f);
+     /* Compute length of incbin from start, maxlen, and len */
+     if (start > flen) {
+       yasm_warn_set(YASM_WARN_GENERAL,
+                     N_("`incbin': start past end of file `%s'"),
+                     incbin->filename);
+       start = flen;
+     }
+     flen -= start;
+     if (incbin->maxlen)
+       if (maxlen < flen)
+           flen = maxlen;
+     bc->len += flen;
++    return 0;
+ }
+ static int
+ bc_incbin_tobytes(yasm_bytecode *bc, unsigned char **bufp, void *d,
+                 yasm_output_value_func output_value,
+                 /*@unused@*/ yasm_output_reloc_func output_reloc)
+ {
+     bytecode_incbin *incbin = (bytecode_incbin *)bc->contents;
+     FILE *f;
+     /*@dependent@*/ /*@null@*/ const yasm_intnum *num;
+     unsigned long start = 0;
+     /* Convert start to integer value */
+     if (incbin->start) {
+       num = yasm_expr_get_intnum(&incbin->start, NULL);
+       if (!num)
+           yasm_internal_error(
+               N_("could not determine start in bc_tobytes_incbin"));
+       start = yasm_intnum_get_uint(num);
+     }
+     /* Open file */
+     f = fopen(incbin->filename, "rb");
+     if (!f) {
+       yasm_error_set(YASM_ERROR_IO, N_("`incbin': unable to open file `%s'"),
+                      incbin->filename);
+       return 1;
+     }
+     /* Seek to start of data */
+     if (fseek(f, (long)start, SEEK_SET) < 0) {
+       yasm_error_set(YASM_ERROR_IO,
+                      N_("`incbin': unable to seek on file `%s'"),
+                      incbin->filename);
+       fclose(f);
+       return 1;
+     }
+     /* Read len bytes */
+     if (fread(*bufp, 1, (size_t)bc->len, f) < (size_t)bc->len) {
+       yasm_error_set(YASM_ERROR_IO,
+                      N_("`incbin': unable to read %lu bytes from file `%s'"),
+                      bc->len, incbin->filename);
+       fclose(f);
+       return 1;
+     }
+     *bufp += bc->len;
+     fclose(f);
+     return 0;
+ }
+ yasm_bytecode *
+ yasm_bc_create_incbin(char *filename, yasm_expr *start, yasm_expr *maxlen,
+                     unsigned long line)
+ {
+     bytecode_incbin *incbin = yasm_xmalloc(sizeof(bytecode_incbin));
+     /*@-mustfree@*/
+     incbin->filename = filename;
+     incbin->start = start;
+     incbin->maxlen = maxlen;
+     /*@=mustfree@*/
+     return yasm_bc_create_common(&bc_incbin_callback, incbin, line);
+ }
index 0000000000000000000000000000000000000000,48fb2112c211d6ee230e6d84fc08105600cafaaa..4d3afacbe79d0b4ffebdc4d690ebb91104552aa3
mode 000000,100644..100644
--- /dev/null
@@@ -1,0 -1,347 +1,348 @@@
 -static yasm_bc_resolve_flags bc_insn_resolve
 -    (yasm_bytecode *bc, int save, yasm_calc_bc_dist_func calc_bc_dist);
+ /*
+  * Insn bytecode
+  *
+  *  Copyright (C) 2005-2006  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.
+  */
+ #define YASM_LIB_INTERNAL
+ #include "util.h"
+ /*@unused@*/ RCSID("$Id$");
+ #include "coretype.h"
+ #include "errwarn.h"
+ #include "expr.h"
+ #include "value.h"
+ #include "bytecode.h"
+ #include "arch.h"
+ #include "bc-int.h"
+ typedef struct bytecode_insn {
+     /*@dependent@*/ yasm_arch *arch;
+     unsigned long insn_data[4];
+     int num_operands;
+     /*@null@*/ yasm_insn_operands operands;
+     /* array of 4-element prefix_data arrays */
+     int num_prefixes;
+     /*@null@*/ unsigned long **prefixes;
+     /* array of segment prefixes */
+     int num_segregs;
+     /*@null@*/ unsigned long *segregs;
+ } bytecode_insn;
+ static void bc_insn_destroy(void *contents);
+ static void bc_insn_print(const void *contents, FILE *f, int indent_level);
+ static void bc_insn_finalize(yasm_bytecode *bc, yasm_bytecode *prev_bc);
 -    bc_insn_resolve,
++static int bc_insn_calc_len(yasm_bytecode *bc, yasm_bc_add_span_func add_span,
++                          void *add_span_data);
+ static int bc_insn_tobytes(yasm_bytecode *bc, unsigned char **bufp, void *d,
+                          yasm_output_value_func output_value,
+                          /*@null@*/ yasm_output_reloc_func output_reloc);
+ static const yasm_bytecode_callback bc_insn_callback = {
+     bc_insn_destroy,
+     bc_insn_print,
+     bc_insn_finalize,
 -static yasm_bc_resolve_flags
 -bc_insn_resolve(yasm_bytecode *bc, int save,
 -              yasm_calc_bc_dist_func calc_bc_dist)
++    bc_insn_calc_len,
++    yasm_bc_expand_common,
+     bc_insn_tobytes,
+     0
+ };
+ yasm_immval *
+ yasm_imm_create_expr(yasm_expr *e)
+ {
+     yasm_immval *im = yasm_xmalloc(sizeof(yasm_immval));
+     if (yasm_value_finalize_expr(&im->val, e, 0))
+       yasm_error_set(YASM_ERROR_TOO_COMPLEX,
+                      N_("immediate expression too complex"));
+     im->sign = 0;
+     return im;
+ }
+ const yasm_expr *
+ yasm_ea_get_disp(const yasm_effaddr *ea)
+ {
+     return ea->disp.abs;
+ }
+ void
+ yasm_ea_set_len(yasm_effaddr *ptr, unsigned int len)
+ {
+     if (!ptr)
+       return;
+     /* Currently don't warn if length truncated, as this is called only from
+      * an explicit override, where we expect the user knows what they're doing.
+      */
+     ptr->disp.size = (unsigned char)len;
+ }
+ void
+ yasm_ea_set_nosplit(yasm_effaddr *ptr, unsigned int nosplit)
+ {
+     if (!ptr)
+       return;
+     ptr->nosplit = (unsigned char)nosplit;
+ }
+ void
+ yasm_ea_set_strong(yasm_effaddr *ptr, unsigned int strong)
+ {
+     if (!ptr)
+       return;
+     ptr->strong = (unsigned char)strong;
+ }
+ void
+ yasm_ea_set_segreg(yasm_effaddr *ea, unsigned long segreg)
+ {
+     if (!ea)
+       return;
+     if (segreg != 0 && ea->segreg != 0)
+       yasm_warn_set(YASM_WARN_GENERAL,
+                     N_("multiple segment overrides, using leftmost"));
+     ea->segreg = segreg;
+ }
+ /*@-nullstate@*/
+ void
+ yasm_ea_destroy(yasm_effaddr *ea)
+ {
+     ea->callback->destroy(ea);
+     yasm_value_delete(&ea->disp);
+     yasm_xfree(ea);
+ }
+ /*@=nullstate@*/
+ /*@-nullstate@*/
+ void
+ yasm_ea_print(const yasm_effaddr *ea, FILE *f, int indent_level)
+ {
+     fprintf(f, "%*sDisp:\n", indent_level, "");
+     yasm_value_print(&ea->disp, f, indent_level+1);
+     fprintf(f, "%*sNoSplit=%u\n", indent_level, "", (unsigned int)ea->nosplit);
+     ea->callback->print(ea, f, indent_level);
+ }
+ /*@=nullstate@*/
+ static void
+ bc_insn_destroy(void *contents)
+ {
+     bytecode_insn *insn = (bytecode_insn *)contents;
+     if (insn->num_operands > 0)
+       yasm_ops_delete(&insn->operands, 0);
+     if (insn->num_prefixes > 0) {
+       int i;
+       for (i=0; i<insn->num_prefixes; i++)
+           yasm_xfree(insn->prefixes[i]);
+       yasm_xfree(insn->prefixes);
+     }
+     if (insn->num_segregs > 0)
+       yasm_xfree(insn->segregs);
+     yasm_xfree(contents);
+ }
+ static void
+ bc_insn_print(const void *contents, FILE *f, int indent_level)
+ {
+ }
+ static void
+ bc_insn_finalize(yasm_bytecode *bc, yasm_bytecode *prev_bc)
+ {
+     bytecode_insn *insn = (bytecode_insn *)bc->contents;
+     int i;
+     yasm_insn_operand *op;
+     yasm_error_class eclass;
+     char *str, *xrefstr;
+     unsigned long xrefline;
+     /* Simplify the operands' expressions first. */
+     for (i = 0, op = yasm_ops_first(&insn->operands);
+        op && i<insn->num_operands; op = yasm_operand_next(op), i++) {
+       /* Check operand type */
+       switch (op->type) {
+           case YASM_INSN__OPERAND_MEMORY:
+               /* Don't get over-ambitious here; some archs' memory expr
+                * parser are sensitive to the presence of *1, etc, so don't
+                * simplify reg*1 identities.
+                */
+               if (op->data.ea)
+                   op->data.ea->disp.abs =
+                       yasm_expr__level_tree(op->data.ea->disp.abs, 1, 1, 0,
+                                             NULL, NULL, NULL, NULL);
+               if (yasm_error_occurred()) {
+                   /* Add a pointer to where it was used to the error */
+                   yasm_error_fetch(&eclass, &str, &xrefline, &xrefstr);
+                   if (xrefstr) {
+                       yasm_error_set_xref(xrefline, "%s", xrefstr);
+                       yasm_xfree(xrefstr);
+                   }
+                   if (str) {
+                       yasm_error_set(eclass, "%s in memory expression", str);
+                       yasm_xfree(str);
+                   }
+                   return;
+               }
+               break;
+           case YASM_INSN__OPERAND_IMM:
+               op->data.val =
+                   yasm_expr__level_tree(op->data.val, 1, 1, 1, NULL, NULL,
+                                         NULL, NULL);
+               if (yasm_error_occurred()) {
+                   /* Add a pointer to where it was used to the error */
+                   yasm_error_fetch(&eclass, &str, &xrefline, &xrefstr);
+                   if (xrefstr) {
+                       yasm_error_set_xref(xrefline, "%s", xrefstr);
+                       yasm_xfree(xrefstr);
+                   }
+                   if (str) {
+                       yasm_error_set(eclass, "%s in immediate expression",
+                                      str);
+                       yasm_xfree(str);
+                   }
+                   return;
+               }
+               break;
+           default:
+               break;
+       }
+     }
+     yasm_arch_finalize_insn(insn->arch, bc, prev_bc, insn->insn_data,
+                           insn->num_operands, &insn->operands,
+                           insn->num_prefixes, insn->prefixes,
+                           insn->num_segregs, insn->segregs);
+ }
 -    yasm_internal_error(N_("bc_insn_resolve() is not implemented"));
++static int
++bc_insn_calc_len(yasm_bytecode *bc, yasm_bc_add_span_func add_span,
++               void *add_span_data)
+ {
 -    return YASM_BC_RESOLVE_ERROR;
++    yasm_internal_error(N_("bc_insn_calc_len() is not implemented"));
+     /*@notreached@*/
++    return 0;
+ }
+ static int
+ bc_insn_tobytes(yasm_bytecode *bc, unsigned char **bufp, void *d,
+               yasm_output_value_func output_value,
+               /*@unused@*/ yasm_output_reloc_func output_reloc)
+ {
+     yasm_internal_error(N_("bc_insn_tobytes() is not implemented"));
+     /*@notreached@*/
+     return 1;
+ }
+ yasm_bytecode *
+ yasm_bc_create_insn(yasm_arch *arch, const unsigned long insn_data[4],
+                   int num_operands, /*@null@*/ yasm_insn_operands *operands,
+                   unsigned long line)
+ {
+     bytecode_insn *insn = yasm_xmalloc(sizeof(bytecode_insn));
+     insn->arch = arch;
+     insn->insn_data[0] = insn_data[0];
+     insn->insn_data[1] = insn_data[1];
+     insn->insn_data[2] = insn_data[2];
+     insn->insn_data[3] = insn_data[3];
+     insn->num_operands = num_operands;
+     if (operands)
+       insn->operands = *operands;     /* structure copy */
+     else
+       yasm_ops_initialize(&insn->operands);
+     insn->num_prefixes = 0;
+     insn->prefixes = NULL;
+     insn->num_segregs = 0;
+     insn->segregs = NULL;
+     return yasm_bc_create_common(&bc_insn_callback, insn, line);
+ }
+ yasm_bytecode *
+ yasm_bc_create_empty_insn(yasm_arch *arch, unsigned long line)
+ {
+     bytecode_insn *insn = yasm_xmalloc(sizeof(bytecode_insn));
+     insn->arch = arch;
+     insn->insn_data[0] = 0;
+     insn->insn_data[1] = 0;
+     insn->insn_data[2] = 0;
+     insn->insn_data[3] = 0;
+     insn->num_operands = 0;
+     yasm_ops_initialize(&insn->operands);
+     insn->num_prefixes = 0;
+     insn->prefixes = NULL;
+     insn->num_segregs = 0;
+     insn->segregs = NULL;
+     return yasm_bc_create_common(&bc_insn_callback, insn, line);
+ }
+ void
+ yasm_bc_insn_add_prefix(yasm_bytecode *bc, const unsigned long prefix_data[4])
+ {
+     bytecode_insn *insn = (bytecode_insn *)bc->contents;
+     assert(bc->callback == bc_insn_callback);
+     insn->prefixes =
+       yasm_xrealloc(insn->prefixes,
+                     (insn->num_prefixes+1)*sizeof(unsigned long *));
+     insn->prefixes[insn->num_prefixes] =
+       yasm_xmalloc(4*sizeof(unsigned long));
+     insn->prefixes[insn->num_prefixes][0] = prefix_data[0];
+     insn->prefixes[insn->num_prefixes][1] = prefix_data[1];
+     insn->prefixes[insn->num_prefixes][2] = prefix_data[2];
+     insn->prefixes[insn->num_prefixes][3] = prefix_data[3];
+     insn->num_prefixes++;
+ }
+ void
+ yasm_bc_insn_add_seg_prefix(yasm_bytecode *bc, unsigned long segreg)
+ {
+     bytecode_insn *insn = (bytecode_insn *)bc->contents;
+     assert(bc->callback == bc_insn_callback);
+     insn->segregs =
+       yasm_xrealloc(insn->segregs,
+                     (insn->num_segregs+1)*sizeof(unsigned long));
+     insn->segregs[insn->num_segregs] = segreg;
+     insn->num_segregs++;
+ }
index 9bdea87cb059dd73ff7bcacf99abbede62e4cc08,5bb8635748707ad4ebaebca536f7882b3e94a667..a25eeb3bb866a8b8c5674ede015ddc3ffcfe9d01
@@@ -59,13 -31,12 +31,14 @@@ typedef struct yasm_bytecode_callback 
      void (*destroy) (/*@only@*/ void *contents);
      void (*print) (const void *contents, FILE *f, int indent_level);
      void (*finalize) (yasm_bytecode *bc, yasm_bytecode *prev_bc);
 -    yasm_bc_resolve_flags (*resolve)
 -      (yasm_bytecode *bc, int save, yasm_calc_bc_dist_func calc_bc_dist);
 +    int (*calc_len) (yasm_bytecode *bc, yasm_bc_add_span_func add_span,
 +                   void *add_span_data);
 +    int (*expand) (yasm_bytecode *bc, int span, long old_val, long new_val,
 +                 /*@out@*/ long *neg_thres, /*@out@*/ long *pos_thres);
      int (*tobytes) (yasm_bytecode *bc, unsigned char **bufp, void *d,
-                   yasm_output_expr_func output_expr,
+                   yasm_output_value_func output_value,
                    /*@null@*/ yasm_output_reloc_func output_reloc);
+     int reserve;    /* Reserve space instead of outputting data */
  } yasm_bytecode_callback;
  
  struct yasm_bytecode {
index 0000000000000000000000000000000000000000,0d4da09f78244f1648c53b18e6b196b539dcaa2e..277601929994aa0c2bf0590e0bfb17cc7e43fdf0
mode 000000,100644..100644
--- /dev/null
@@@ -1,0 -1,132 +1,147 @@@
 -static yasm_bc_resolve_flags bc_org_resolve
 -    (yasm_bytecode *bc, int save, yasm_calc_bc_dist_func calc_bc_dist);
+ /*
+  * ORG bytecode
+  *
+  *  Copyright (C) 2005-2006  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.
+  */
+ #define YASM_LIB_INTERNAL
+ #include "util.h"
+ /*@unused@*/ RCSID("$Id$");
+ #include "coretype.h"
+ #include "file.h"
+ #include "errwarn.h"
+ #include "intnum.h"
+ #include "expr.h"
+ #include "value.h"
+ #include "bytecode.h"
+ #include "bc-int.h"
+ typedef struct bytecode_org {
+     unsigned long start;      /* target starting offset within section */
+ } bytecode_org;
+ static void bc_org_destroy(void *contents);
+ static void bc_org_print(const void *contents, FILE *f, int indent_level);
+ static void bc_org_finalize(yasm_bytecode *bc, yasm_bytecode *prev_bc);
 -    bc_org_resolve,
++static int bc_org_calc_len(yasm_bytecode *bc, yasm_bc_add_span_func add_span,
++                         void *add_span_data);
++static int bc_org_expand(yasm_bytecode *bc, int span, long old_val,
++                       long new_val, /*@out@*/ long *neg_thres,
++                       /*@out@*/ long *pos_thres);
+ static int bc_org_tobytes(yasm_bytecode *bc, unsigned char **bufp, void *d,
+                         yasm_output_value_func output_value,
+                         /*@null@*/ yasm_output_reloc_func output_reloc);
+ static const yasm_bytecode_callback bc_org_callback = {
+     bc_org_destroy,
+     bc_org_print,
+     bc_org_finalize,
 -static yasm_bc_resolve_flags
 -bc_org_resolve(yasm_bytecode *bc, int save,
 -             yasm_calc_bc_dist_func calc_bc_dist)
++    bc_org_calc_len,
++    bc_org_expand,
+     bc_org_tobytes,
+     0
+ };
+ static void
+ bc_org_destroy(void *contents)
+ {
+     yasm_xfree(contents);
+ }
+ static void
+ bc_org_print(const void *contents, FILE *f, int indent_level)
+ {
+     const bytecode_org *org = (const bytecode_org *)contents;
+     fprintf(f, "%*s_Org_\n", indent_level, "");
+     fprintf(f, "%*sStart=%lu\n", indent_level, "", org->start);
+ }
+ static void
+ bc_org_finalize(yasm_bytecode *bc, yasm_bytecode *prev_bc)
+ {
+ }
 -    return YASM_BC_RESOLVE_MIN_LEN;
++static int
++bc_org_calc_len(yasm_bytecode *bc, yasm_bc_add_span_func add_span,
++              void *add_span_data)
+ {
++    yasm_internal_error(N_("org not yet implemented"));
++#if 0
+     bytecode_org *org = (bytecode_org *)bc->contents;
+     /* Check for overrun */
+     if (bc->offset > org->start) {
+       yasm_error_set(YASM_ERROR_GENERAL,
+                      N_("ORG overlap with already existing data"));
+       return YASM_BC_RESOLVE_ERROR | YASM_BC_RESOLVE_UNKNOWN_LEN;
+     }
+     /* Generate space to start offset */
+     bc->len = org->start - bc->offset;
++#endif
++    return 0;
++}
++
++static int
++bc_org_expand(yasm_bytecode *bc, int span, long old_val, long new_val,
++            /*@out@*/ long *neg_thres, /*@out@*/ long *pos_thres)
++{
++    yasm_internal_error(N_("org not yet implemented"));
++    return 0;
+ }
+ static int
+ bc_org_tobytes(yasm_bytecode *bc, unsigned char **bufp, void *d,
+              yasm_output_value_func output_value,
+              /*@unused@*/ yasm_output_reloc_func output_reloc)
+ {
+     bytecode_org *org = (bytecode_org *)bc->contents;
+     unsigned long len, i;
+     /* Sanity check for overrun */
+     if (bc->offset > org->start) {
+       yasm_error_set(YASM_ERROR_GENERAL,
+                      N_("ORG overlap with already existing data"));
+       return 1;
+     }
+     len = org->start - bc->offset;
+     for (i=0; i<len; i++)
+       YASM_WRITE_8(*bufp, 0);
+     return 0;
+ }
+ yasm_bytecode *
+ yasm_bc_create_org(unsigned long start, unsigned long line)
+ {
+     bytecode_org *org = yasm_xmalloc(sizeof(bytecode_org));
+     org->start = start;
+     return yasm_bc_create_common(&bc_org_callback, org, line);
+ }
index 0000000000000000000000000000000000000000,9e1fa1a77130b5e35d8e234d5b1c93db1f7cd299..03280d180a8f1a404a11c99c2dc1d326e0d89885
mode 000000,100644..100644
--- /dev/null
@@@ -1,0 -1,162 +1,158 @@@
 -static yasm_bc_resolve_flags bc_reserve_resolve
 -    (yasm_bytecode *bc, int save, yasm_calc_bc_dist_func calc_bc_dist);
+ /*
+  * Bytecode utility functions
+  *
+  *  Copyright (C) 2001  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.
+  */
+ #define YASM_LIB_INTERNAL
+ #include "util.h"
+ /*@unused@*/ RCSID("$Id$");
+ #include "coretype.h"
+ #include "errwarn.h"
+ #include "intnum.h"
+ #include "expr.h"
+ #include "value.h"
+ #include "bytecode.h"
+ #include "bc-int.h"
+ #include "expr-int.h"
+ typedef struct bytecode_reserve {
+     /*@only@*/ /*@null@*/ yasm_expr *numitems; /* number of items to reserve */
+     unsigned char itemsize;       /* size of each item (in bytes) */
+ } bytecode_reserve;
+ static void bc_reserve_destroy(void *contents);
+ static void bc_reserve_print(const void *contents, FILE *f, int indent_level);
+ static void bc_reserve_finalize(yasm_bytecode *bc, yasm_bytecode *prev_bc);
 -    bc_reserve_resolve,
++static int bc_reserve_calc_len(yasm_bytecode *bc,
++                             yasm_bc_add_span_func add_span,
++                             void *add_span_data);
+ static int bc_reserve_tobytes(yasm_bytecode *bc, unsigned char **bufp, void *d,
+                             yasm_output_value_func output_value,
+                             /*@null@*/ yasm_output_reloc_func output_reloc);
+ static const yasm_bytecode_callback bc_reserve_callback = {
+     bc_reserve_destroy,
+     bc_reserve_print,
+     bc_reserve_finalize,
 -static yasm_bc_resolve_flags
 -bc_reserve_resolve(yasm_bytecode *bc, int save,
 -                 yasm_calc_bc_dist_func calc_bc_dist)
++    bc_reserve_calc_len,
++    yasm_bc_expand_common,
+     bc_reserve_tobytes,
+     1
+ };
+ static void
+ bc_reserve_destroy(void *contents)
+ {
+     bytecode_reserve *reserve = (bytecode_reserve *)contents;
+     yasm_expr_destroy(reserve->numitems);
+     yasm_xfree(contents);
+ }
+ static void
+ bc_reserve_print(const void *contents, FILE *f, int indent_level)
+ {
+     const bytecode_reserve *reserve = (const bytecode_reserve *)contents;
+     fprintf(f, "%*s_Reserve_\n", indent_level, "");
+     fprintf(f, "%*sNum Items=", indent_level, "");
+     yasm_expr_print(reserve->numitems, f);
+     fprintf(f, "\n%*sItem Size=%u\n", indent_level, "",
+           (unsigned int)reserve->itemsize);
+ }
+ static void
+ bc_reserve_finalize(yasm_bytecode *bc, yasm_bytecode *prev_bc)
+ {
+     bytecode_reserve *reserve = (bytecode_reserve *)bc->contents;
+     yasm_value val;
+     if (yasm_value_finalize_expr(&val, reserve->numitems, 0))
+       yasm_error_set(YASM_ERROR_TOO_COMPLEX,
+                      N_("reserve expression too complex"));
+     else if (val.rel)
+       yasm_error_set(YASM_ERROR_NOT_ABSOLUTE,
+                      N_("reserve expression not absolute"));
+     else if (val.abs && yasm_expr__contains(val.abs, YASM_EXPR_FLOAT))
+       yasm_error_set(YASM_ERROR_VALUE,
+                      N_("expression must not contain floating point value"));
+     reserve->numitems = val.abs;
+ }
 -    yasm_bc_resolve_flags retval = YASM_BC_RESOLVE_MIN_LEN;
 -    /*@null@*/ yasm_expr *temp;
 -    yasm_expr **tempp;
++static int
++bc_reserve_calc_len(yasm_bytecode *bc, yasm_bc_add_span_func add_span,
++                  void *add_span_data)
+ {
+     bytecode_reserve *reserve = (bytecode_reserve *)bc->contents;
 -      return YASM_BC_RESOLVE_MIN_LEN;
 -
 -    if (save) {
 -      temp = NULL;
 -      tempp = &reserve->numitems;
 -    } else {
 -      temp = yasm_expr_copy(reserve->numitems);
 -      assert(temp != NULL);
 -      tempp = &temp;
 -    }
 -    num = yasm_expr_get_intnum(tempp, calc_bc_dist);
+     /*@dependent@*/ /*@null@*/ const yasm_intnum *num;
+     if (!reserve->numitems)
 -      /* For reserve, just say non-constant quantity instead of allowing
 -       * the circular reference error to filter through.
 -       */
++      return 0;
++
++    num = yasm_expr_get_intnum(&reserve->numitems, NULL);
+     if (!num) {
 -      retval = YASM_BC_RESOLVE_ERROR | YASM_BC_RESOLVE_UNKNOWN_LEN;
 -    } else
 -      bc->len += yasm_intnum_get_uint(num)*reserve->itemsize;
 -    yasm_expr_destroy(temp);
 -    return retval;
++      /* Check for use of floats first. */
++      if (reserve->numitems &&
++          yasm_expr__contains(reserve->numitems, YASM_EXPR_FLOAT)) {
++          yasm_error_set(YASM_ERROR_VALUE,
++              N_("expression must not contain floating point value"));
++          return -1;
++      }
++      /* FIXME: Non-constant currently not allowed. */
+       yasm_error_set(YASM_ERROR_NOT_CONSTANT,
+                      N_("attempt to reserve non-constant quantity of space"));
++      return -1;
++    }
++    
++    bc->len += yasm_intnum_get_uint(num)*reserve->itemsize;
++    return 0;
+ }
+ static int
+ bc_reserve_tobytes(yasm_bytecode *bc, unsigned char **bufp, void *d,
+                  yasm_output_value_func output_value,
+                  /*@unused@*/ yasm_output_reloc_func output_reloc)
+ {
+     yasm_internal_error(N_("bc_reserve_tobytes called"));
+     /*@notreached@*/
+     return 1;
+ }
+ yasm_bytecode *
+ yasm_bc_create_reserve(yasm_expr *numitems, unsigned int itemsize,
+                      unsigned long line)
+ {
+     bytecode_reserve *reserve = yasm_xmalloc(sizeof(bytecode_reserve));
+     /*@-mustfree@*/
+     reserve->numitems = numitems;
+     /*@=mustfree@*/
+     reserve->itemsize = (unsigned char)itemsize;
+     return yasm_bc_create_common(&bc_reserve_callback, reserve, line);
+ }
index daffb2baf393d59f51c42ef7c2243f927b348d15,7138b3ce6bc21a140606d595217235847b0d6516..e008da1aa205068f465f3972f78823b1be07f25b
@@@ -1286,91 -170,78 +179,80 @@@ yasm_bc_finalize(yasm_bytecode *bc, yas
  }
  
  /*@null@*/ yasm_intnum *
- yasm_common_calc_bc_dist(/*@null@*/ yasm_bytecode *precbc1,
-                        /*@null@*/ yasm_bytecode *precbc2)
+ yasm_common_calc_bc_dist(yasm_bytecode *precbc1, yasm_bytecode *precbc2)
  {
-     unsigned int dist;
+     unsigned long dist;
      yasm_intnum *intn;
  
-     if (precbc2) {
-       dist = precbc2->offset + precbc2->len;
-       if (precbc1) {
-           if (dist < precbc1->offset + precbc1->len) {
-               intn = yasm_intnum_create_uint(precbc1->offset + precbc1->len
-                                              - dist);
-               yasm_intnum_calc(intn, YASM_EXPR_NEG, NULL, precbc1->line);
-               return intn;
-           }
-           dist -= precbc1->offset + precbc1->len;
-       }
-       return yasm_intnum_create_uint(dist);
-     } else {
-       if (precbc1) {
-           intn = yasm_intnum_create_uint(precbc1->offset + precbc1->len);
-           yasm_intnum_calc(intn, YASM_EXPR_NEG, NULL, precbc1->line);
-           return intn;
-       } else {
-           return yasm_intnum_create_uint(0);
-       }
+     if (precbc1->section != precbc2->section)
+       return NULL;
+     dist = precbc2->offset + precbc2->len;
+     if (dist < precbc1->offset + precbc1->len) {
+       intn = yasm_intnum_create_uint(precbc1->offset + precbc1->len - dist);
+       yasm_intnum_calc(intn, YASM_EXPR_NEG, NULL);
+       return intn;
      }
+     dist -= precbc1->offset + precbc1->len;
+     return yasm_intnum_create_uint(dist);
  }
  
 -yasm_bc_resolve_flags
 -yasm_bc_resolve(yasm_bytecode *bc, int save,
 -              yasm_calc_bc_dist_func calc_bc_dist)
 +int
 +yasm_bc_calc_len(yasm_bytecode *bc, yasm_bc_add_span_func add_span,
 +               void *add_span_data)
  {
 -    yasm_bc_resolve_flags retval = YASM_BC_RESOLVE_MIN_LEN;
 -    /*@null@*/ yasm_expr *temp;
 -    yasm_expr **tempp;
 -    /*@dependent@*/ /*@null@*/ const yasm_intnum *num;
 +    int retval = 0;
  
 -    bc->len = 0;      /* start at 0 */
 +    bc->len = 0;
  
      if (!bc->callback)
        yasm_internal_error(N_("got empty bytecode in bc_resolve"));
      else
 -      retval = bc->callback->resolve(bc, save, calc_bc_dist);
 -
 -    /* Multiply len by number of multiples */
 +      retval = bc->callback->calc_len(bc, add_span, add_span_data);
 +#if 0
 +    /* Check for multiples */
      if (bc->multiple) {
 -      if (save) {
 -          temp = NULL;
 -          tempp = &bc->multiple;
 -      } else {
 -          temp = yasm_expr_copy(bc->multiple);
 -          assert(temp != NULL);
 -          tempp = &temp;
 -      }
 -      num = yasm_expr_get_intnum(tempp, calc_bc_dist);
 +      /*@dependent@*/ /*@null@*/ const yasm_intnum *num;
 +
 +      num = yasm_expr_get_intnum(&bc->multiple, NULL);
        if (!num) {
 -          retval = YASM_BC_RESOLVE_UNKNOWN_LEN;
 -          if (temp && yasm_expr__contains(temp, YASM_EXPR_FLOAT)) {
 +          if (yasm_expr__contains(bc->multiple, YASM_EXPR_FLOAT)) {
-               yasm__error(bc->line,
+               yasm_error_set(YASM_ERROR_VALUE,
                    N_("expression must not contain floating point value"));
 -              retval |= YASM_BC_RESOLVE_ERROR;
 +              retval = -1;
 +          } else {
 +              /* FIXME: Non-constant currently not allowed. */
 +              yasm__error(bc->line,
 +                          N_("attempt to use non-constant multiple"));
 +              retval = -1;
            }
 -      } else {
 -          if (yasm_intnum_sign(num) >= 0)
 -              bc->len *= yasm_intnum_get_uint(num);
 -          else
 -              retval |= YASM_BC_RESOLVE_ERROR;
        }
 -      yasm_expr_destroy(temp);
      }
 -
 +#endif
      /* If we got an error somewhere along the line, clear out any calc len */
 -    if (retval & YASM_BC_RESOLVE_UNKNOWN_LEN)
 +    if (retval < 0)
        bc->len = 0;
  
      return retval;
  }
  
 +int
 +yasm_bc_expand(yasm_bytecode *bc, int span, long old_val, long new_val,
 +             /*@out@*/ long *neg_thres, /*@out@*/ long *pos_thres)
 +{
 +    if (!bc->callback) {
 +      yasm_internal_error(N_("got empty bytecode in bc_set_long"));
 +      /*@unreached@*/
 +      return 0;
 +    } else
 +      return bc->callback->expand(bc, span, old_val, new_val, neg_thres,
 +                                  pos_thres);
 +}
 +
  /*@null@*/ /*@only@*/ unsigned char *
  yasm_bc_tobytes(yasm_bytecode *bc, unsigned char *buf, unsigned long *bufsize,
-               /*@out@*/ unsigned long *multiple, /*@out@*/ int *gap,
-               void *d, yasm_output_expr_func output_expr,
+               /*@out@*/ int *gap, void *d,
+               yasm_output_value_func output_value,
                /*@null@*/ yasm_output_reloc_func output_reloc)
      /*@sets *buf@*/
  {
index 8260c88e2b1e6c782ea7b0e14e007c27f1e73004,621bd0521387ce19e1f5f8c1b6232affc3131dfd..181d1bb5b6696ef4b4b8ef12f90e5366f7750b37
@@@ -47,14 -89,14 +89,6 @@@ typedef struct yasm_datavalhead yasm_da
  /*@reldef@*/ STAILQ_HEAD(yasm_datavalhead, yasm_dataval);
  #endif
  
- /** Create an immediate value from an unsigned integer.
-  * \param int_val   unsigned integer
-  * \param line            virtual line (from yasm_linemap)
-  * \return Newly allocated immediate value.
-  */
- /*@only@*/ yasm_immval *yasm_imm_create_int(unsigned long int_val,
-                                           unsigned long line);
 -/** Return value flags for yasm_bc_resolve(). */
 -typedef enum {
 -    YASM_BC_RESOLVE_NONE = 0,         /**< Ok, but length is not minimum. */
 -    YASM_BC_RESOLVE_ERROR = 1<<0,     /**< Error found, output. */
 -    YASM_BC_RESOLVE_MIN_LEN = 1<<1,   /**< Length is minimum possible. */
 -    YASM_BC_RESOLVE_UNKNOWN_LEN = 1<<2        /**< Length indeterminate. */
 -} yasm_bc_resolve_flags;
--
  /** Create an immediate value from an expression.
   * \param e   expression (kept, do not free).
   * \return Newly allocated immediate value.
@@@ -270,47 -312,27 +304,50 @@@ void yasm_bc_finalize(yasm_bytecode *bc
   * yasm_expr output functions.
   * \see yasm_calc_bc_dist_func for parameter descriptions.
   */
- /*@null@*/ yasm_intnum *yasm_common_calc_bc_dist
-     (/*@null@*/ yasm_bytecode *precbc1, /*@null@*/ yasm_bytecode *precbc2);
+ /*@null@*/ /*@only@*/ yasm_intnum *yasm_common_calc_bc_dist
+     (yasm_bytecode *precbc1, yasm_bytecode *precbc2);
  
 -/** Resolve labels in a bytecode, and calculate its length.
 - * Tries to minimize the length as much as possible.
 - * \note Sometimes it's impossible to determine if a length is the minimum
 - *       possible.  In this case, this function returns that the length is NOT
 - *       the minimum.
 +/**
-  * \param critical    dependent expression for bytecode expansion
++ * \param value               dependent value for bytecode expansion
++ * \param origin_prevbc       origin for distance computation to relative portion of
++ *                    value; value.rel and origin must be within the same
++ *                    section.
 + * \param neg_thres   negative threshold for long/short decision
 + * \param pos_thres   positive threshold for long/short decision
 + */
 +typedef void (*yasm_bc_add_span_func)
-     (void *add_span_data, yasm_bytecode *bc, int id,
-      /*@only@*/ yasm_expr *dependent, long neg_thres, long pos_thres);
++    (void *add_span_data, yasm_bytecode *bc, int id, yasm_value *value,
++     /*@null@*/ yasm_bytecode *origin_prevbc, long neg_thres, long pos_thres);
 +
 +/** Resolve EQUs in a bytecode and calculate its minimum size.
-  * Returns dependent bytecode spans for cases where, if the length spanned
++ * Generates dependent bytecode spans for cases where, if the length spanned
 + * increases, it could cause the bytecode size to increase.
 + * Any bytecode multiple is NOT included in the length or spans generation;
 + * this must be handled at a higher level.
 + * \param bc          bytecode
 + * \return 0 if no error occurred, nonzero if there was an error recognized
 + *         (and output) during execution.
 + * \note May store to bytecode updated expressions and the short length.
 + */
 +int yasm_bc_calc_len(yasm_bytecode *bc, yasm_bc_add_span_func add_span,
 +                   void *add_span_data);
 +
 +/** Recalculate a bytecode's length based on an expanded span length.
   * \param bc          bytecode
 - * \param save                when zero, this function does \em not modify bc other
 - *                    than the length/size values (i.e. it doesn't keep the
 - *                    values returned by calc_bc_dist except temporarily to
 - *                    try to minimize the length); when nonzero, all fields
 - *                    in bc may be modified by this function
 - * \param calc_bc_dist        function used to determine bytecode distance
 - * \return Flags indicating whether the length is the minimum possible,
 - *       indeterminate, and if there was an error recognized (and output)
 - *       during execution.
 + * \param span                span ID (as given to yasm_bc_add_span_func in
 + *                      yasm_bc_calc_len)
 + * \param old_val     previous span value
 + * \param new_val     new span value
 + * \param neg_thres   negative threshold for long/short decision (returned)
 + * \param pos_thres   postivie threshold for long/short decision (returned)
 + * \return 0 if bc no longer dependent on this span's length, negative if
 + *         there was an error recognized (and output) during execution, and
 + *         positive if bc size may increase for this span further based on the
 + *         new negative and positive thresholds returned.
 + * \note May store to bytecode updated expressions and the updated length.
   */
 -yasm_bc_resolve_flags yasm_bc_resolve(yasm_bytecode *bc, int save,
 -                                    yasm_calc_bc_dist_func calc_bc_dist);
 +int yasm_bc_expand(yasm_bytecode *bc, int span, long old_val, long new_val,
 +                 /*@out@*/ long *neg_thres, /*@out@*/ long *pos_thres);
  
  /** Convert a bytecode into its byte representation.
   * \param bc          bytecode
index b8e0a5acd5d4f6496258345033b58e4a039dd4e8,160d5dd4d7171f1e679ac280d0595b95aa80cb04..94b8e733ca89479cbaec146719cba5251a6ecde1
@@@ -650,47 -789,9 +789,46 @@@ yasm_intnum_check_size(const yasm_intnu
      return (Set_Max(val) < (long)size);
  }
  
- unsigned long
- yasm_intnum_get_leb128(const yasm_intnum *intn, unsigned char *ptr, int sign)
 +int
 +yasm_intnum_in_range(const yasm_intnum *intn, long low, long high)
 +{
 +    wordptr val = result;
 +    wordptr lval = op1static;
 +    wordptr hval = op2static;
 +
 +    /* If not already a bitvect, convert value to be written to a bitvect */
 +    if (intn->type == INTNUM_BV)
 +      val = intn->val.bv;
 +    else {
 +      BitVector_Empty(val);
 +      BitVector_Chunk_Store(val, 32, 0, intn->val.ul);
 +    }
 +
 +    /* Convert high and low to bitvects */
 +    BitVector_Empty(lval);
 +    if (low >= 0)
 +      BitVector_Chunk_Store(lval, 32, 0, (unsigned long)low);
 +    else {
 +      BitVector_Chunk_Store(lval, 32, 0, (unsigned long)(-low));
 +      BitVector_Negate(lval, lval);
 +    }
 +
 +    BitVector_Empty(hval);
 +    if (high >= 0)
 +      BitVector_Chunk_Store(hval, 32, 0, (unsigned long)high);
 +    else {
 +      BitVector_Chunk_Store(hval, 32, 0, (unsigned long)(-high));
 +      BitVector_Negate(hval, hval);
 +    }
 +
 +    /* Compare! */
 +    return (BitVector_Compare(val, lval) >= 0
 +          && BitVector_Compare(val, hval) <= 0);
 +}
 +
+ static unsigned long
+ get_leb128(wordptr val, unsigned char *ptr, int sign)
  {
-     wordptr val = op1static;
      unsigned long i, size;
      unsigned char *ptr_orig = ptr;
  
Simple merge
index 346f18c7102efd790b9bf1277551d92426f07bc6,f351d63657aa8efaa520b2aaa3c2ebae4130cf97..241805abecda7a6e577622396d4f62b796f92bae
@@@ -536,265 -601,3 +605,276 @@@ yasm_section_print(const yasm_section *
        }
      }
  }
-     /*@owned@*/ yasm_expr *dependent;
 +
 +/*
 + * Robertson (1977) optimizer
 + * Based (somewhat loosely) on the algorithm given in:
 + *   MRC Technical Summary Report # 1779
 + *   CODE GENERATION FOR SHORT/LONG ADDRESS MACHINES
 + *   Edward L. Robertson
 + *   Mathematics Research Center
 + *   University of Wisconsin-Madison
 + *   610 Walnut Street
 + *   Madison, Wisconsin 53706
 + *   August 1977
 + *
 + * Key components of algorithm:
 + *  - start assuming all short forms
 + *  - build spans for short->long transition dependencies
 + *  - if a long form is needed, walk the dependencies and update
 + * Major differences from Robertson's algorithm:
 + *  - detection of cycles
 + *  - any difference of two locations is allowed
 + *  - handling of alignment gaps
 + *  - handling of multiples
 + *
 + * Data structures:
 + *  - Interval tree to store spans and associated data
 + *  - Queue Q
 + *
 + * Each span keeps track of:
 + *  - Associated bytecode (bytecode that depends on the span length)
 + *  - Active/inactive state (starts out active)
 + *  - Sign (negative/positive; negative being "backwards" in address)
 + *  - Current length in bytes
 + *  - New length in bytes
 + *  - Negative/Positive thresholds
 + *  - Span ID (unique within each bytecode)
 + *
 + * How org and align are handled:
 + * Some portions are critical values that must not depend on any bytecode
 + * offset (either relative or absolute).
 + *
 + * ALIGN: 0 length (always).  Bump offset to alignment.  Span from 0 to
 + *        align bytecode, update on any change.  If span length
 + *        increases past alignment, increase offset by alignment and update
 + *        dependent spans.  Alignment is critical value.
 + * ORG:   Same as align, but if span's length exceeds org value, error.
 + *        ORG value is critical value.
 + *
 + * How times is handled:
 + *
 + * TIMES: Handled separately from bytecode "raw" size.  If not span-dependent,
 + *        trivial (just multiplied in at any bytecode size increase).  Span
 + *        dependent times update on any change (span ID 0).  If the resultant
 + *        next bytecode offset would be less than the old next bytecode offset,
 + *        error.  Otherwise increase offset and update dependent spans.
 + *
 + * To reduce interval tree size, a first expansion pass is performed
 + * before the spans are added to the tree.
 + *
 + * Basic algorithm outline:
 + *
 + * 1. Initialization:
 + *  a. Number bytecodes sequentially (via bc_index) and calculate offsets
 + *     of all bytecodes assuming minimum length, building a list of all
 + *     dependent spans as we go.
 + *     "minimum" here means absolute minimum:
 + *      - align 0 length
 + *      - times values (with span-dependent values) assumed to be 0
 + *      - org bumps offset
 + *  b. Iterate over spans.  Set span length based on bytecode offsets
 + *     determined in 1a.  If span is "certainly" long because the span
 + *     is an absolute reference to another section (or external) or the
 + *     distance calculated based on the minimum length is greater than the
 + *     span's threshold, expand the span's bytecode, and if no further
 + *     expansion can result, delete the span.  Otherwise (or if the
 + *     expansion results in another threshold of expansion), add span to
 + *     interval tree.
 + *  c. Iterate over bytecodes to update all bytecode offsets based on new
 + *     (expanded) lengths calculated in 1b.
 + *  d. Iterate over spans.  Update span's length based on new bytecode offsets
 + *     determined in 1c.  If span's length exceeds long threshold, add that
 + *     span to Q.
 + * 2. Main loop:
 + *   While Q not empty:
 + *     Expand BC dependent on span at head of Q (and remove span from Q).
 + *     Update span:
 + *       If BC no longer dependent on span, mark span as inactive.
 + *       If BC has new thresholds for span, update span.
 + *     If BC increased in size, for each active span that contains BC:
 + *       Increase span length by difference between short and long BC length.
 + *       If span exceeds long threshold (or is flagged to recalculate on any
 + *       change), add it to tail of Q.
 + * 3. Final pass over bytecodes to generate final offsets.
 + */
 +
 +typedef struct yasm_span {
 +    /*@reldef@*/ STAILQ_ENTRY(yasm_span) link;
 +
 +    /*@dependent@*/ yasm_bytecode *bc;
 +
-                 /*@only@*/ yasm_expr *dependent, long neg_thres,
-                 long pos_thres)
++    yasm_value *depval;
++    yasm_bytecode *origin_prevbc;
 +
 +    /* Special handling: see descriptions above */
 +    enum {
 +      NOT_SPECIAL = 0,
 +      SPECIAL_ALIGN,
 +      SPECIAL_ORG,
 +      SPECIAL_TIMES
 +    } special;
 +
 +    long cur_val;
 +    long new_val;
 +
 +    long neg_thres;
 +    long pos_thres;
 +
 +    int id;
 +
 +    int active;
 +} yasm_span;
 +
 +typedef struct optimize_data {
 +    /*@reldef@*/ STAILQ_HEAD(yasm_spanhead, yasm_span) spans;
 +} optimize_data;
 +
 +static void
 +optimize_add_span(void *add_span_data, yasm_bytecode *bc, int id,
-     span->dependent = dependent;
++                yasm_value *value, /*@null@*/ yasm_bytecode *origin_prevbc,
++                long neg_thres, long pos_thres)
 +{
 +    optimize_data *optd = (optimize_data *)add_span_data;
 +    yasm_span *span = yasm_xmalloc(sizeof(yasm_span));
 +
 +    span->bc = bc;
++    span->depval = value;
++    span->origin_prevbc = origin_prevbc;
 +    span->special = NOT_SPECIAL;
 +    span->cur_val = 0;
 +    span->new_val = 0;
 +    span->neg_thres = neg_thres;
 +    span->pos_thres = pos_thres;
 +    span->id = id;
 +    span->active = 1;
 +
 +    STAILQ_INSERT_TAIL(&optd->spans, span, link);
 +}
 +
 +static void
 +update_all_bc_offsets(yasm_object *object)
 +{
 +    yasm_section *sect;
 +
 +    STAILQ_FOREACH(sect, &object->sections, link) {
 +      unsigned long offset = 0;
 +
 +      yasm_bytecode *cur = STAILQ_FIRST(&sect->bcs);
 +      yasm_bytecode *prev;
 +
 +      /* Skip our locally created empty bytecode first. */
 +      prev = cur;
 +      cur = STAILQ_NEXT(cur, link);
 +
 +      /* Iterate through the remainder, if any. */
 +      while (cur) {
 +          cur->offset = offset;
 +          offset += cur->len;
 +          prev = cur;
 +          cur = STAILQ_NEXT(cur, link);
 +      }
 +    }
 +}
 +
 +void
 +yasm_object_optimize(yasm_object *object, yasm_arch *arch)
 +{
 +    yasm_section *sect;
 +    unsigned long bc_index = 0;
 +    int saw_error = 0;
 +    optimize_data optd;
 +    yasm_span *span;
 +    long neg_thres, pos_thres;
 +
 +    STAILQ_INIT(&optd.spans);
 +
 +    /* Step 1a */
 +    STAILQ_FOREACH(sect, &object->sections, link) {
 +      unsigned long offset = 0;
 +
 +      yasm_bytecode *cur = STAILQ_FIRST(&sect->bcs);
 +      yasm_bytecode *prev;
 +
 +      cur->bc_index = bc_index++;
 +
 +      /* Skip our locally created empty bytecode first. */
 +      prev = cur;
 +      cur = STAILQ_NEXT(cur, link);
 +
 +      /* Iterate through the remainder, if any. */
 +      while (cur) {
 +          cur->bc_index = bc_index++;
 +
 +          if (yasm_bc_calc_len(cur, optimize_add_span, &optd))
 +              saw_error = 1;
 +
 +          /* TODO: times */
 +          if (cur->multiple)
 +              yasm_internal_error("multiple not yet supported");
 +
 +          cur->offset = offset;
 +          offset += cur->len;
 +          prev = cur;
 +          cur = STAILQ_NEXT(cur, link);
 +      }
 +    }
 +
 +    if (saw_error)
 +      return;
-       yasm_expr *depcopy = yasm_expr_copy(span->dependent);
-       yasm_intnum *intn =
-           yasm_expr_get_intnum(&depcopy, yasm_common_calc_bc_dist);
-       if (intn)
-           span->new_val = yasm_intnum_get_int(intn);
-       else {
-           /* absolute, external, or too complex; force to longer form */
-           span->new_val = LONG_MAX;
-           span->active = 0;
++#if 0
 +    /* Step 1b */
 +    STAILQ_FOREACH(span, &optd.spans, link) {
-       yasm_expr_destroy(depcopy);
++      /* Handle absolute portion */
++      if (span->depval->abs) {
++          yasm_expr *depcopy = yasm_expr_copy(span->depval->abs);
++          yasm_intnum *intn =
++              yasm_expr_get_intnum(&depcopy, yasm_common_calc_bc_dist);
++          if (intn)
++              span->new_val = yasm_intnum_get_int(intn);
++          else {
++              /* absolute, external, or too complex; force to longer form */
++              span->new_val = LONG_MAX;
++              span->active = 0;
++          }
++          yasm_expr_destroy(depcopy);
++      } else
++          span->new_val = 0;
++
++      /* Handle relative portion */
++      if (span->depval->rel && span->new_val != LONG_MAX) {
++          span->new_val += 
 +      }
 +
 +      if (span->new_val < span->neg_thres
 +          || span->new_val > span->pos_thres) {
 +          int retval = yasm_bc_expand(span->bc, span->id, span->cur_val,
 +                                      span->new_val, &neg_thres, &pos_thres);
 +          if (retval < 0)
 +              saw_error = 1;
 +          else if (retval > 0) {
 +              span->neg_thres = neg_thres;
 +              span->pos_thres = pos_thres;
 +          } else
 +              span->active = 0;
 +      }
 +      span->cur_val = span->new_val;
 +    }
++#endif
 +    if (saw_error)
 +      return;
 +
 +    /* Step 1c */
 +    update_all_bc_offsets(object);
 +
 +    /* Step 1d */
 +    STAILQ_FOREACH(span, &optd.spans, link) {
 +      if (!span->active)
 +          continue;
 +    }
 +
 +    /* Step 2 */
 +
 +    /* Step 3 */
 +    update_all_bc_offsets(object);
 +}
Simple merge
index 7691b08151227216ab852abf681c355d6db4ac1a,4792b070641d55bdfdaa646d7612934fbc2e0446..cefbeb19deafafc88bb67fa31e7935f62eba06e6
@@@ -188,6 -198,6 +198,7 @@@ yasm_arch_module yasm_lc3b_LTX_arch = 
      lc3b_ea_create_expr,
      lc3b_machines,
      "lc3b",
-     2,
-     512
+     16,
++    512,
+     2
  };
index be37760e4741f34493d6cad641f03a1edfb02817,52e486c17a5b2546dae2940de7bfc2a04231e6bd..72b2b4da0694eec3b7760619930890d33a0ae288
@@@ -383,6 -461,6 +461,7 @@@ yasm_arch_module yasm_x86_LTX_arch = 
      yasm_x86__ea_create_expr,
      x86_machines,
      "x86",
-     2,
-     128
+     16,
++    128,
+     1
  };
index 7065f4879c85a50ee243fc894ec18c3c5cbdb8ef,88ed771d070ea830f0d26b34c538478fefa54372..725d3d97eabbef6a758c122d77e2022fa87ce76d
@@@ -187,44 -204,43 +204,17 @@@ typedef struct x86_insn 
        /* None */
        X86_POSTOP_NONE = 0,
  
--      /* Shift opcodes have an immediate form and a ,1 form (with no
--       * immediate).  In the parser, we set this and opcode_len=1, but store
-        * the non-,1 version in the second byte of the opcode array.  We then
 -       * the ,1 version in the second byte of the opcode array.  We then
--       * choose between the two versions once we know the actual value of
--       * imm (because we don't know it in the parser module).
--       *
--       * A override to force the imm version should just leave this at
--       * 0.  Then later code won't know the ,1 version even exists.
--       * TODO: Figure out how this affects CPU flags processing.
--       */
--      X86_POSTOP_SHIFT,
--
        /* Instructions that take a sign-extended imm8 as well as imm values
         * (eg, the arith instructions and a subset of the imul instructions)
-        * should set this and put the non-imm8 form in the second byte of the
 -       * should set this and put the imm8 form in the second byte of the
--       * opcode.
++       * should set this and put the imm8 form in the second (and possibly
++       * third) byte of the opcode.
         */
        X86_POSTOP_SIGNEXT_IMM8,
  
--      /* Long (modrm+sib) mov instructions in amd64 can be optimized into
--       * short mov instructions if a 32-bit address override is applied in
--       * 64-bit mode to an EA of just an offset (no registers) and the
--       * target register is al/ax/eax/rax.
--       */
--      X86_POSTOP_SHORTMOV,
--
        /* Override any attempt at address-size override to 16 bits, and never
         * generate a prefix.  This is used for the ENTER opcode.
         */
--      X86_POSTOP_ADDRESS16,
--
--      /* Used for 64-bit mov immediate, which can take a sign-extended
--       * imm32 as well as imm64 values.  The imm32 form is put in the
--       * second byte of the opcode and its ModRM byte is put in the third
--       * byte of the opcode.
-        * FIXME: Update for new optimizer.
--       */
--      X86_POSTOP_SIGNEXT_IMM32
++      X86_POSTOP_ADDRESS16
      } postop;
  } x86_insn;
  
@@@ -267,33 -280,18 +254,17 @@@ void yasm_x86__bc_apply_prefixe
   * 1 if invalid EA, or 2 if indeterminate EA.
   */
  int yasm_x86__expr_checkea
-     (yasm_expr **ep, unsigned char *addrsize, unsigned int bits,
-      unsigned int nosplit, int address16_op, unsigned char *displen,
-      unsigned char *modrm, unsigned char *v_modrm, unsigned char *n_modrm,
-      unsigned char *sib, unsigned char *v_sib, unsigned char *n_sib,
-      unsigned char *pcrel, unsigned char *rex);
- void yasm_x86__parse_cpu(yasm_arch *arch, const char *cpuid,
-                        unsigned long line);
- int yasm_x86__parse_check_reg
-     (yasm_arch *arch, /*@out@*/ unsigned long data[1], const char *id,
-      unsigned long line);
- int yasm_x86__parse_check_reggroup
-     (yasm_arch *arch, /*@out@*/ unsigned long data[1], const char *id,
-      unsigned long line);
- int yasm_x86__parse_check_segreg
-     (yasm_arch *arch, /*@out@*/ unsigned long data[1], const char *id,
-      unsigned long line);
- int yasm_x86__parse_check_insn
-     (yasm_arch *arch, /*@out@*/ unsigned long data[4], const char *id,
-      unsigned long line);
- int yasm_x86__parse_check_prefix
+     (x86_effaddr *x86_ea, unsigned char *addrsize, unsigned int bits,
 -     int address16_op, unsigned char *rex,
 -     yasm_calc_bc_dist_func calc_bc_dist);
++     int address16_op, unsigned char *rex);
+ void yasm_x86__parse_cpu(yasm_arch *arch, const char *cpuid, size_t cpuid_len);
+ yasm_arch_insnprefix yasm_x86__parse_check_insnprefix
      (yasm_arch *arch, /*@out@*/ unsigned long data[4], const char *id,
-      unsigned long line);
int yasm_x86__parse_check_targetmod
-     (yasm_arch *arch, /*@out@*/ unsigned long data[1], const char *id,
-      unsigned long line);
+      size_t id_len);
yasm_arch_regtmod yasm_x86__parse_check_regtmod
+     (yasm_arch *arch, /*@out@*/ unsigned long *data, const char *id,
+      size_t id_len);
  
  void yasm_x86__finalize_insn
      (yasm_arch *arch, yasm_bytecode *bc, yasm_bytecode *prev_bc,
index 7bfc4cc648124922f84e297a8b04f6bf404a9327,62ef563b7118a304af16ba5ac3800e18bca0181c..d5bbfa1832de794e4bfd8ffcff4c084a9c5fdb69
@@@ -69,37 -45,28 +45,37 @@@ static void x86_ea_print(const yasm_eff
  static void x86_bc_insn_destroy(void *contents);
  static void x86_bc_insn_print(const void *contents, FILE *f,
                              int indent_level);
 -static yasm_bc_resolve_flags x86_bc_insn_resolve
 -    (yasm_bytecode *bc, int save, yasm_calc_bc_dist_func calc_bc_dist);
 +static int x86_bc_insn_calc_len(yasm_bytecode *bc,
 +                              yasm_bc_add_span_func add_span,
 +                              void *add_span_data);
 +static int x86_bc_insn_expand(yasm_bytecode *bc, int span, long old_val,
 +                            long new_val, /*@out@*/ long *neg_thres,
 +                            /*@out@*/ long *pos_thres);
  static int x86_bc_insn_tobytes(yasm_bytecode *bc, unsigned char **bufp,
-                              void *d, yasm_output_expr_func output_expr,
+                              void *d, yasm_output_value_func output_value,
                               /*@null@*/ yasm_output_reloc_func output_reloc);
  
  static void x86_bc_jmp_destroy(void *contents);
  static void x86_bc_jmp_print(const void *contents, FILE *f, int indent_level);
 -static yasm_bc_resolve_flags x86_bc_jmp_resolve
 -    (yasm_bytecode *bc, int save, yasm_calc_bc_dist_func calc_bc_dist);
 +static int x86_bc_jmp_calc_len(yasm_bytecode *bc,
 +                             yasm_bc_add_span_func add_span,
 +                             void *add_span_data);
 +static int x86_bc_jmp_expand(yasm_bytecode *bc, int span, long old_val,
 +                           long new_val, /*@out@*/ long *neg_thres,
 +                           /*@out@*/ long *pos_thres);
  static int x86_bc_jmp_tobytes(yasm_bytecode *bc, unsigned char **bufp,
-                             void *d, yasm_output_expr_func output_expr,
+                             void *d, yasm_output_value_func output_value,
                              /*@null@*/ yasm_output_reloc_func output_reloc);
  
  static void x86_bc_jmpfar_destroy(void *contents);
  static void x86_bc_jmpfar_print(const void *contents, FILE *f,
                                int indent_level);
 -static yasm_bc_resolve_flags x86_bc_jmpfar_resolve
 -    (yasm_bytecode *bc, int save, yasm_calc_bc_dist_func calc_bc_dist);
 +static int x86_bc_jmpfar_calc_len(yasm_bytecode *bc,
 +                                yasm_bc_add_span_func add_span,
 +                                void *add_span_data);
  static int x86_bc_jmpfar_tobytes
      (yasm_bytecode *bc, unsigned char **bufp, void *d,
-      yasm_output_expr_func output_expr,
+      yasm_output_value_func output_value,
       /*@null@*/ yasm_output_reloc_func output_reloc);
  
  /* Effective address callback structures */
@@@ -115,27 -82,27 +91,30 @@@ static const yasm_bytecode_callback x86
      x86_bc_insn_destroy,
      x86_bc_insn_print,
      yasm_bc_finalize_common,
 -    x86_bc_insn_resolve,
 +    x86_bc_insn_calc_len,
 +    x86_bc_insn_expand,
-     x86_bc_insn_tobytes
+     x86_bc_insn_tobytes,
+     0
  };
  
  static const yasm_bytecode_callback x86_bc_callback_jmp = {
      x86_bc_jmp_destroy,
      x86_bc_jmp_print,
      yasm_bc_finalize_common,
 -    x86_bc_jmp_resolve,
 +    x86_bc_jmp_calc_len,
 +    x86_bc_jmp_expand,
-     x86_bc_jmp_tobytes
+     x86_bc_jmp_tobytes,
+     0
  };
  
  static const yasm_bytecode_callback x86_bc_callback_jmpfar = {
      x86_bc_jmpfar_destroy,
      x86_bc_jmpfar_print,
      yasm_bc_finalize_common,
 -    x86_bc_jmpfar_resolve,
 +    x86_bc_jmpfar_calc_len,
 +    yasm_bc_expand_common,
-     x86_bc_jmpfar_tobytes
+     x86_bc_jmpfar_tobytes,
+     0
  };
  
  int
@@@ -537,121 -497,189 +509,87 @@@ x86_common_calc_len(const x86_common *c
      return len;
  }
  
 -static yasm_bc_resolve_flags
 -x86_bc_insn_resolve(yasm_bytecode *bc, int save,
 -                  yasm_calc_bc_dist_func calc_bc_dist)
 +static int
 +x86_bc_insn_calc_len(yasm_bytecode *bc, yasm_bc_add_span_func add_span,
 +                   void *add_span_data)
  {
      x86_insn *insn = (x86_insn *)bc->contents;
-     /*@null@*/ yasm_expr *temp;
-     x86_effaddr *x86_ea = (x86_effaddr *)insn->ea;
-     yasm_effaddr *ea = &x86_ea->ea;
+     x86_effaddr *x86_ea = insn->x86_ea;
      yasm_immval *imm = insn->imm;
 -    yasm_bc_resolve_flags retval = YASM_BC_RESOLVE_MIN_LEN;
  
-     if (ea) {
-       if (ea->disp) {
-           /* Handle shortmov special-casing */
-           if (insn->postop == X86_POSTOP_SHORTMOV &&
-               insn->common.mode_bits == 64 && insn->common.addrsize == 32 &&
-               !yasm_expr__contains(ea->disp, YASM_EXPR_REG)) {
-               yasm_x86__ea_set_disponly((yasm_effaddr *)x86_ea);
-               /* Make the short form permanent. */
-               insn->opcode.opcode[0] = insn->opcode.opcode[1];
-           }
+     if (x86_ea) {
 -      /* Create temp copy of disp, etc. */
 -      x86_effaddr eat = *x86_ea;      /* structure copy */
 -
 -      /* Don't overwrite original expression portion */
 -      if (x86_ea->ea.disp.abs)
 -          eat.ea.disp.abs = yasm_expr_copy(x86_ea->ea.disp.abs);
 -
 -      /* Handle shortmov special-casing */
 -      if (insn->postop == X86_POSTOP_SHORTMOV &&
 -          insn->common.mode_bits == 64 && insn->common.addrsize == 32 &&
 -          (!eat.ea.disp.abs ||
 -           !yasm_expr__contains(eat.ea.disp.abs, YASM_EXPR_REG))) {
 -          yasm_x86__ea_set_disponly(&eat);
 -
 -          if (save) {
 -              /* Make the short form permanent. */
 -              insn->opcode.opcode[0] = insn->opcode.opcode[1];
 -          }
 -      }
 -
+       /* Check validity of effective address and calc R/M bits of
+        * Mod/RM byte and SIB byte.  We won't know the Mod field
+        * of the Mod/RM byte until we know more about the
+        * displacement.
+        */
 -      switch (yasm_x86__expr_checkea(&eat, &insn->common.addrsize,
++      if (yasm_x86__expr_checkea(x86_ea, &insn->common.addrsize,
+               insn->common.mode_bits, insn->postop == X86_POSTOP_ADDRESS16,
 -              &insn->rex, calc_bc_dist)) {
 -          case 1:
 -              yasm_expr_destroy(eat.ea.disp.abs);
 -              /* failed, don't bother checking rest of insn */
 -              return YASM_BC_RESOLVE_UNKNOWN_LEN|YASM_BC_RESOLVE_ERROR;
 -          case 2:
 -              yasm_expr_destroy(eat.ea.disp.abs);
 -              /* failed, don't bother checking rest of insn */
 -              return YASM_BC_RESOLVE_UNKNOWN_LEN;
 -          default:
 -              yasm_expr_destroy(eat.ea.disp.abs);
 -              /* okay */
 -              break;
 -      }
 -
 -      if (eat.ea.disp.size != 8) {
 -          /* Fits into a word/dword, or unknown. */
 -          retval = YASM_BC_RESOLVE_NONE;  /* may not be smallest size */
++              &insn->rex))
++          /* failed, don't bother checking rest of insn */
++          return -1;
  
-           /* Check validity of effective address and calc R/M bits of
-            * Mod/RM byte and SIB byte.  We won't know the Mod field
-            * of the Mod/RM byte until we know more about the
-            * displacement.
 -          /* Handle unknown case, make displen word-sized */
 -          if (eat.ea.need_nonzero_len)
 -              eat.ea.disp.size = (insn->common.addrsize == 16) ? 16 : 32;
 -      }
++      if (x86_ea->ea.disp.size == 0) {
++          /* Handle unknown case, default to byte-sized and set as
++           * critical expression.
 +           */
-           if (yasm_x86__expr_checkea(&ea->disp, &insn->common.addrsize,
-                   insn->common.mode_bits, ea->nosplit,
-                   insn->postop == X86_POSTOP_ADDRESS16, &ea->len,
-                   &x86_ea->modrm, &x86_ea->valid_modrm, &x86_ea->need_modrm,
-                   &x86_ea->sib, &x86_ea->valid_sib, &x86_ea->need_sib,
-                   &x86_ea->pcrel, &insn->rex))
-               /* failed, don't bother checking rest of insn */
-               return -1;
-           /* Handle address16 postop case */
-           if (insn->postop == X86_POSTOP_ADDRESS16)
-               insn->common.addrsize = 0;
-           if (ea->len == 0xff) {
-               /* Handle unknown case, default to byte-sized and set as
-                * critical expression.
-                */
-               bc->len += 1;
-               add_span(add_span_data, bc, 1, yasm_expr_copy(ea->disp), -128,
-                        127);
-           } else
-               bc->len += ea->len;
-       }
++          bc->len += 1;
++          add_span(add_span_data, bc, 1, &x86_ea->ea.disp, NULL, -128, 127);
++      } else
++          bc->len + x86_ea->ea.disp.size/8;
+       /* Handle address16 postop case */
+       if (insn->postop == X86_POSTOP_ADDRESS16)
+           insn->common.addrsize = 0;
  
 -      /* If we had forced ea->len but had to override, save it now */
 -      if (x86_ea->ea.disp.size != 0 &&
 -          x86_ea->ea.disp.size != eat.ea.disp.size)
 -          x86_ea->ea.disp.size = eat.ea.disp.size;
 -
 -      if (save) {
 -          eat.ea.disp.abs = x86_ea->ea.disp.abs; /* Copy back original */
 -          *x86_ea = eat;      /* structure copy */
 -          if (x86_ea->ea.disp.size == 0) {
 -              yasm_value_delete(&x86_ea->ea.disp);
 -              x86_ea->ea.need_disp = 0;
 -          }
 -      }
 -
        /* Compute length of ea and add to total */
 -      bc->len += eat.need_modrm + (eat.need_sib ? 1:0) + eat.ea.disp.size/8;
 -      bc->len += (eat.ea.segreg != 0) ? 1 : 0;
 +      bc->len += x86_ea->need_modrm + (x86_ea->need_sib ? 1:0);
 +      bc->len += (x86_ea->ea.segreg != 0) ? 1 : 0;
      }
  
      if (imm) {
-       int immlen = imm->len;
-       if (imm->val) {
-           /* TODO: check imm->len vs. sized len from expr? */
-           /* Handle signext_imm8 postop special-casing */
-           if (insn->postop == X86_POSTOP_SIGNEXT_IMM8) {
-               /*@dependent@*/ /*@null@*/ yasm_intnum *num;
-               num = yasm_expr_get_intnum(&imm->val, NULL);
-               if (num) {
-                   int val = yasm_intnum_get_int(num);
-                   if (val >= -128 && val <= 127) {
-                       /* We can use the sign-extended byte form: shorten
-                        * the immediate length to 1.
-                        */
-                       imm->len = 1;
-                       immlen = 1;
-                   } else {
-                       /* We can't use the ,1. */
-                       insn->opcode.opcode[0] = insn->opcode.opcode[1];
-                   }
-                   insn->postop = X86_POSTOP_NONE;
-               } else {
-                   /* Unknown; default to byte form and set as critical
-                    * expression.
-                    */
-                   immlen = 1;
-                   add_span(add_span_data, bc, 2, yasm_expr_copy(imm->val),
-                            -128, 127);
-               }
-           }
 -      /*@null@*/ yasm_expr *temp = NULL;
 -      const yasm_intnum *num = NULL;
++      yasm_intnum *zero = yasm_intnum_create_uint(0);
++      const yasm_intnum *num = zero;
+       unsigned int immlen = imm->val.size;
+       long val;
  
-           /* Handle shift postop special-casing */
-           if (insn->postop == X86_POSTOP_SHIFT) {
-               /*@dependent@*/ /*@null@*/ yasm_intnum *num;
-               num = yasm_expr_get_intnum(&imm->val, NULL);
-               if (num) {
-                   if (yasm_intnum_get_uint(num) == 1) {
-                       /* We can use the ,1. */
-                       yasm_expr_destroy(imm->val);
-                       yasm_xfree(imm);
-                       insn->imm = NULL;
-                       immlen = 0;
-                   } else {
-                       /* We can't use the ,1. */
-                       insn->opcode.opcode[0] = insn->opcode.opcode[1];
-                   }
-                   insn->postop = X86_POSTOP_NONE;
-               } else {
-                   /* Just assume we can't use the ,1 form: allowing this
-                    * is more work than it's worth.
 -      if (imm->val.abs) {
 -          temp = yasm_expr_copy(imm->val.abs);
 -          assert(temp != NULL);
 -          num = yasm_expr_get_intnum(&temp, calc_bc_dist);
 -      }
++      if (imm->val.abs)
++          num = yasm_expr_get_intnum(&imm->val.abs, NULL);
+       /* TODO: check imm->len vs. sized len from expr? */
 -      switch (insn->postop) {
 -          case X86_POSTOP_SIGNEXT_IMM8:
 -              /* Handle signext_imm8 postop special-casing */
++      /* Handle signext_imm8 postop special-casing */
++      if (insn->postop == X86_POSTOP_SIGNEXT_IMM8) {
++          if (imm->val.rel || num) {
+               if (imm->val.rel)
 -                  val = 1000;     /* has relative portion, don't collapse */
 -              else if (num)
 -                  val = yasm_intnum_get_int(num);
++                  val = 1000; /* has relative portion, don't collapse */
+               else
 -                  val = 0;
++                  val = yasm_intnum_get_int(num);
+               if (val >= -128 && val <= 127) {
+                   /* We can use the sign-extended byte form: shorten
 -                   * the immediate length to 1.
++                   * the immediate length to 1 and make the byte form
++                   * permanent.
                     */
-                   insn->opcode.opcode[0] = insn->opcode.opcode[1];
-                   insn->postop = X86_POSTOP_NONE;
++                  imm->val.size = 8;
+                   immlen = 8;
 -                  if (save) {
 -                      /* Make the byte form permanent. */
 -                      insn->opcode.opcode[0] = insn->opcode.opcode[1];
 -                      imm->val.size = 8;
 -                      if (insn->opcode.opcode[2] != 0) {
 -                          insn->opcode.opcode[1] = insn->opcode.opcode[2];
 -                          insn->opcode.len++;
 -                      }
 -                  } else if (insn->opcode.opcode[2] != 0)
 -                      bc->len++;
 -              }
 -              /* Not really necessary, but saves confusion over it. */
 -              if (save)
 -                  insn->postop = X86_POSTOP_NONE;
 -              break;
 -
 -          case X86_POSTOP_SIGNEXT_IMM32:
 -              /* Handle signext_imm32 postop special-casing */
 -              if (!num || yasm_intnum_check_size(num, 32, 0, 1)) {
 -                  bc->len++;  /* Due to ModRM byte */
 -                  immlen = 32;
 -                  if (save) {
 -                      /* Throwaway REX byte */
 -                      unsigned char rex_temp = 0;
 -
 -                      /* Build ModRM EA - CAUTION: this depends on
 -                       * opcode 0 being a mov instruction!
 -                       */
 -                      insn->x86_ea = yasm_x86__ea_create_reg(
 -                          (unsigned long)insn->opcode.opcode[0]-0xB8,
 -                          &rex_temp, 64);
 -
 -                      /* Make the imm32s form permanent. */
 -                      insn->opcode.opcode[0] = insn->opcode.opcode[1];
 -                      imm->val.size = 32;
++                  if (insn->opcode.opcode[2] != 0) {
++                      insn->opcode.opcode[1] = insn->opcode.opcode[2];
++                      insn->opcode.len++;
+                   }
                }
 -              /* Not really necessary, but saves confusion over it. */
 -              if (save)
 -                  insn->postop = X86_POSTOP_NONE;
 -              break;
 -
 -          case X86_POSTOP_SHIFT:
 -              /* Handle shift postop special-casing */
 -              if (num && yasm_intnum_get_uint(num) == 1) {
 -                  /* We can use the ,1 form: no imm (set to 0 len) */
 -                  immlen = 0;
 -
 -                  if (save) {
 -                      /* Make the ,1 form permanent. */
 -                      insn->opcode.opcode[0] = insn->opcode.opcode[1];
 -                      /* Delete imm, as it's not needed. */
 -                      yasm_value_delete(&imm->val);
 -                      yasm_xfree(imm);
 -                      insn->imm = (yasm_immval *)NULL;
 -                  }
 -              } else
 -                  retval = YASM_BC_RESOLVE_NONE;  /* could still get ,1 */
 -
 -              /* Not really necessary, but saves confusion over it. */
 -              if (save)
 -                  insn->postop = X86_POSTOP_NONE;
 -              break;
 -
 -          default:
 -              break;
++              insn->postop = X86_POSTOP_NONE;
++          } else {
++              /* Unknown; default to byte form and set as critical
++               * expression.
++               */
++              immlen = 8;
++              add_span(add_span_data, bc, 2, &imm->val, NULL, -128, 127);
 +          }
        }
  
-       bc->len += immlen;
 -      yasm_expr_destroy(temp);
++      yasm_intnum_destroy(zero);
+       bc->len += immlen/8;
      }
  
      bc->len += insn->opcode.len;
         (insn->common.mode_bits == 64 && insn->common.opersize == 64 &&
          insn->def_opersize_64 != 64)))
        bc->len++;
-     x86_effaddr *x86_ea = (x86_effaddr *)insn->ea;
 +    return 0;
 +}
 +
 +static int
 +x86_bc_insn_expand(yasm_bytecode *bc, int span, long old_val, long new_val,
 +                 /*@out@*/ long *neg_thres, /*@out@*/ long *pos_thres)
 +{
 +    x86_insn *insn = (x86_insn *)bc->contents;
 +    /*@null@*/ yasm_expr *temp;
-     if (ea && ea->disp) {
++    x86_effaddr *x86_ea = insn->x86_ea;
 +    yasm_effaddr *ea = &x86_ea->ea;
 +    yasm_immval *imm = insn->imm;
 +
-       if (ea->len == 0xff) {
-           ea->len = (insn->common.addrsize == 16) ? 2U : 4U;
++    if (ea && ea->disp.abs) {
 +      /* Change displacement length into word-sized */
-           bc->len += ea->len;
++      if (ea->disp.size == 0) {
++          ea->disp.size = (insn->common.addrsize == 16) ? 16 : 32;
 +          x86_ea->modrm &= ~0300;
 +          x86_ea->modrm |= 0200;
 +          bc->len--;
++          bc->len += ea->disp.size/8;
 +      }
 +    }
  
-     if (imm && imm->val) {
 -    return retval;
++    if (imm && imm->val.abs) {
 +      if (insn->postop == X86_POSTOP_SIGNEXT_IMM8) {
 +          bc->len--;
-           bc->len += imm->len;
++          bc->len += imm->val.size/8;
 +          insn->postop = X86_POSTOP_NONE;
 +      }
 +    }
 +
 +    return 0;
  }
  
 -static yasm_bc_resolve_flags
 -x86_bc_jmp_resolve(yasm_bytecode *bc, int save,
 -                 yasm_calc_bc_dist_func calc_bc_dist)
 +static int
 +x86_bc_jmp_calc_len(yasm_bytecode *bc, yasm_bc_add_span_func add_span,
 +                  void *add_span_data)
  {
      x86_jmp *jmp = (x86_jmp *)bc->contents;
 -    yasm_bc_resolve_flags retval = YASM_BC_RESOLVE_MIN_LEN;
+     yasm_bytecode *target_prevbc;
+     /*@null@*/ yasm_expr *temp;
+     /*@only@*/ yasm_intnum *num;
+     /*@dependent@*/ /*@null@*/ yasm_intnum *num2;
+     long rel;
      unsigned char opersize;
 -    x86_jmp_opcode_sel jrtype = JMP_NONE;
  
      /* As opersize may be 0, figure out its "real" value. */
      opersize = (jmp->common.opersize == 0) ?
        jmp->common.mode_bits : jmp->common.opersize;
  
 -    /* We only check to see if forced forms are actually legal if we're in
 -     * save mode.  Otherwise we assume that they are legal.
 -     */
 -    switch (jmp->op_sel) {
 -      case JMP_SHORT_FORCED:
 -          /* 1 byte relative displacement */
 -          jrtype = JMP_SHORT;
 -          if (save) {
 -              /* does a short form exist? */
 -              if (jmp->shortop.len == 0) {
 -                  yasm_error_set(YASM_ERROR_TYPE,
 -                                 N_("short jump does not exist"));
 -                  return YASM_BC_RESOLVE_ERROR | YASM_BC_RESOLVE_UNKNOWN_LEN;
 -              }
 -
 -              if (!jmp->target.rel)
 -                  num = yasm_intnum_create_uint(0);
 -              else if (!yasm_symrec_get_label(jmp->target.rel, &target_prevbc)
 -                       || target_prevbc->section != jmp->origin_prevbc->section
 -                       || !(num = calc_bc_dist(jmp->origin_prevbc,
 -                                               target_prevbc))) {
 -                  /* External or out of segment, so we can't check distance.
 -                   * This depends on the objfmt supporting 8-bit relocs.
 -                   * While most don't, some might, so allow it.  The objfmt
 -                   * will error if not supported.
 -                   */
 -                  break;
 -              }
 +    bc->len += x86_common_calc_len(&jmp->common);
  
 -              if (jmp->target.abs) {
 -                  temp = yasm_expr_copy(jmp->target.abs);
 -                  num2 = yasm_expr_get_intnum(&temp, calc_bc_dist);
 -                  if (!num2) {
 -                      yasm_expr_destroy(temp);
 -                      yasm_error_set(YASM_ERROR_TOO_COMPLEX,
 -                                     N_("jump target too complex"));
 -                      return YASM_BC_RESOLVE_ERROR |
 -                          YASM_BC_RESOLVE_UNKNOWN_LEN;
 -                  }
 -                  yasm_intnum_calc(num, YASM_EXPR_ADD, num2);
 -                  yasm_expr_destroy(temp);
 -              }
 +    if (jmp->op_sel == JMP_NEAR_FORCED || jmp->shortop.len == 0) {
 +      if (jmp->nearop.len == 0) {
-           yasm__error(bc->line, N_("near jump does not exist"));
++          yasm_error_set(YASM_ERROR_TYPE, N_("near jump does not exist"));
 +          return -1;
 +      }
  
 -              rel = yasm_intnum_get_int(num);
 -              yasm_intnum_destroy(num);
 -              rel -= jmp->shortop.len+1;
 -              /* short displacement must fit in -128 <= rel <= +127 */
 -              if (rel < -128 || rel > 127) {
 -                  yasm_error_set(YASM_ERROR_OVERFLOW,
 -                                 N_("short jump out of range"));
 -                  return YASM_BC_RESOLVE_ERROR | YASM_BC_RESOLVE_UNKNOWN_LEN;
 -              }
 -          }
 -          break;
 -      case JMP_NEAR_FORCED:
 -          /* 2/4 byte relative displacement (depending on operand size) */
 -          jrtype = JMP_NEAR;
 -          if (save) {
 -              if (jmp->nearop.len == 0) {
 -                  yasm_error_set(YASM_ERROR_TYPE,
 -                                 N_("near jump does not exist"));
 -                  return YASM_BC_RESOLVE_ERROR | YASM_BC_RESOLVE_UNKNOWN_LEN;
 -              }
 -          }
 -          break;
 -      default:
 -          /* Due to code in x86_finalize_jmp(), we can only get here if
 -           * there's BOTH short and near opcodes available, and it wasn't
 -           * forced by the user.
 -           */
 -          if (!jmp->target.rel)
 -              num = yasm_intnum_create_uint(0);
 -          else if (!yasm_symrec_get_label(jmp->target.rel, &target_prevbc)
 -                   || target_prevbc->section != jmp->origin_prevbc->section
 -                   || !(num = calc_bc_dist(jmp->origin_prevbc,
 -                                           target_prevbc))) {
 -              /* It's unknown.  Thus, assume near displacement. */
 -              jrtype = JMP_NEAR;
 -              retval = YASM_BC_RESOLVE_NONE;
 -              break;
 -          }
 +      /* Near jump, no spans needed */
 +      bc->len += jmp->nearop.len;
 +      bc->len += (opersize == 16) ? 2 : 4;
 +      return 0;
 +    }
  
 -          /* Try to find shortest displacement based on difference between
 -           * target expr value and origin offset.
 -           */
 -          if (jmp->target.abs) {
 -              temp = yasm_expr_copy(jmp->target.abs);
 -              num2 = yasm_expr_get_intnum(&temp, calc_bc_dist);
 -              if (!num2) {
 -                  yasm_expr_destroy(temp);
 -                  yasm_error_set(YASM_ERROR_TOO_COMPLEX,
 -                                 N_("jump target too complex"));
 -                  return YASM_BC_RESOLVE_ERROR | YASM_BC_RESOLVE_UNKNOWN_LEN;
 -              }
 -              yasm_intnum_calc(num, YASM_EXPR_ADD, num2);
 -              yasm_expr_destroy(temp);
 -          }
 +    if (jmp->op_sel == JMP_SHORT_FORCED || jmp->nearop.len == 0) {
 +      if (jmp->shortop.len == 0) {
-           yasm__error(bc->line, N_("short jump does not exist"));
++          yasm_error_set(YASM_ERROR_TYPE, N_("short jump does not exist"));
 +          return -1;
 +      }
  
 -          rel = yasm_intnum_get_int(num);
 -          yasm_intnum_destroy(num);
 -          rel -= jmp->shortop.len+1;
 -          /* short displacement must fit within -128 <= rel <= +127 */
 -          if (rel >= -128 && rel <= 127) {
 -              /* It fits into a short displacement. */
 -              jrtype = JMP_SHORT;
 -          } else {
 -              /* Near for now, but could get shorter in the future as
 -               * there's a short form available.
 -               */
 -              jrtype = JMP_NEAR;
 -              retval = YASM_BC_RESOLVE_NONE;
 -          }
 -          break;
 +      /* We want to be sure to error if we exceed short length, so
 +       * put it in as a dependent expression (falling through).
 +       */
      }
  
-     /* Short jump, generate span */
 -    switch (jrtype) {
 -      case JMP_SHORT:
 -          if (save)
 -              jmp->op_sel = JMP_SHORT;
 -          if (jmp->shortop.len == 0)
 -              return YASM_BC_RESOLVE_UNKNOWN_LEN; /* size not available */
 -
++    if (jmp->target.rel
++      && (!yasm_symrec_get_label(jmp->target.rel, &target_prevbc)
++          || target_prevbc->section != jmp->origin_prevbc->section)) {
++      /* External or out of segment, so we can't check distance.
++       * Allowing forced short jumps depends on the objfmt supporting
++       * 8-bit relocs.  While most don't, some might, so allow it here.
++       * Otherwise default to word-sized.
++       * The objfmt will error if not supported.
++       */
++      if (jmp->op_sel == JMP_SHORT_FORCED || jmp->nearop.len == 0) {
+           bc->len += jmp->shortop.len + 1;
 -          break;
 -      case JMP_NEAR:
 -          if (save)
 -              jmp->op_sel = JMP_NEAR;
 -          if (jmp->nearop.len == 0)
 -              return YASM_BC_RESOLVE_UNKNOWN_LEN; /* size not available */
 -
++      } else {
+           bc->len += jmp->nearop.len;
+           bc->len += (opersize == 16) ? 2 : 4;
 -          break;
 -      default:
 -          yasm_internal_error(N_("unknown jump type"));
++      }
++      return 0;
++    }
++
++    /* Default to short jump and generate span */
 +    bc->len += jmp->shortop.len + 1;
-     add_span(add_span_data, bc, 1,
-            yasm_expr_create(YASM_EXPR_SUB,
-                             yasm_expr_expr(yasm_expr_copy(jmp->target)),
-                             yasm_expr_sym(jmp->origin), bc->line),
-            -128, 127);
++    add_span(add_span_data, bc, 1, &jmp->target, jmp->origin_prevbc, -128, 127);
 +    return 0;
 +}
 +
 +static int
 +x86_bc_jmp_expand(yasm_bytecode *bc, int span, long old_val, long new_val,
 +                /*@out@*/ long *neg_thres, /*@out@*/ long *pos_thres)
 +{
 +    x86_jmp *jmp = (x86_jmp *)bc->contents;
 +    unsigned char opersize;
 +
 +    if (span != 1)
 +      yasm_internal_error(N_("unrecognized span id"));
 +
 +    /* As opersize may be 0, figure out its "real" value. */
 +    opersize = (jmp->common.opersize == 0) ?
 +      jmp->common.mode_bits : jmp->common.opersize;
 +
 +    if (jmp->nearop.len == 0) {
-       yasm__error(bc->line, N_("short jump out of range"));
++      yasm_error_set(YASM_ERROR_VALUE, N_("short jump out of range"));
 +      return -1;
      }
 -    bc->len += x86_common_resolve(&jmp->common);
  
 -    return retval;
 +    /* Upgrade to a near jump */
 +    jmp->op_sel = JMP_NEAR;
 +    bc->len -= jmp->shortop.len + 1;
 +    bc->len += jmp->nearop.len;
 +    bc->len += (opersize == 16) ? 2 : 4;
 +
 +    return 0;
  }
  
 -static yasm_bc_resolve_flags
 -x86_bc_jmpfar_resolve(yasm_bytecode *bc, int save,
 -                    yasm_calc_bc_dist_func calc_bc_dist)
 +static int
 +x86_bc_jmpfar_calc_len(yasm_bytecode *bc, yasm_bc_add_span_func add_span,
 +                     void *add_span_data)
  {
      x86_jmpfar *jmpfar = (x86_jmpfar *)bc->contents;
      unsigned char opersize;
@@@ -860,40 -941,43 +816,42 @@@ x86_bc_insn_tobytes(yasm_bytecode *bc, 
            YASM_WRITE_8(*bufp, x86_ea->sib);
        }
  
-       if (ea->disp) {
-           /* Simplify expression */
-           ea->disp = yasm_expr_simplify(ea->disp, yasm_common_calc_bc_dist);
-           if (x86_ea->pcrel) {
-               /*@null@*/ yasm_expr *wrt = yasm_expr_extract_wrt(&ea->disp);
-               ea->disp =
-                   yasm_expr_create(YASM_EXPR_SUB, yasm_expr_expr(ea->disp),
-                                    yasm_expr_sym(x86_ea->origin), bc->line);
-               if (wrt) {
-                   ea->disp =
-                       yasm_expr_create(YASM_EXPR_WRT,
-                                        yasm_expr_expr(ea->disp),
-                                        yasm_expr_expr(wrt), bc->line);
-               }
-               if (output_expr(&ea->disp, *bufp, ea->len,
-                               (size_t)(ea->len*8), 0,
-                               (unsigned long)(*bufp-bufp_orig), bc, 1, 1,
-                               d))
-                   return 1;
-           } else {
-               if (output_expr(&ea->disp, *bufp, ea->len,
-                               (size_t)(ea->len*8), 0,
-                               (unsigned long)(*bufp-bufp_orig), bc, 0, 1,
-                               d))
-                   return 1;
+       if (x86_ea->ea.need_disp) {
+           x86_effaddr eat = *x86_ea;  /* structure copy */
+           unsigned char addrsize = insn->common.addrsize;
+           unsigned int disp_len = x86_ea->ea.disp.size/8;
+           eat.valid_modrm = 0;    /* force checkea to actually run */
+           if (x86_ea->ea.disp.abs) {
+               /* Call checkea() to simplify the registers out of the
+                * displacement.  Throw away all of the return values except
+                * for the modified expr.
+                */
+               if (yasm_x86__expr_checkea
+                   (&eat, &addrsize, insn->common.mode_bits,
 -                   insn->postop == X86_POSTOP_ADDRESS16, &insn->rex,
 -                   yasm_common_calc_bc_dist))
++                   insn->postop == X86_POSTOP_ADDRESS16, &insn->rex))
+                   yasm_internal_error(N_("checkea failed"));
+               x86_ea->ea.disp.abs = eat.ea.disp.abs;
            }
-           *bufp += ea->len;
-       } else {
-           /* 0 displacement, but we didn't know it before, so we have to
-            * write out 0 value.
-            * FIXME: Is this still needed?
-            */
-           for (i=0; i<ea->len; i++)
-               YASM_WRITE_8(*bufp, 0);
+           if (x86_ea->ea.disp.ip_rel) {
+               /* Adjust relative displacement to end of bytecode */
+               /*@only@*/ yasm_intnum *delta;
+               delta = yasm_intnum_create_int(-(long)bc->len);
+               if (!x86_ea->ea.disp.abs)
+                   x86_ea->ea.disp.abs =
+                       yasm_expr_create_ident(yasm_expr_int(delta), bc->line);
+               else
+                   x86_ea->ea.disp.abs =
+                       yasm_expr_create(YASM_EXPR_ADD,
+                                        yasm_expr_expr(x86_ea->ea.disp.abs),
+                                        yasm_expr_int(delta), bc->line);
+           }
+           if (output_value(&x86_ea->ea.disp, *bufp, disp_len,
+                            (unsigned long)(*bufp-bufp_orig), bc, 1, d))
+               return 1;
+           *bufp += disp_len;
        }
      }
  
index 1570e8b7cf3f142db7e136fdffb2c9392055ffa7,b83d79794056d64461064e74a5950a53b8d5572a..01a1cb4587b39a808f20768d8b560d0591b1f0bb
@@@ -247,22 -247,47 +247,46 @@@ x86_expr_checkea_distcheck_reg(yasm_exp
   * and 0 if all values successfully determined and saved in data.
   */
  static int
- x86_expr_checkea_getregusage(yasm_expr **ep, /*@null@*/ yasm_expr **wrt,
-     /*@null@*/ int *indexreg, unsigned char *pcrel, unsigned int bits,
-     void *data, int *(*get_reg)(yasm_expr__item *ei, int *regnum, void *d))
+ x86_expr_checkea_getregusage(yasm_expr **ep, /*@null@*/ int *indexreg,
+     int *pcrel, unsigned int bits, void *data,
 -    int *(*get_reg)(yasm_expr__item *ei, int *regnum, void *d),
 -    yasm_calc_bc_dist_func calc_bc_dist)
++    int *(*get_reg)(yasm_expr__item *ei, int *regnum, void *d))
  {
      int i;
      int *reg;
      int regnum;
      int indexval = 0;
      int indexmult = 0;
-     yasm_expr *e;
+     yasm_expr *e, *wrt;
  
      /*@-unqualifiedtrans@*/
-     *ep = yasm_expr__level_tree(*ep, 1, indexreg == 0, NULL, NULL, NULL, NULL);
-     if (*wrt)
-       *wrt = yasm_expr__level_tree(*wrt, 1, indexreg == 0, NULL, NULL, NULL,
-                                    NULL);
 -    *ep = yasm_expr__level_tree(*ep, 1, 1, indexreg == 0, calc_bc_dist, NULL,
 -                              NULL, NULL);
++    *ep = yasm_expr__level_tree(*ep, 1, 1, indexreg == 0, NULL, NULL, NULL,
++                              NULL);
+     /* Check for WRT rip first */
+     wrt = yasm_expr_extract_wrt(ep);
+     if (wrt && wrt->op == YASM_EXPR_IDENT &&
+       wrt->terms[0].type == YASM_EXPR_REG) {
+       if (bits != 64) {   /* only valid in 64-bit mode */
+           yasm_expr_destroy(wrt);
+           return 1;
+       }
+       reg = get_reg(&wrt->terms[0], &regnum, data);
+       if (!reg || regnum != 16) { /* only accept rip */
+           yasm_expr_destroy(wrt);
+           return 1;
+       }
+       (*reg)++;
+       /* Delete WRT.  Set pcrel to 1 to indicate to x86
+        * bytecode code to do PC-relative displacement transform.
+        */
+       *pcrel = 1;
+       yasm_expr_destroy(wrt);
+     } else if (wrt) {
+       yasm_expr_destroy(wrt);
+       return 1;
+     }
      /*@=unqualifiedtrans@*/
      assert(*ep != NULL);
      e = *ep;
@@@ -464,57 -469,63 +463,76 @@@ x86_checkea_calc_displen(x86_effaddr *x
        } else if (dispreq) {
            /* for BP/EBP, there *must* be a displacement value, but we
             * may not know the size (8 or 16/32) for sure right now.
-            * We can't leave displen at 0, because that just means
-            * unknown displacement, including none.
             */
-           *displen = 0xff;
-           *modrm |= 0100;
-           *v_modrm = 1;
+           x86_ea->ea.need_nonzero_len = 1;
++          x86_ea->modrm |= 0100;
++          x86_ea->valid_modrm = 1;
++          return 0;
+       }
 -      if (x86_ea->ea.disp.rel ||
 -          (x86_ea->ea.disp.abs &&
 -           !(intn = yasm_expr_get_intnum(&x86_ea->ea.disp.abs, NULL)))) {
 -          /* expr still has unknown values or is relative:
 -           * assume 16/32-bit disp
 -           */
++      /* Relative displacement; basically all object formats need non-byte
++       * for relocation here, so just do that.
++       */
++      if (x86_ea->ea.disp.rel)
+           x86_ea->ea.disp.size = wordsize;
 -          x86_ea->modrm |= 0200;
 -          x86_ea->valid_modrm = 1;
 -          return 0;
 -      }       
+       /* don't try to find out what size displacement we have if
+        * displen is known.
+        */
+       if (x86_ea->ea.disp.size != 0) {
+           if (x86_ea->ea.disp.size == 8)
+               x86_ea->modrm |= 0100;
+           else
+               x86_ea->modrm |= 0200;
+           x86_ea->valid_modrm = 1;
            return 0;
        }
  
-       intn = yasm_expr_get_intnum(ep, NULL);
-       if (!intn) {
 +      /* At this point there's 3 possibilities for the displacement:
 +       *  - None (if =0)
 +       *  - signed 8 bit (if in -128 to 127 range)
 +       *  - 16/32 bit (word size)
 +       * For now, check intnum value right now; if it's not 0,
 +       * assume 8 bit and set up for allowing 16 bit later.
 +       * FIXME: this should really set up two thresholds, one for 8-bit
 +       * expansion and one for 16-bit expansion.  The complex expression
 +       * equaling zero is probably a rare case, so we ignore it for now.
 +       */
-           *displen = 0xff;
-           *modrm |= 0100;
-           *v_modrm = 1;
++      if (x86_ea->ea.disp.abs &&
++          !(intn = yasm_expr_get_intnum(&x86_ea->ea.disp.abs, NULL))) {
 +          /* expr still has unknown values: treat like BP/EBP above */
-       }
++          x86_ea->ea.need_nonzero_len = 1;
++          x86_ea->modrm |= 0100;
++          x86_ea->valid_modrm = 1;
 +          return 0;
-       dispval = yasm_intnum_get_int(intn);
++      }       
 +
+       if (intn)
+           dispval = yasm_intnum_get_int(intn);
+       else
+           dispval = 0;
  
        /* Figure out what size displacement we will have. */
-       if (dispval == 0) {
+       if (!x86_ea->ea.need_nonzero_len && dispval == 0) {
            /* if we know that the displacement is 0 right now,
-            * go ahead and delete the expr (making it so no
-            * displacement value is included in the output).
+            * go ahead and delete the expr and make it so no
+            * displacement value is included in the output.
             * The Mod bits of ModRM are set to 0 above, and
             * we're done with the ModRM byte!
 -           *
 -           * Don't do this if we came from dispreq check above, so
 -           * check *displen.
             */
-           yasm_expr_destroy(e);
-           *ep = (yasm_expr *)NULL;
+           yasm_expr_destroy(x86_ea->ea.disp.abs);
+           x86_ea->ea.disp.abs = NULL;
+           x86_ea->ea.need_disp = 0;
        } else if (dispval >= -128 && dispval <= 127) {
            /* It fits into a signed byte */
-           *displen = 1;
-           *modrm |= 0100;
+           x86_ea->ea.disp.size = 8;
+           x86_ea->modrm |= 0100;
        } else {
            /* It's a 16/32-bit displacement */
-           *displen = wordsize;
-           *modrm |= 0200;
+           x86_ea->ea.disp.size = wordsize;
+           x86_ea->modrm |= 0200;
        }
-       *v_modrm = 1;   /* We're done with ModRM */
+       x86_ea->valid_modrm = 1;        /* We're done with ModRM */
      }
  
      return 0;
@@@ -547,21 -558,12 +565,11 @@@ x86_expr_checkea_getregsize_callback(ya
  }
  
  int
- yasm_x86__expr_checkea(yasm_expr **ep, unsigned char *addrsize,
-                      unsigned int bits, unsigned int nosplit,
-                      int address16_op, unsigned char *displen,
-                      unsigned char *modrm, unsigned char *v_modrm,
-                      unsigned char *n_modrm, unsigned char *sib,
-                      unsigned char *v_sib, unsigned char *n_sib,
-                      unsigned char *pcrel, unsigned char *rex)
+ yasm_x86__expr_checkea(x86_effaddr *x86_ea, unsigned char *addrsize,
 -                     unsigned int bits, int address16_op, unsigned char *rex,
 -                     yasm_calc_bc_dist_func calc_bc_dist)
++                     unsigned int bits, int address16_op, unsigned char *rex)
  {
-     yasm_expr *e, *wrt;
      int retval;
  
-     /* First split off any top-level WRT.  We'll add it back in at the end */
-     wrt = yasm_expr_extract_wrt(ep);
-     e = *ep;
      if (*addrsize == 0) {
        /* we need to figure out the address size from what we know about:
         * - the displacement length
        reg3264_data.regs = reg3264mult;
        reg3264_data.bits = bits;
        reg3264_data.addrsize = *addrsize;
-       if (x86_expr_checkea_getregusage(ep, &wrt, &indexreg, pcrel, bits,
-                                        &reg3264_data,
-                                        x86_expr_checkea_get_reg3264)) {
-           yasm__error((*ep)->line, N_("invalid effective address"));
-           return 1;
+       if (x86_ea->ea.disp.abs) {
+           int pcrel = 0;
+           switch (x86_expr_checkea_getregusage
+                   (&x86_ea->ea.disp.abs, &indexreg, &pcrel, bits,
 -                   &reg3264_data, x86_expr_checkea_get_reg3264,
 -                   calc_bc_dist)) {
++                   &reg3264_data, x86_expr_checkea_get_reg3264)) {
+               case 1:
+                   yasm_error_set(YASM_ERROR_VALUE,
+                                  N_("invalid effective address"));
+                   return 1;
+               case 2:
+                   if (pcrel) {
+                       x86_ea->ea.disp.curpos_rel = 1;
+                       x86_ea->ea.disp.ip_rel = 1;
+                   }
+                   return 2;
+               default:
+                   if (pcrel) {
+                       x86_ea->ea.disp.curpos_rel = 1;
+                       x86_ea->ea.disp.ip_rel = 1;
+                   }
+                   break;
+           }
        }
-       e = *ep;
  
        /* If indexreg mult is 0, discard it.
         * This is possible because of the way indexreg is found in
        }
  
        /* 16-bit cannot have SIB */
-       *sib = 0;
-       *v_sib = 0;
-       *n_sib = 0;
-       if (x86_expr_checkea_getregusage(ep, &wrt, NULL, pcrel, bits,
-                                        &reg16mult,
-                                        x86_expr_checkea_get_reg16)) {
-           yasm__error((*ep)->line, N_("invalid effective address"));
-           return 1;
+       x86_ea->sib = 0;
+       x86_ea->valid_sib = 0;
+       x86_ea->need_sib = 0;
+       if (x86_ea->ea.disp.abs) {
+           int pcrel = 0;
+           switch (x86_expr_checkea_getregusage
+                   (&x86_ea->ea.disp.abs, (int *)NULL, &pcrel, bits,
 -                   &reg16mult, x86_expr_checkea_get_reg16, calc_bc_dist)) {
++                   &reg16mult, x86_expr_checkea_get_reg16)) {
+               case 1:
+                   yasm_error_set(YASM_ERROR_VALUE,
+                                  N_("invalid effective address"));
+                   return 1;
+               case 2:
+                   if (pcrel) {
+                       x86_ea->ea.disp.curpos_rel = 1;
+                       x86_ea->ea.disp.ip_rel = 1;
+                   }
+                   return 2;
+               default:
+                   if (pcrel) {
+                       x86_ea->ea.disp.curpos_rel = 1;
+                       x86_ea->ea.disp.ip_rel = 1;
+                   }
+                   break;
+           }
        }
-       e = *ep;
  
        /* reg multipliers not 0 or 1 are illegal. */
        if (reg16mult.bx & ~1 || reg16mult.si & ~1 || reg16mult.di & ~1 ||
index 7f1d50aa1b9b3d37eb244f69f9b4f1d520a1869c,03770ae2ce6e8db58bb4ffa119499fc25e3915c5..f0245707de1d1aa929f38100eaa86db282876877
@@@ -106,6 -108,6 +108,7 @@@ RCSID("$Id$")
   *             14 = CR4
   *             15 = memory offset (an EA, but with no registers allowed)
   *                  [special case for MOV opcode]
++ *             16 = immediate, value=1 (for special-case shift)
   *  - 3 bits = size (user-specified, or from register size):
   *             0 = any size acceptable/no size spec acceptable (dep. on strict)
   *             1/2/3/4 = 8/16/32/64 bits (from user or reg size)
   *             9 = operand size goes into address size (jmp only)
   *             A = far jump (outputs a farjmp instead of normal insn)
   * The below describes postponed actions: actions which can't be completed at
-- * parse-time due to things like EQU and complex expressions.  For these, some
++ * parse-time due to possibly dependent expressions.  For these, some
   * additional data (stored in the second byte of the opcode with a one-byte
   * opcode) is passed to later stages of the assembler with flags set to
   * indicate postponed actions.
   *  - 3 bits = postponed action:
   *             0 = none
-- *             1 = shift operation with a ,1 short form (instead of imm8).
-- *             2 = large imm16/32 that can become a sign-extended imm8.
-- *             3 = could become a short opcode mov with bits=64 and a32 prefix
-- *             4 = forced 16-bit address size (override ignored, no prefix)
-- *             5 = large imm64 that can become a sign-extended imm32.
++ *             1 = large imm16/32 that can become a sign-extended imm8.
++ *             2 = could become a short opcode mov with bits=64 and a32 prefix
++ *             3 = forced 16-bit address size (override ignored, no prefix)
++ *             4 = large imm64 that can become a sign-extended imm32.
   */
  #define OPT_Imm               0x0
  #define OPT_Reg               0x1
  #define OPT_SS                0x13
  #define OPT_CR4               0x14
  #define OPT_MemOffs   0x15
++#define OPT_Imm1      0x16
  #define OPT_MASK      0x1F
  
  #define OPS_Any               (0UL<<5)
  #define OPA_MASK      (0xFUL<<13)
  
  #define OPAP_None     (0UL<<17)
--#define OPAP_ShiftOp  (1UL<<17)
--#define OPAP_SImm8Avail       (2UL<<17)
--#define OPAP_ShortMov (3UL<<17)
--#define OPAP_A16      (4UL<<17)
--#define OPAP_SImm32Avail (5UL<<17)
++#define OPAP_SImm8Avail       (1UL<<17)
++#define OPAP_ShortMov (2UL<<17)
++#define OPAP_A16      (3UL<<17)
++#define OPAP_SImm32Avail (4UL<<17)
  #define OPAP_MASK     (7UL<<17)
  
  typedef struct x86_insn_info {
@@@ -1075,33 -1073,28 +1073,28 @@@ static const x86_insn_info imul_insn[] 
  static const x86_insn_info shift_insn[] = {
      { CPU_Any, MOD_SpAdd|MOD_GasSufB, 0, 0, 0, 1, {0xD2, 0, 0}, 0, 2,
        {OPT_RM|OPS_8|OPA_EA, OPT_Creg|OPS_8|OPA_None, 0} },
--    /* FIXME: imm8 is only avail on 186+, but we use imm8 to get to postponed
--     * ,1 form, so it has to be marked as Any.  We need to store the active
--     * CPU flags somewhere to pass that parse-time info down the line.
--     */
-     { CPU_Any, MOD_SpAdd|MOD_GasSufB, 0, 0, 0, 1, {0xD0, 0xC0, 0}, 0, 2,
 -    { CPU_Any, MOD_SpAdd|MOD_GasSufB, 0, 0, 0, 1, {0xC0, 0xD0, 0}, 0, 2,
--      {OPT_RM|OPS_8|OPA_EA, OPT_Imm|OPS_8|OPS_Relaxed|OPA_Imm|OPAP_ShiftOp,
--       0} },
++    { CPU_Any, MOD_SpAdd|MOD_GasSufB, 0, 0, 0, 1, {0xD0, 0, 0}, 0, 2,
++      {OPT_RM|OPS_8|OPA_EA, OPT_Imm1|OPS_8|OPS_Relaxed|OPA_None, 0} },
++    { CPU_186, MOD_SpAdd|MOD_GasSufB, 0, 0, 0, 1, {0xC0, 0, 0}, 0, 2,
++      {OPT_RM|OPS_8|OPA_EA, OPT_Imm|OPS_8|OPS_Relaxed|OPA_Imm, 0} },
      { CPU_Any, MOD_SpAdd|MOD_GasSufW, 16, 0, 0, 1, {0xD3, 0, 0}, 0, 2,
        {OPT_RM|OPS_16|OPA_EA, OPT_Creg|OPS_8|OPA_None, 0} },
-     { CPU_Any, MOD_SpAdd|MOD_GasSufW, 16, 0, 0, 1, {0xD1, 0xC1, 0}, 0, 2,
 -    { CPU_Any, MOD_SpAdd|MOD_GasSufW, 16, 0, 0, 1, {0xC1, 0xD1, 0}, 0, 2,
--      {OPT_RM|OPS_16|OPA_EA, OPT_Imm|OPS_8|OPS_Relaxed|OPA_Imm|OPAP_ShiftOp,
--       0} },
++    { CPU_Any, MOD_SpAdd|MOD_GasSufW, 16, 0, 0, 1, {0xD1, 0, 0}, 0, 2,
++      {OPT_RM|OPS_16|OPA_EA, OPT_Imm1|OPS_8|OPS_Relaxed|OPA_None, 0} },
++    { CPU_186, MOD_SpAdd|MOD_GasSufW, 16, 0, 0, 1, {0xC1, 0, 0}, 0, 2,
++      {OPT_RM|OPS_16|OPA_EA, OPT_Imm|OPS_8|OPS_Relaxed|OPA_Imm, 0} },
      { CPU_Any, MOD_SpAdd|MOD_GasSufL, 32, 0, 0, 1, {0xD3, 0, 0}, 0, 2,
        {OPT_RM|OPS_32|OPA_EA, OPT_Creg|OPS_8|OPA_None, 0} },
-     { CPU_Any, MOD_SpAdd|MOD_GasSufL, 32, 0, 0, 1, {0xD1, 0xC1, 0}, 0, 2,
 -    { CPU_Any, MOD_SpAdd|MOD_GasSufL, 32, 0, 0, 1, {0xC1, 0xD1, 0}, 0, 2,
--      {OPT_RM|OPS_32|OPA_EA, OPT_Imm|OPS_8|OPS_Relaxed|OPA_Imm|OPAP_ShiftOp,
-        0} },
-     { CPU_Hammer|CPU_64, MOD_SpAdd, 64, 0, 0, 1, {0xD3, 0, 0}, 0, 2,
-       {OPT_RM|OPS_64|OPA_EA, OPT_Creg|OPS_8|OPA_None, 0} },
-     { CPU_Hammer|CPU_64, MOD_SpAdd, 64, 0, 0, 1, {0xD1, 0xC1, 0}, 0, 2,
-       {OPT_RM|OPS_64|OPA_EA, OPT_Imm|OPS_8|OPS_Relaxed|OPA_Imm|OPAP_ShiftOp,
--       0} },
++    { CPU_386, MOD_SpAdd|MOD_GasSufL, 32, 0, 0, 1, {0xD1, 0, 0}, 0, 2,
++      {OPT_RM|OPS_32|OPA_EA, OPT_Imm1|OPS_8|OPS_Relaxed|OPA_None, 0} },
++    { CPU_386, MOD_SpAdd|MOD_GasSufL, 32, 0, 0, 1, {0xC1, 0, 0}, 0, 2,
++      {OPT_RM|OPS_32|OPA_EA, OPT_Imm|OPS_8|OPS_Relaxed|OPA_Imm, 0} },
      { CPU_Hammer|CPU_64, MOD_SpAdd|MOD_GasSufQ, 64, 0, 0, 1, {0xD3, 0, 0}, 0,
        2, {OPT_RM|OPS_64|OPA_EA, OPT_Creg|OPS_8|OPA_None, 0} },
-     { CPU_Hammer|CPU_64, MOD_SpAdd|MOD_GasSufQ, 64, 0, 0, 1, {0xD1, 0xC1, 0},
 -    { CPU_Hammer|CPU_64, MOD_SpAdd|MOD_GasSufQ, 64, 0, 0, 1, {0xC1, 0xD1, 0},
--      0, 2, {OPT_RM|OPS_64|OPA_EA,
--           OPT_Imm|OPS_8|OPS_Relaxed|OPA_Imm|OPAP_ShiftOp, 0} },
++    { CPU_Hammer|CPU_64, MOD_SpAdd|MOD_GasSufQ, 64, 0, 0, 1, {0xD1, 0, 0},
++      0, 2, {OPT_RM|OPS_64|OPA_EA, OPT_Imm1|OPS_8|OPS_Relaxed|OPA_None, 0} },
++    { CPU_Hammer|CPU_64, MOD_SpAdd|MOD_GasSufQ, 64, 0, 0, 1, {0xC1, 0, 0},
++      0, 2, {OPT_RM|OPS_64|OPA_EA, OPT_Imm|OPS_8|OPS_Relaxed|OPA_Imm, 0} },
      /* In GAS mode, single operands are equivalent to shifting by 1 forms */
      { CPU_Any, MOD_SpAdd|MOD_GasOnly|MOD_GasSufB, 0, 0, 0, 1, {0xD0, 0, 0},
        0, 1, {OPT_RM|OPS_8|OPA_EA, 0, 0} },
@@@ -2207,7 -2234,9 +2234,10 @@@ yasm_x86__finalize_insn(yasm_arch *arch
      unsigned char im_sign;
      unsigned char spare;
      int i;
-     static const unsigned int size_lookup[] = {0, 1, 2, 4, 8, 10, 16, 0};
+     unsigned int size_lookup[] = {0, 8, 16, 32, 64, 80, 128, 0};
++    unsigned long do_postop = 0;
+     size_lookup[7] = mode_bits;
  
      if (!info) {
        num_info = 1;
                                            YASM_EXPR_REG))
                        mismatch = 1;
                    break;
++              case OPT_Imm1:
++                  if (op->type == YASM_INSN__OPERAND_IMM) {
++                      const yasm_intnum *num;
++                      num = yasm_expr_get_intnum(&op->data.val, NULL);
++                      if (!num || !yasm_intnum_is_pos1(num))
++                          mismatch = 1;
++                  } else
++                      mismatch = 1;
++                  break;
                default:
                    yasm_internal_error(N_("invalid operand type"));
            }
            switch ((int)(info->operands[i] & OPAP_MASK)) {
                case OPAP_None:
                    break;
--              case OPAP_ShiftOp:
--                  insn->postop = X86_POSTOP_SHIFT;
--                  break;
                case OPAP_SImm8Avail:
                    insn->postop = X86_POSTOP_SIGNEXT_IMM8;
                    break;
                case OPAP_ShortMov:
--                  insn->postop = X86_POSTOP_SHORTMOV;
++                  do_postop = OPAP_ShortMov;
                    break;
                case OPAP_A16:
                    insn->postop = X86_POSTOP_ADDRESS16;
                    break;
                case OPAP_SImm32Avail:
--                  insn->postop = X86_POSTOP_SIGNEXT_IMM32;
++                  do_postop = OPAP_SImm32Avail;
                    break;
                default:
                    yasm_internal_error(
        insn->common.addrsize = 0;
      }
  
++    /* Handle non-span-dependent post-ops here */
++    switch (do_postop) {
++      case OPAP_ShortMov:
++          /* Long (modrm+sib) mov instructions in amd64 can be optimized into
++           * short mov instructions if a 32-bit address override is applied in
++           * 64-bit mode to an EA of just an offset (no registers) and the
++           * target register is al/ax/eax/rax.
++           */
++          if (insn->common.mode_bits == 64 && insn->common.addrsize == 32 &&
++              (!insn->x86_ea->ea.disp.abs ||
++               !yasm_expr__contains(insn->x86_ea->ea.disp.abs,
++                                    YASM_EXPR_REG))) {
++              yasm_x86__ea_set_disponly(insn->x86_ea);
++              /* Make the short form permanent. */
++              insn->opcode.opcode[0] = insn->opcode.opcode[1];
++          }
++          insn->opcode.opcode[1] = 0; /* avoid possible confusion */
++          break;
++      case OPAP_SImm32Avail:
++          /* Used for 64-bit mov immediate, which can take a sign-extended
++           * imm32 as well as imm64 values.  The imm32 form is put in the
++           * second byte of the opcode and its ModRM byte is put in the third
++           * byte of the opcode.
++           */
++          if (!insn->imm->val.abs ||
++              yasm_intnum_check_size(
++                  yasm_expr_get_intnum(&insn->imm->val.abs, NULL),
++                  32, 0, 1)) {
++              /* Throwaway REX byte */
++              unsigned char rex_temp = 0;
++
++              /* Build ModRM EA - CAUTION: this depends on
++               * opcode 0 being a mov instruction!
++               */
++              insn->x86_ea = yasm_x86__ea_create_reg(
++                  (unsigned long)insn->opcode.opcode[0]-0xB8, &rex_temp, 64);
++
++              /* Make the imm32s form permanent. */
++              insn->opcode.opcode[0] = insn->opcode.opcode[1];
++              insn->imm->val.size = 32;
++          }
++          insn->opcode.opcode[1] = 0; /* avoid possible confusion */
++          break;
++      default:
++          break;
++    }
++
      /* Transform the bytecode */
      yasm_x86__bc_transform_insn(bc, insn);
  }
index 809221981ed5b00c7f853f07e4f9afff01438f9b,cf0a5ffdf4164f4e4eeae5cfe900a6c6492ddf33..845b3a7d7f9199a0ce64c7e703b06fddb1a240f5
@@@ -3,5 -5,7 +5,7 @@@ EXTRA_DIST += modules/dbgfmts/dwarf2/Ma
  EXTRA_DIST += modules/dbgfmts/null/Makefile.inc
  EXTRA_DIST += modules/dbgfmts/stabs/Makefile.inc
  
+ include modules/dbgfmts/codeview/Makefile.inc
+ include modules/dbgfmts/dwarf2/Makefile.inc
  include modules/dbgfmts/null/Makefile.inc
 -include modules/dbgfmts/stabs/Makefile.inc
 +#include modules/dbgfmts/stabs/Makefile.inc
index 0000000000000000000000000000000000000000,dc0c3ab4ab275f61805ef3cf32e03d25f2ada96c..78c1059a0998fe70a7a24192828c204d7e335e02
mode 000000,100644..100644
--- /dev/null
@@@ -1,0 -1,1102 +1,1106 @@@
 -static yasm_bc_resolve_flags cv8_symhead_bc_resolve
 -    (yasm_bytecode *bc, int save, yasm_calc_bc_dist_func calc_bc_dist);
+ /*
+  * CodeView debugging format - symbol and line information
+  *
+  *  Copyright (C) 2006  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.
+  * 3. Neither the name of the author nor the names of other contributors
+  *    may be used to endorse or promote products derived from this
+  *    software without specific prior written permission.
+  *
+  * 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
+ #include <libyasm.h>
+ #include "cv-dbgfmt.h"
+ enum cv8_symheadtype {
+     CV8_DEBUG_SYMS    = 0xF1, /* CV5 symbol information */
+     CV8_LINE_NUMS     = 0xF2, /* line numbers for a section */
+     CV8_FILE_STRTAB   = 0xF3, /* filename string table */
+     CV8_FILE_INFO     = 0xF4  /* source file info */
+ };
+ enum cv_symtype {
+     /* Non-modal Symbols */
+     CV_S_COMPILE      = 0x0001,       /* Compile Flag */
+     CV_S_REGISTER     = 0x0002,       /* Register */
+     CV_S_CONSTANT     = 0x0003,       /* Constant */
+     CV_S_UDT          = 0x0004,       /* User-defined Type */
+     CV_S_SSEARCH      = 0x0005,       /* Start Search */
+     CV_S_END          = 0x0006,       /* End of Block */
+     CV_S_SKIP         = 0x0007,       /* Skip Record */
+     CV_S_OBJNAME      = 0x0009,       /* Object File Name */
+     CV_S_ENDARG               = 0x000a,       /* End of Arguments */
+     CV_S_COBOLUDT     = 0x000b,       /* COBOL User-defined Type */
+     CV_S_MANYREG      = 0x000c,       /* Many Registers */
+     CV_S_RETURN               = 0x000d,       /* Function Return */
+     CV_S_ENTRYTHIS    = 0x000e,       /* "this" at Method Entry */
+     /* Symbols for 16:16 Segmented Architectures */
+     CV_S_BPREL16      = 0x0100,       /* BP Relative 16:16 */
+     CV_S_LDATA16      = 0x0101,       /* Local Data 16:16 */
+     CV_S_GDATA16      = 0x0102,       /* Global Data Symbol 16:16 */
+     CV_S_PUB16                = 0x0103,       /* Public Symbol 16:16 */
+     CV_S_LPROC16      = 0x0104,       /* Local Start 16:16 */
+     CV_S_GPROC16      = 0x0105,       /* Global Start 16:16 */
+     CV_S_THUNK16      = 0x0106,       /* Thunk Start 16:16 */
+     CV_S_BLOCK16      = 0x0107,       /* Block Start 16:16 */
+     CV_S_WITH16               = 0x0108,       /* With Start 16:16 */
+     CV_S_LABEL16      = 0x0109,       /* Code Label 16:16 */
+     CV_S_CEXMODEL16   = 0x0110,       /* Change Execution Model 16:16 */
+     CV_S_VFTPATH16    = 0x010b,       /* Virtual Function Table Path 16:16 */
+     CV_S_REGREL16     = 0x010c,       /* Register Relative 16:16 */
+     /* Symbols for 16:32 Segmented Architectures */
+     CV_S_BPREL32      = 0x0200,       /* BP Relative 16:32 */
+     CV_S_LDATA32      = 0x0201,       /* Local Data 16:32 */
+     CV_S_GDATA32      = 0x0202,       /* Global Data Symbol 16:32 */
+     CV_S_PUB32                = 0x0203,       /* Public Symbol 16:32 */
+     CV_S_LPROC32      = 0x0204,       /* Local Start 16:32 */
+     CV_S_GPROC32      = 0x0205,       /* Global Start 16:32 */
+     CV_S_THUNK32      = 0x0206,       /* Thunk Start 16:32 */
+     CV_S_BLOCK32      = 0x0207,       /* Block Start 16:32 */
+     CV_S_WITH32               = 0x0208,       /* With Start 16:32 */
+     CV_S_LABEL32      = 0x0209,       /* Code Label 16:32 */
+     CV_S_CEXMODEL32   = 0x0210,       /* Change Execution Model 16:32 */
+     CV_S_VFTPATH32    = 0x020b,       /* Virtual Function Table Path 16:32 */
+     CV_S_REGREL32     = 0x020c,       /* Register Relative 16:32 */
+     CV_S_LTHREAD32    = 0x020d,       /* Local Thread Storage 16:32 */
+     CV_S_GTHREAD32    = 0x020e,       /* Global Thread Storage 16:32 */
+     /* Symbols for MIPS */
+     CV_S_LPROCMIPS    = 0x0300,       /* Local procedure start MIPS */
+     CV_S_GPROCMIPS    = 0x0301,       /* Global procedure start MIPS */
+     /* Symbols for CV8 - strings are 0 terminated rather than length-prefix.
+      * Incomplete and unofficial.
+      */
+     CV8_S_OBJNAME     = 0x1101,       /* Object File Name */
+     CV8_S_LABEL32     = 0x1105,       /* Code Label 16:32 */
+     CV8_S_LDATA32     = 0x110c,       /* Local Data 16:32 */
+     CV8_S_GDATA32     = 0x110d,       /* Global Data 16:32 */
+     CV8_S_LPROC32     = 0x1110,       /* Local Start 16:32 */
+     CV8_S_COMPILE     = 0x1116        /* Compile Flag */
+ };
+ typedef struct cv8_symhead {
+     yasm_dbgfmt_cv *dbgfmt_cv;
+     enum cv8_symheadtype type;
+     yasm_bytecode *start_prevbc;
+     yasm_bytecode *end_prevbc;
+     int first;            /* nonzero if first symhead in section */
+ } cv8_symhead;
+ typedef struct cv8_fileinfo {
+     yasm_dbgfmt_cv *dbgfmt_cv;
+     const cv_filename *fn;
+ } cv8_fileinfo;
+ /* Note: each line number group is associated with a file AND a section */
+ typedef struct cv8_linepair {
+     unsigned long offset;
+     unsigned long line;
+ } cv8_linepair;
+ /* Decrease linked list overhead a bit doing it this way */
+ typedef struct cv8_lineset {
+     STAILQ_ENTRY(cv8_lineset) link;
+     cv8_linepair pairs[126];
+     size_t num_pairs;
+ } cv8_lineset;
+ typedef struct cv8_lineinfo {
+     STAILQ_ENTRY(cv8_lineinfo) link;
+     yasm_dbgfmt_cv *dbgfmt_cv;
+     const cv_filename *fn;    /* filename associated with line numbers */
+     yasm_section *sect;               /* section line numbers are for */
+     yasm_symrec *sectsym;     /* symbol for beginning of sect */
+     unsigned long num_linenums;
+     STAILQ_HEAD(, cv8_lineset) linesets;
+ } cv8_lineinfo;
+ /* Symbols use a bit of meta-programming to encode formats: each character
+  * of format represents the output generated, as follows:
+  * 'b' : 1 byte value (integer)
+  * 'h' : 2 byte value (integer)
+  * 'w' : 4 byte value (integer)
+  * 'Y' : symrec SECREL+SECTION (pointer)
+  * 'T' : type index (integer)
+  * 'S' : length-prefixed string (pointer)
+  * 'Z' : 0-terminated string (pointer)
+  */
+ typedef struct cv_sym {
+     yasm_dbgfmt_cv *dbgfmt_cv;
+     enum cv_symtype type;
+     const char *format;
+     union {
+       unsigned long i;
+       void *p;
+     } args[10];
+ } cv_sym;
+ /* Bytecode callback function prototypes */
+ static void cv8_symhead_bc_destroy(void *contents);
+ static void cv8_symhead_bc_print(const void *contents, FILE *f,
+                                int indent_level);
 -static yasm_bc_resolve_flags cv8_fileinfo_bc_resolve
 -    (yasm_bytecode *bc, int save, yasm_calc_bc_dist_func calc_bc_dist);
++static int cv8_symhead_bc_calc_len
++    (yasm_bytecode *bc, yasm_bc_add_span_func add_span, void *add_span_data);
+ static int cv8_symhead_bc_tobytes
+     (yasm_bytecode *bc, unsigned char **bufp, void *d,
+      yasm_output_value_func output_value,
+      /*@null@*/ yasm_output_reloc_func output_reloc);
+ static void cv8_fileinfo_bc_destroy(void *contents);
+ static void cv8_fileinfo_bc_print(const void *contents, FILE *f,
+                                 int indent_level);
 -static yasm_bc_resolve_flags cv8_lineinfo_bc_resolve
 -    (yasm_bytecode *bc, int save, yasm_calc_bc_dist_func calc_bc_dist);
++static int cv8_fileinfo_bc_calc_len
++    (yasm_bytecode *bc, yasm_bc_add_span_func add_span, void *add_span_data);
+ static int cv8_fileinfo_bc_tobytes
+     (yasm_bytecode *bc, unsigned char **bufp, void *d,
+      yasm_output_value_func output_value,
+      /*@null@*/ yasm_output_reloc_func output_reloc);
+ static void cv8_lineinfo_bc_destroy(void *contents);
+ static void cv8_lineinfo_bc_print(const void *contents, FILE *f,
+                                 int indent_level);
 -static yasm_bc_resolve_flags cv_sym_bc_resolve
 -    (yasm_bytecode *bc, int save, yasm_calc_bc_dist_func calc_bc_dist);
++static int cv8_lineinfo_bc_calc_len
++    (yasm_bytecode *bc, yasm_bc_add_span_func add_span, void *add_span_data);
+ static int cv8_lineinfo_bc_tobytes
+     (yasm_bytecode *bc, unsigned char **bufp, void *d,
+      yasm_output_value_func output_value,
+      /*@null@*/ yasm_output_reloc_func output_reloc);
+ static void cv_sym_bc_destroy(void *contents);
+ static void cv_sym_bc_print(const void *contents, FILE *f, int indent_level);
 -    cv8_symhead_bc_resolve,
++static int cv_sym_bc_calc_len
++    (yasm_bytecode *bc, yasm_bc_add_span_func add_span, void *add_span_data);
+ static int cv_sym_bc_tobytes
+     (yasm_bytecode *bc, unsigned char **bufp, void *d,
+      yasm_output_value_func output_value,
+      /*@null@*/ yasm_output_reloc_func output_reloc);
+ /* Bytecode callback structures */
+ static const yasm_bytecode_callback cv8_symhead_bc_callback = {
+     cv8_symhead_bc_destroy,
+     cv8_symhead_bc_print,
+     yasm_bc_finalize_common,
 -    cv8_fileinfo_bc_resolve,
++    cv8_symhead_bc_calc_len,
++    yasm_bc_expand_common,
+     cv8_symhead_bc_tobytes,
+     0
+ };
+ static const yasm_bytecode_callback cv8_fileinfo_bc_callback = {
+     cv8_fileinfo_bc_destroy,
+     cv8_fileinfo_bc_print,
+     yasm_bc_finalize_common,
 -    cv8_lineinfo_bc_resolve,
++    cv8_fileinfo_bc_calc_len,
++    yasm_bc_expand_common,
+     cv8_fileinfo_bc_tobytes,
+     0
+ };
+ static const yasm_bytecode_callback cv8_lineinfo_bc_callback = {
+     cv8_lineinfo_bc_destroy,
+     cv8_lineinfo_bc_print,
+     yasm_bc_finalize_common,
 -    cv_sym_bc_resolve,
++    cv8_lineinfo_bc_calc_len,
++    yasm_bc_expand_common,
+     cv8_lineinfo_bc_tobytes,
+     0
+ };
+ static const yasm_bytecode_callback cv_sym_bc_callback = {
+     cv_sym_bc_destroy,
+     cv_sym_bc_print,
+     yasm_bc_finalize_common,
 -    yasm_bc_resolve(bc, 0, NULL);
++    cv_sym_bc_calc_len,
++    yasm_bc_expand_common,
+     cv_sym_bc_tobytes,
+     0
+ };
+ static cv8_symhead *cv8_add_symhead(yasm_dbgfmt_cv *dbgfmt_cv,
+                                   yasm_section *sect, unsigned long type,
+                                   int first);
+ static void cv8_set_symhead_end(cv8_symhead *head, yasm_bytecode *end_prevbc);
+ static yasm_bytecode *cv8_add_fileinfo
+     (yasm_dbgfmt_cv *dbgfmt_cv, yasm_section *sect, const cv_filename *fn);
+ static unsigned long cv_sym_size(const cv_sym *cvs);
+ static cv_sym *
+ cv8_add_sym_objname(yasm_dbgfmt_cv *dbgfmt_cv, yasm_section *sect,
+                   /*@keep@*/ char *objname)
+ {
+     yasm_bytecode *bc;
+     cv_sym *cvs = yasm_xmalloc(sizeof(cv_sym));
+     cvs->dbgfmt_cv = dbgfmt_cv;
+     cvs->type = CV8_S_OBJNAME;
+     cvs->format = "wZ";
+     cvs->args[0].i = 0;               /* signature (0=asm) */
+     cvs->args[1].p = objname; /* object filename */
+     bc = yasm_bc_create_common(&cv_sym_bc_callback, cvs, 0);
+     bc->len = cv_sym_size(cvs);
+     yasm_cv__append_bc(sect, bc);
+     return cvs;
+ }
+ static cv_sym *
+ cv8_add_sym_compile(yasm_dbgfmt_cv *dbgfmt_cv, yasm_section *sect,
+                   /*@keep@*/ char *creator)
+ {
+     yasm_bytecode *bc;
+     cv_sym *cvs = yasm_xmalloc(sizeof(cv_sym));
+     cvs->dbgfmt_cv = dbgfmt_cv;
+     cvs->type = CV8_S_COMPILE;
+     cvs->format = "wwwwZh";
+     cvs->args[0].i = 3;               /* language (3=Masm) */
+     /* target processor; 0xD0 = AMD64 */
+     if (strcmp(yasm_arch_keyword(dbgfmt_cv->arch), "x86") == 0) {
+       if (strcmp(yasm_arch_get_machine(dbgfmt_cv->arch), "amd64") == 0)
+           cvs->args[1].i = 0xD0;
+       else
+           cvs->args[1].i = 0x6;       /* 686, FIXME */
+     } else
+       cvs->args[1].i = 0;             /* XXX: unknown */
+     cvs->args[2].i = 0;               /* flags (assume 0 for now) */
+     cvs->args[3].i = 0;               /* creator version number (assume 0 for now) */
+     cvs->args[4].p = creator; /* creator string */
+     cvs->args[5].i = 0;               /* no pairs of key/value */
+     bc = yasm_bc_create_common(&cv_sym_bc_callback, cvs, 0);
+     bc->len = cv_sym_size(cvs);
+     yasm_cv__append_bc(sect, bc);
+     return cvs;
+ }
+ static cv_sym *
+ cv8_add_sym_label(yasm_dbgfmt_cv *dbgfmt_cv, yasm_section *sect,
+                 yasm_symrec *sym)
+ {
+     yasm_bytecode *bc;
+     cv_sym *cvs = yasm_xmalloc(sizeof(cv_sym));
+     cvs->dbgfmt_cv = dbgfmt_cv;
+     cvs->type = CV8_S_LABEL32;
+     cvs->format = "YbZ";
+     cvs->args[0].p = sym;     /* symrec for label */
+     cvs->args[1].i = 0;               /* flags (assume 0 for now) */
+     cvs->args[2].p = yasm__xstrdup(yasm_symrec_get_name(sym));
+     bc = yasm_bc_create_common(&cv_sym_bc_callback, cvs, 0);
+     bc->len = cv_sym_size(cvs);
+     yasm_cv__append_bc(sect, bc);
+     return cvs;
+ }
+ static cv_sym *
+ cv8_add_sym_data(yasm_dbgfmt_cv *dbgfmt_cv, yasm_section *sect,
+                unsigned long type, yasm_symrec *sym, int is_global)
+ {
+     yasm_bytecode *bc;
+     cv_sym *cvs = yasm_xmalloc(sizeof(cv_sym));
+     cvs->dbgfmt_cv = dbgfmt_cv;
+     cvs->type = is_global ? CV8_S_GDATA32 : CV8_S_LDATA32;
+     cvs->format = "wYZ";
+     cvs->args[0].i = type;    /* type index */
+     cvs->args[1].p = sym;     /* symrec for label */
+     cvs->args[2].p = yasm__xstrdup(yasm_symrec_get_name(sym));
+     bc = yasm_bc_create_common(&cv_sym_bc_callback, cvs, 0);
+     bc->len = cv_sym_size(cvs);
+     yasm_cv__append_bc(sect, bc);
+     return cvs;
+ }
+ static size_t
+ cv_dbgfmt_add_file(yasm_dbgfmt_cv *dbgfmt_cv, size_t filenum,
+                  const char *filename)
+ {
+     char *pathname;
+     size_t i;
+     yasm_md5_context context;
+     FILE *f;
+     unsigned char *buf;
+     size_t len;
+     /* Put the filename into the filename table */
+     if (filenum == 0) {
+       /* Look to see if we already have that filename in the table */
+       for (; filenum<dbgfmt_cv->filenames_size; filenum++) {
+           if (!dbgfmt_cv->filenames[filenum].filename ||
+               strcmp(dbgfmt_cv->filenames[filenum].filename, filename) == 0)
+               break;
+       }
+     } else
+       filenum--;      /* array index is 0-based */
+     /* Realloc table if necessary */
+     if (filenum >= dbgfmt_cv->filenames_allocated) {
+       size_t old_allocated = dbgfmt_cv->filenames_allocated;
+       dbgfmt_cv->filenames_allocated = filenum+32;
+       dbgfmt_cv->filenames = yasm_xrealloc(dbgfmt_cv->filenames,
+           sizeof(cv_filename)*dbgfmt_cv->filenames_allocated);
+       for (i=old_allocated; i<dbgfmt_cv->filenames_allocated; i++) {
+           dbgfmt_cv->filenames[i].pathname = NULL;
+           dbgfmt_cv->filenames[i].filename = NULL;
+           dbgfmt_cv->filenames[i].str_off = 0;
+           dbgfmt_cv->filenames[i].info_off = 0;
+       }
+     }
+     /* Calculate MD5 checksum of file */
+     buf = yasm_xmalloc(1024);
+     yasm_md5_init(&context);
+     f = fopen(filename, "rb");
+     if (!f)
+       yasm__fatal(N_("codeview: could not open source file"));
+     while ((len = fread(buf, 1, 1024, f)) > 0)
+       yasm_md5_update(&context, buf, len);
+     yasm_md5_final(dbgfmt_cv->filenames[filenum].digest, &context);
+     fclose(f);
+     yasm_xfree(buf);
+     /* Actually save in table */
+     if (dbgfmt_cv->filenames[filenum].pathname)
+       yasm_xfree(dbgfmt_cv->filenames[filenum].pathname);
+     if (dbgfmt_cv->filenames[filenum].filename)
+       yasm_xfree(dbgfmt_cv->filenames[filenum].filename);
+     pathname = yasm__abspath(filename);
+     dbgfmt_cv->filenames[filenum].pathname = pathname;
+     dbgfmt_cv->filenames[filenum].filename = yasm__xstrdup(filename);
+     /* Update table size */
+     if (filenum >= dbgfmt_cv->filenames_size)
+       dbgfmt_cv->filenames_size = filenum + 1;
+     return filenum;
+ }
+ static yasm_bytecode *
+ cv_append_str(yasm_section *sect, const char *str)
+ {
+     yasm_datavalhead dvs;
+     yasm_bytecode *bc;
+     yasm_dvs_initialize(&dvs);
+     yasm_dvs_append(&dvs, yasm_dv_create_string(yasm__xstrdup(str),
+                                               strlen(str)));
+     bc = yasm_bc_create_data(&dvs, 1, 1, NULL, 0);
+     yasm_bc_finalize(bc, yasm_cv__append_bc(sect, bc));
 -    yasm_bc_resolve(bc, 0, NULL);
++    yasm_bc_calc_len(bc, NULL, NULL);
+     return bc;
+ }
+ typedef struct cv_line_info {
+     yasm_section *debug_symline;
+     yasm_dbgfmt_cv *dbgfmt_cv;
+     yasm_errwarns *errwarns;
+     unsigned int num_lineinfos;
+     STAILQ_HEAD(, cv8_lineinfo) cv8_lineinfos;
+     /*@null@*/ cv8_lineinfo *cv8_cur_li;
+     /*@null@*/ cv8_lineset *cv8_cur_ls;
+ } cv_line_info;
+ static int
+ cv_generate_line_bc(yasm_bytecode *bc, /*@null@*/ void *d)
+ {
+     cv_line_info *info = (cv_line_info *)d;
+     yasm_dbgfmt_cv *dbgfmt_cv = info->dbgfmt_cv;
+     size_t i;
+     const char *filename;
+     unsigned long line;
+     /*@null@*/ yasm_bytecode *nextbc = yasm_bc__next(bc);
+     yasm_section *sect = yasm_bc_get_section(bc);
+     if (nextbc && bc->offset == nextbc->offset)
+       return 0;
+     yasm_linemap_lookup(dbgfmt_cv->linemap, bc->line, &filename, &line);
+     if (!info->cv8_cur_li
+       || strcmp(filename, info->cv8_cur_li->fn->filename) != 0) {
+       yasm_bytecode *sectbc;
+       char symname[8];
+       /* first see if we already have a lineinfo that is for this section and
+        * filename
+        */
+       STAILQ_FOREACH(info->cv8_cur_li, &info->cv8_lineinfos, link) {
+           if (sect == info->cv8_cur_li->sect
+               && strcmp(filename, info->cv8_cur_li->fn->filename) == 0)
+               break;
+       }
+       if (info->cv8_cur_li) {
+           info->cv8_cur_ls = STAILQ_LAST(&info->cv8_cur_li->linesets,
+                                          cv8_lineset, link);
+           goto done;          /* found one */
+       }
+       /* Nope; find file */
+       for (i=0; i<dbgfmt_cv->filenames_size; i++) {
+           if (strcmp(filename, dbgfmt_cv->filenames[i].filename) == 0)
+               break;
+       }
+       if (i >= dbgfmt_cv->filenames_size)
+           yasm_internal_error(N_("could not find filename in table"));
+       /* and create new lineinfo structure */
+       info->cv8_cur_li = yasm_xmalloc(sizeof(cv8_lineinfo));
+       info->cv8_cur_li->dbgfmt_cv = dbgfmt_cv;
+       info->cv8_cur_li->fn = &dbgfmt_cv->filenames[i];
+       info->cv8_cur_li->sect = sect;
+       sectbc = yasm_section_bcs_first(sect);
+       if (sectbc->symrecs && sectbc->symrecs[0])
+           info->cv8_cur_li->sectsym = sectbc->symrecs[0];
+       else {
+           sprintf(symname, ".%06u", info->num_lineinfos++);
+           info->cv8_cur_li->sectsym =
+               yasm_symtab_define_label(dbgfmt_cv->symtab, symname, sectbc,
+                                        1, 0);
+       }
+       info->cv8_cur_li->num_linenums = 0;
+       STAILQ_INIT(&info->cv8_cur_li->linesets);
+       STAILQ_INSERT_TAIL(&info->cv8_lineinfos, info->cv8_cur_li, link);
+       info->cv8_cur_ls = NULL;
+     }
+ done:
+     /* build new lineset if necessary */
+     if (!info->cv8_cur_ls || info->cv8_cur_ls->num_pairs >= 126) {
+       info->cv8_cur_ls = yasm_xmalloc(sizeof(cv8_lineset));
+       info->cv8_cur_ls->num_pairs = 0;
+       STAILQ_INSERT_TAIL(&info->cv8_cur_li->linesets, info->cv8_cur_ls, link);
+     }
+     /* add linepair for this bytecode */
+     info->cv8_cur_ls->pairs[info->cv8_cur_ls->num_pairs].offset = bc->offset;
+     info->cv8_cur_ls->pairs[info->cv8_cur_ls->num_pairs].line =
+       0x80000000 | line;
+     info->cv8_cur_ls->num_pairs++;
+     info->cv8_cur_li->num_linenums++;
+     return 0;
+ }
+ static int
+ cv_generate_line_section(yasm_section *sect, /*@null@*/ void *d)
+ {
+     cv_line_info *info = (cv_line_info *)d;
+     if (!yasm_section_is_code(sect))
+       return 0;       /* not code, so no line data for this section */
+     info->cv8_cur_li = NULL;
+     info->cv8_cur_ls = NULL;
+     yasm_section_bcs_traverse(sect, info->errwarns, info, cv_generate_line_bc);
+     return 0;
+ }
+ static int
+ cv_generate_filename(const char *filename, void *d)
+ {
+     yasm_dbgfmt_cv *dbgfmt_cv = (yasm_dbgfmt_cv *)d;
+     cv_dbgfmt_add_file(dbgfmt_cv, 0, filename);
+     return 0;
+ }
+ static int
+ cv_generate_sym(yasm_symrec *sym, void *d)
+ {
+     cv_line_info *info = (cv_line_info *)d;
+     yasm_bytecode *precbc;
+     /* only care about labels (for now) */
+     if (!yasm_symrec_get_label(sym, &precbc))
+       return 0;
+     /* TODO: add data types; until then, just mark everything as UBYTE */
+     if (yasm_section_is_code(yasm_bc_get_section(precbc)))
+       cv8_add_sym_label(info->dbgfmt_cv, info->debug_symline, sym);
+     else
+       cv8_add_sym_data(info->dbgfmt_cv, info->debug_symline, 0x20, sym,
+           yasm_symrec_get_visibility(sym) & YASM_SYM_GLOBAL?1:0);
+     return 0;
+ }
+ yasm_section *
+ yasm_cv__generate_symline(yasm_dbgfmt_cv *dbgfmt_cv, yasm_errwarns *errwarns)
+ {
+     cv_line_info info;
+     int new;
+     size_t i;
+     cv8_symhead *head;
+     cv8_lineinfo *li;
+     yasm_bytecode *bc;
+     unsigned long off;
+     /* Generate filenames based on linemap */
+     yasm_linemap_traverse_filenames(dbgfmt_cv->linemap, dbgfmt_cv,
+                                   cv_generate_filename);
+     info.dbgfmt_cv = dbgfmt_cv;
+     info.errwarns = errwarns;
+     info.debug_symline = yasm_object_get_general(dbgfmt_cv->object,
+                                                ".debug$S", 0, 1, 0, 0, &new,
+                                                0);
+     info.num_lineinfos = 0;
+     STAILQ_INIT(&info.cv8_lineinfos);
+     info.cv8_cur_li = NULL;
+     info.cv8_cur_ls = NULL;
+     /* source filenames string table */
+     head = cv8_add_symhead(dbgfmt_cv, info.debug_symline, CV8_FILE_STRTAB, 1);
+     cv_append_str(info.debug_symline, "");
+     off = 1;
+     for (i=0; i<dbgfmt_cv->filenames_size; i++) {
+       if (!dbgfmt_cv->filenames[i].pathname) {
+           yasm_error_set(YASM_ERROR_GENERAL,
+                          N_("codeview file number %d unassigned"), i+1);
+           yasm_errwarn_propagate(errwarns, 0);
+           continue;
+       }
+       bc = cv_append_str(info.debug_symline,
+                          dbgfmt_cv->filenames[i].pathname);
+       dbgfmt_cv->filenames[i].str_off = off;
+       off += bc->len;
+     }
+     cv8_set_symhead_end(head, yasm_section_bcs_last(info.debug_symline));
+     /* Align 4 */
+     bc = yasm_bc_create_align
+       (yasm_expr_create_ident(yasm_expr_int(yasm_intnum_create_uint(4)), 0),
+        NULL, NULL, NULL, 0);
+     yasm_bc_finalize(bc, yasm_cv__append_bc(info.debug_symline, bc));
 -    yasm_bc_resolve(bc, 0, NULL);
++    yasm_bc_calc_len(bc, NULL, NULL);
+     /* source file info table */
+     head = cv8_add_symhead(dbgfmt_cv, info.debug_symline, CV8_FILE_INFO, 0);
+     off = 0;
+     for (i=0; i<dbgfmt_cv->filenames_size; i++) {
+       if (!dbgfmt_cv->filenames[i].pathname)
+           continue;
+       bc = cv8_add_fileinfo(dbgfmt_cv, info.debug_symline,
+                             &dbgfmt_cv->filenames[i]);
+       dbgfmt_cv->filenames[i].info_off = off;
+       off += bc->len;
+     }
+     cv8_set_symhead_end(head, yasm_section_bcs_last(info.debug_symline));
+     /* Already aligned 4 */
+     /* Generate line numbers for sections */
+     yasm_object_sections_traverse(dbgfmt_cv->object, (void *)&info,
+                                 cv_generate_line_section);
+     /* Output line numbers for sections */
+     STAILQ_FOREACH(li, &info.cv8_lineinfos, link) {
+       head = cv8_add_symhead(dbgfmt_cv, info.debug_symline, CV8_LINE_NUMS,
+                              0);
+       bc = yasm_bc_create_common(&cv8_lineinfo_bc_callback, li, 0);
+       bc->len = 24+li->num_linenums*8;
+       yasm_cv__append_bc(info.debug_symline, bc);
+       cv8_set_symhead_end(head, yasm_section_bcs_last(info.debug_symline));
+     }
+     /* Already aligned 4 */
+     /* Output debugging symbols */
+     head = cv8_add_symhead(dbgfmt_cv, info.debug_symline, CV8_DEBUG_SYMS, 0);
+     /* add object and compile flag first */
+     cv8_add_sym_objname(dbgfmt_cv, info.debug_symline,
+       yasm__abspath(yasm_object_get_object_fn(dbgfmt_cv->object)));
+     cv8_add_sym_compile(dbgfmt_cv, info.debug_symline,
+                       yasm__xstrdup(PACKAGE_NAME " " PACKAGE_INTVER "."
+                                     PACKAGE_BUILD));
+     /* then iterate through symbol table */
+     yasm_symtab_traverse(dbgfmt_cv->symtab, &info, cv_generate_sym);
+     cv8_set_symhead_end(head, yasm_section_bcs_last(info.debug_symline));
+     /* Align 4 at end */
+     bc = yasm_bc_create_align
+       (yasm_expr_create_ident(yasm_expr_int(yasm_intnum_create_uint(4)), 0),
+        NULL, NULL, NULL, 0);
+     yasm_bc_finalize(bc, yasm_cv__append_bc(info.debug_symline, bc));
 -static yasm_bc_resolve_flags
 -cv8_symhead_bc_resolve(yasm_bytecode *bc, int save,
 -                     yasm_calc_bc_dist_func calc_bc_dist)
++    yasm_bc_calc_len(bc, NULL, NULL);
+     return info.debug_symline;
+ }
+ static void
+ cv_out_sym(yasm_symrec *sym, unsigned long off, yasm_bytecode *bc,
+          unsigned char **bufp, void *d, yasm_output_value_func output_value)
+ {
+     yasm_value val;
+     /* sym in its section */
+     yasm_value_init_sym(&val, sym, 32);
+     val.section_rel = 1;
+     output_value(&val, *bufp, 4, off, bc, 0, d);
+     *bufp += 4;
+     /* section index */
+     yasm_value_init_sym(&val, sym, 16);
+     val.seg_of = 1;
+     output_value(&val, *bufp, 2, off+4, bc, 0, d);
+     *bufp += 2;
+ }
+ static cv8_symhead *
+ cv8_add_symhead(yasm_dbgfmt_cv *dbgfmt_cv, yasm_section *sect,
+               unsigned long type, int first)
+ {
+     cv8_symhead *head;
+     yasm_bytecode *bc;
+     head = yasm_xmalloc(sizeof(cv8_symhead));
+     head->dbgfmt_cv = dbgfmt_cv;
+     head->type = type;
+     head->first = first;
+     head->start_prevbc = yasm_section_bcs_last(sect);
+     bc = yasm_bc_create_common(&cv8_symhead_bc_callback, head, 0);
+     if (first)
+       bc->len = 12;
+     else
+       bc->len = 8;
+     head->end_prevbc = bc;
+     yasm_cv__append_bc(sect, bc);
+     return head;
+ }
+ static void
+ cv8_set_symhead_end(cv8_symhead *head, yasm_bytecode *end_prevbc)
+ {
+     head->end_prevbc = end_prevbc;
+ }
+ static void
+ cv8_symhead_bc_destroy(void *contents)
+ {
+     yasm_xfree(contents);
+ }
+ static void
+ cv8_symhead_bc_print(const void *contents, FILE *f, int indent_level)
+ {
+     /* TODO */
+ }
 -    yasm_internal_error(N_("tried to resolve a codeview symhead bytecode"));
++static int
++cv8_symhead_bc_calc_len(yasm_bytecode *bc, yasm_bc_add_span_func add_span,
++                      void *add_span_data)
+ {
 -    return YASM_BC_RESOLVE_MIN_LEN;
++    yasm_internal_error(N_("tried to calc_len a codeview symhead bytecode"));
+     /*@notreached@*/
 -static yasm_bc_resolve_flags
 -cv8_fileinfo_bc_resolve(yasm_bytecode *bc, int save,
 -                      yasm_calc_bc_dist_func calc_bc_dist)
++    return 0;
+ }
+ static int
+ cv8_symhead_bc_tobytes(yasm_bytecode *bc, unsigned char **bufp, void *d,
+                      yasm_output_value_func output_value,
+                      yasm_output_reloc_func output_reloc)
+ {
+     cv8_symhead *head = (cv8_symhead *)bc->contents;
+     yasm_dbgfmt_cv *dbgfmt_cv = head->dbgfmt_cv;
+     unsigned char *buf = *bufp;
+     yasm_intnum *intn, *cval;
+     cval = yasm_intnum_create_uint(4);
+     /* Output "version" if first */
+     if (head->first) {
+       yasm_arch_intnum_tobytes(dbgfmt_cv->arch, cval, buf, 4, 32, 0, bc, 0);
+       buf += 4;
+     }
+     /* Type contained - 4 bytes */
+     yasm_intnum_set_uint(cval, head->type);
+     yasm_arch_intnum_tobytes(dbgfmt_cv->arch, cval, buf, 4, 32, 0, bc, 0);
+     buf += 4;
+     /* Total length of info (following this field) - 4 bytes */
+     yasm_intnum_set_uint(cval, bc->len);
+     intn = yasm_common_calc_bc_dist(head->start_prevbc, head->end_prevbc);
+     yasm_intnum_calc(intn, YASM_EXPR_SUB, cval);
+     yasm_arch_intnum_tobytes(dbgfmt_cv->arch, intn, buf, 4, 32, 0, bc, 0);
+     buf += 4;
+     yasm_intnum_destroy(intn);
+     *bufp = buf;
+     yasm_intnum_destroy(cval);
+     return 0;
+ }
+ static yasm_bytecode *
+ cv8_add_fileinfo(yasm_dbgfmt_cv *dbgfmt_cv, yasm_section *sect,
+                const cv_filename *fn)
+ {
+     cv8_fileinfo *fi;
+     yasm_bytecode *bc;
+     fi = yasm_xmalloc(sizeof(cv8_fileinfo));
+     fi->dbgfmt_cv = dbgfmt_cv;
+     fi->fn = fn;
+     bc = yasm_bc_create_common(&cv8_fileinfo_bc_callback, fi, 0);
+     bc->len = 24;
+     yasm_cv__append_bc(sect, bc);
+     return bc;
+ }
+ static void
+ cv8_fileinfo_bc_destroy(void *contents)
+ {
+     yasm_xfree(contents);
+ }
+ static void
+ cv8_fileinfo_bc_print(const void *contents, FILE *f, int indent_level)
+ {
+     /* TODO */
+ }
 -    yasm_internal_error(N_("tried to resolve a codeview fileinfo bytecode"));
++static int
++cv8_fileinfo_bc_calc_len(yasm_bytecode *bc, yasm_bc_add_span_func add_span,
++                       void *add_span_data)
+ {
 -    return YASM_BC_RESOLVE_MIN_LEN;
++    yasm_internal_error(N_("tried to calc_len a codeview fileinfo bytecode"));
+     /*@notreached@*/
 -static yasm_bc_resolve_flags
 -cv8_lineinfo_bc_resolve(yasm_bytecode *bc, int save,
 -                      yasm_calc_bc_dist_func calc_bc_dist)
++    return 0;
+ }
+ static int
+ cv8_fileinfo_bc_tobytes(yasm_bytecode *bc, unsigned char **bufp, void *d,
+                       yasm_output_value_func output_value,
+                       yasm_output_reloc_func output_reloc)
+ {
+     cv8_fileinfo *fi = (cv8_fileinfo *)bc->contents;
+     yasm_dbgfmt_cv *dbgfmt_cv = fi->dbgfmt_cv;
+     unsigned char *buf = *bufp;
+     yasm_intnum *cval;
+     int i;
+     /* Offset in filename string table */
+     cval = yasm_intnum_create_uint(fi->fn->str_off);
+     yasm_arch_intnum_tobytes(dbgfmt_cv->arch, cval, buf, 4, 32, 0, bc, 0);
+     buf += 4;
+     /* Checksum type/length */
+     yasm_intnum_set_uint(cval, 0x0110);
+     yasm_arch_intnum_tobytes(dbgfmt_cv->arch, cval, buf, 2, 16, 0, bc, 0);
+     buf += 2;
+     /* Checksum */
+     for (i=0; i<16; i++)
+       YASM_WRITE_8(buf, fi->fn->digest[i]);
+     /* Pad */
+     YASM_WRITE_8(buf, 0);
+     YASM_WRITE_8(buf, 0);
+     *bufp = buf;
+     yasm_intnum_destroy(cval);
+     return 0;
+ }
+ static void
+ cv8_lineinfo_bc_destroy(void *contents)
+ {
+     cv8_lineinfo *li = (cv8_lineinfo *)contents;
+     cv8_lineset *ls1, *ls2;
+     /* delete line sets */
+     ls1 = STAILQ_FIRST(&li->linesets);
+     while (ls1) {
+       ls2 = STAILQ_NEXT(ls1, link);
+       yasm_xfree(ls1);
+       ls1 = ls2;
+     }
+     yasm_xfree(contents);
+ }
+ static void
+ cv8_lineinfo_bc_print(const void *contents, FILE *f, int indent_level)
+ {
+     /* TODO */
+ }
 -    yasm_internal_error(N_("tried to resolve a codeview linehead bytecode"));
++static int
++cv8_lineinfo_bc_calc_len(yasm_bytecode *bc, yasm_bc_add_span_func add_span,
++                       void *add_span_data)
+ {
 -    return YASM_BC_RESOLVE_MIN_LEN;
++    yasm_internal_error(N_("tried to calc_len a codeview linehead bytecode"));
+     /*@notreached@*/
 -static yasm_bc_resolve_flags
 -cv_sym_bc_resolve(yasm_bytecode *bc, int save,
 -                yasm_calc_bc_dist_func calc_bc_dist)
++    return 0;
+ }
+ static int
+ cv8_lineinfo_bc_tobytes(yasm_bytecode *bc, unsigned char **bufp, void *d,
+                       yasm_output_value_func output_value,
+                       yasm_output_reloc_func output_reloc)
+ {
+     cv8_lineinfo *li = (cv8_lineinfo *)bc->contents;
+     yasm_dbgfmt_cv *dbgfmt_cv = li->dbgfmt_cv;
+     unsigned char *buf = *bufp;
+     yasm_intnum *cval;
+     unsigned long i;
+     cv8_lineset *ls;
+     /* start offset and section */
+     cv_out_sym(li->sectsym, 0, bc, &buf, d, output_value);
+     /* Two bytes of pad/alignment */
+     YASM_WRITE_8(buf, 0);
+     YASM_WRITE_8(buf, 0);
+     /* Section length covered by line number info */
+     cval = yasm_common_calc_bc_dist(yasm_section_bcs_first(li->sect),
+                                   yasm_section_bcs_last(li->sect));
+     yasm_arch_intnum_tobytes(dbgfmt_cv->arch, cval, buf, 4, 32, 0, bc, 0);
+     buf += 4;
+     /* Offset of source file in info table */
+     yasm_intnum_set_uint(cval, li->fn->info_off);
+     yasm_arch_intnum_tobytes(dbgfmt_cv->arch, cval, buf, 4, 32, 0, bc, 0);
+     buf += 4;
+     /* Number of line number pairs */
+     yasm_intnum_set_uint(cval, li->num_linenums);
+     yasm_arch_intnum_tobytes(dbgfmt_cv->arch, cval, buf, 4, 32, 0, bc, 0);
+     buf += 4;
+     /* Number of bytes of line number pairs + 12 (no, I don't know why) */
+     yasm_intnum_set_uint(cval, li->num_linenums*8+12);
+     yasm_arch_intnum_tobytes(dbgfmt_cv->arch, cval, buf, 4, 32, 0, bc, 0);
+     buf += 4;
+     /* Offset / line number pairs */
+     i = 0;
+     STAILQ_FOREACH(ls, &li->linesets, link) {
+       unsigned long j;
+       for (j=0; i<li->num_linenums && j<126; i++, j++) {
+           /* offset in section */
+           yasm_intnum_set_uint(cval, ls->pairs[j].offset);
+           yasm_arch_intnum_tobytes(dbgfmt_cv->arch, cval, buf, 4, 32, 0, bc,
+                                    0);
+           buf += 4;
+           /* line number in file */
+           yasm_intnum_set_uint(cval, ls->pairs[j].line);
+           yasm_arch_intnum_tobytes(dbgfmt_cv->arch, cval, buf, 4, 32, 0, bc,
+                                    0);
+           buf += 4;
+       }
+     }
+     *bufp = buf;
+     yasm_intnum_destroy(cval);
+     return 0;
+ }
+ static unsigned long
+ cv_sym_size(const cv_sym *cvs)
+ {
+     const char *ch = cvs->format;
+     unsigned long len = 4;  /* sym length and type */
+     unsigned long slen;
+     int arg = 0;
+     while (*ch) {
+       switch (*ch) {
+           case 'b':
+               len++;
+               arg++;
+               break;
+           case 'h':
+               len += 2;
+               arg++;
+               break;
+           case 'w':
+               len += 4;
+               arg++;
+               break;
+           case 'Y':
+               len += 6;       /* XXX: will be 4 in 16-bit version */
+               arg++;
+               break;
+           case 'T':
+               len += 4;       /* XXX: will be 2 in CV4 */
+               arg++;
+               break;
+           case 'S':
+               len += 1;       /* XXX: is this 1 or 2? */
+               slen = strlen((const char *)cvs->args[arg++].p);
+               len += slen <= 0xff ? slen : 0xff;
+               break;
+           case 'Z':
+               len += strlen((const char *)cvs->args[arg++].p) + 1;
+               break;
+           default:
+               yasm_internal_error(N_("unknown sym format character"));
+       }
+       ch++;
+     }
+     return len;
+ }
+ static void
+ cv_sym_bc_destroy(void *contents)
+ {
+     cv_sym *cvs = (cv_sym *)contents;
+     const char *ch = cvs->format;
+     int arg = 0;
+     while (*ch) {
+       switch (*ch) {
+           case 'b':
+           case 'h':
+           case 'w':
+           case 'Y':
+           case 'T':
+               arg++;
+               break;  /* nothing to destroy */
+           case 'S':
+           case 'Z':
+               yasm_xfree(cvs->args[arg++].p);
+               break;
+           default:
+               yasm_internal_error(N_("unknown sym format character"));
+       }
+       ch++;
+     }
+     yasm_xfree(contents);
+ }
+ static void
+ cv_sym_bc_print(const void *contents, FILE *f, int indent_level)
+ {
+     /* TODO */
+ }
 -    yasm_internal_error(N_("tried to resolve a codeview sym bytecode"));
++static int
++cv_sym_bc_calc_len(yasm_bytecode *bc, yasm_bc_add_span_func add_span,
++                 void *add_span_data)
+ {
 -    return YASM_BC_RESOLVE_MIN_LEN;
++    yasm_internal_error(N_("tried to calc_len a codeview sym bytecode"));
+     /*@notreached@*/
++    return 0;
+ }
+ static int
+ cv_sym_bc_tobytes(yasm_bytecode *bc, unsigned char **bufp, void *d,
+                 yasm_output_value_func output_value,
+                 yasm_output_reloc_func output_reloc)
+ {
+     cv_sym *cvs = (cv_sym *)bc->contents;
+     yasm_dbgfmt_cv *dbgfmt_cv = cvs->dbgfmt_cv;
+     unsigned char *buf = *bufp;
+     yasm_intnum *cval;
+     const char *ch = cvs->format;
+     size_t len;
+     int arg = 0;
+     /* Total length of record (following this field) - 2 bytes */
+     cval = yasm_intnum_create_uint(bc->len-2);
+     yasm_arch_intnum_tobytes(dbgfmt_cv->arch, cval, buf, 2, 16, 0, bc, 1);
+     buf += 2;
+     /* Type contained - 2 bytes */
+     yasm_intnum_set_uint(cval, cvs->type);
+     yasm_arch_intnum_tobytes(dbgfmt_cv->arch, cval, buf, 2, 16, 0, bc, 0);
+     buf += 2;
+     while (*ch) {
+       switch (*ch) {
+           case 'b':
+               YASM_WRITE_8(buf, cvs->args[arg].i);
+               arg++;
+               break;
+           case 'h':
+               yasm_intnum_set_uint(cval, cvs->args[arg++].i);
+               yasm_arch_intnum_tobytes(dbgfmt_cv->arch, cval, buf, 2, 16, 0,
+                                        bc, 0);
+               buf += 2;
+               break;
+           case 'w':
+               yasm_intnum_set_uint(cval, cvs->args[arg++].i);
+               yasm_arch_intnum_tobytes(dbgfmt_cv->arch, cval, buf, 4, 32, 0,
+                                        bc, 0);
+               buf += 4;
+               break;
+           case 'Y':
+               cv_out_sym((yasm_symrec *)cvs->args[arg++].p,
+                          (unsigned long)(buf-(*bufp)), bc, &buf, d,
+                          output_value);
+               break;
+           case 'T':
+               yasm_intnum_set_uint(cval, cvs->args[arg++].i);
+               yasm_arch_intnum_tobytes(dbgfmt_cv->arch, cval, buf, 4, 32, 0,
+                                        bc, 0);
+               buf += 4;       /* XXX: will be 2 in CV4 */
+               break;
+           case 'S':
+               len = strlen((char *)cvs->args[arg].p);
+               len = len <= 0xff ? len : 0xff;
+               YASM_WRITE_8(buf, len);
+               memcpy(buf, (char *)cvs->args[arg].p, len);
+               buf += len;
+               arg++;
+               break;
+           case 'Z':
+               len = strlen((char *)cvs->args[arg].p)+1;
+               memcpy(buf, (char *)cvs->args[arg].p, len);
+               buf += len;
+               arg++;
+               break;
+           default:
+               yasm_internal_error(N_("unknown leaf format character"));
+       }
+       ch++;
+     }
+     *bufp = buf;
+     yasm_intnum_destroy(cval);
+     return 0;
+ }
index 0000000000000000000000000000000000000000,51cb897b609a00a69f3e1922f5846a881df37d8b..c5d049cb565d9a70fa8e1b492734a622499f5f73
mode 000000,100644..100644
--- /dev/null
@@@ -1,0 -1,780 +1,781 @@@
 -static yasm_bc_resolve_flags cv_type_bc_resolve
 -    (yasm_bytecode *bc, int save, yasm_calc_bc_dist_func calc_bc_dist);
+ /*
+  * CodeView debugging format - type information
+  *
+  *  Copyright (C) 2006  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.
+  * 3. Neither the name of the author nor the names of other contributors
+  *    may be used to endorse or promote products derived from this
+  *    software without specific prior written permission.
+  *
+  * 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
+ #include <libyasm.h>
+ #include "cv-dbgfmt.h"
+ enum cv_reservedtype {
+     /* Bitfields representation - type */
+     CV_TYPE_SPECIAL   = 0x00<<4,      /* Special */
+     CV_TYPE_SIGNED    = 0x01<<4,      /* Signed integral value */
+     CV_TYPE_UNSIGNED  = 0x02<<4,      /* Unsigned integral value */
+     CV_TYPE_BOOLEAN   = 0x03<<4,      /* Boolean */
+     CV_TYPE_REAL      = 0x04<<4,      /* Real */
+     CV_TYPE_COMPLEX   = 0x05<<4,      /* Complex */
+     CV_TYPE_SPECIAL2  = 0x06<<4,      /* Special2 */
+     CV_TYPE_REALINT   = 0x07<<4,      /* Really int value */
+     /* "size" of CV_TYPE_SPECIAL */
+     CV_SPECIAL_NOTYPE = 0x00<<0,      /* No type */
+     CV_SPECIAL_ABS    = 0x01<<0,      /* Absolute symbol */
+     CV_SPECIAL_SEG    = 0x02<<0,      /* Segment */
+     CV_SPECIAL_VOID   = 0x03<<0,      /* Void */
+     CV_SPECIAL_CURRENCY       = 0x04<<0,      /* Basic 8-byte currency value */
+     CV_SPECIAL_NEARBSTR       = 0x05<<0,      /* Near Basic string */
+     CV_SPECIAL_FARBSTR        = 0x06<<0,      /* Far Basic string */
+     /* Size of CV_TYPE_SIGNED, CV_TYPE_UNSIGNED, and CV_TYPE_BOOLEAN */
+     CV_INTEGER_1BYTE  = 0x00<<0,      /* 1 byte */
+     CV_INTEGER_2BYTE  = 0x01<<0,      /* 2 byte */
+     CV_INTEGER_4BYTE  = 0x02<<0,      /* 4 byte */
+     CV_INTEGER_8BYTE  = 0x03<<0,      /* 8 byte */
+     /* Size of CV_TYPE_REAL and CV_TYPE_COMPLEX */
+     CV_REAL_32BIT     = 0x00<<0,      /* 32 bit */
+     CV_REAL_64BIT     = 0x01<<0,      /* 64 bit */
+     CV_REAL_80BIT     = 0x02<<0,      /* 80 bit */
+     CV_REAL_128BIT    = 0x03<<0,      /* 128 bit */
+     CV_REAL_48BIT     = 0x04<<0,      /* 48 bit */
+     /* "size" of CV_TYPE_SPECIAL2 */
+     CV_SPECIAL2_BIT   = 0x00<<0,      /* Bit */
+     CV_SPECIAL2_PASCHAR       = 0x01<<0,      /* Pascal CHAR */
+     /* Size of CV_TYPE_REALINT */
+     CV_REALINT_CHAR   = 0x00<<0,      /* Char */
+     CV_REALINT_WCHAR  = 0x01<<0,      /* Wide character */
+     CV_REALINT_S2BYTE = 0x02<<0,      /* 2-byte signed integer */
+     CV_REALINT_U2BYTE = 0x03<<0,      /* 2-byte unsigned integer */
+     CV_REALINT_S4BYTE = 0x04<<0,      /* 4-byte signed integer */
+     CV_REALINT_U4BYTE = 0x05<<0,      /* 4-byte unsigned integer */
+     CV_REALINT_S8BYTE = 0x06<<0,      /* 8-byte signed integer */
+     CV_REALINT_U8BYTE = 0x07<<0,      /* 8-byte unsigned integer */
+     /* Mode */
+     CV_MODE_DIRECT    = 0x00<<8,      /* Direct; not a pointer */
+     CV_MODE_NEAR      = 0x01<<8,      /* Near pointer */
+     CV_MODE_FAR               = 0x02<<8,      /* Far pointer */
+     CV_MODE_HUGE      = 0x03<<8,      /* Huge pointer */
+     CV_MODE_NEAR32    = 0x04<<8,      /* 32-bit near pointer */
+     CV_MODE_FAR32     = 0x05<<8,      /* 32-bit far pointer */
+     CV_MODE_NEAR64    = 0x06<<8,      /* 64-bit near pointer */
+     /* Pure primitive type listing - based on above bitfields */
+     /* Special Types */
+     CV_T_NOTYPE               = 0x0000, /* Uncharacterized type (no type) */
+     CV_T_ABS          = 0x0001, /* Absolute symbol */
+     CV_T_SEGMENT      = 0x0002, /* Segment type */
+     CV_T_VOID         = 0x0003, /* Void */
+     CV_T_PVOID                = 0x0103, /* Near pointer to void */
+     CV_T_PFVOID               = 0x0203, /* Far pointer to void */
+     CV_T_PHVOID               = 0x0303, /* Huge pointer to void */
+     CV_T_32PVOID      = 0x0403, /* 32-bit near pointer to void */
+     CV_T_32PFVOID     = 0x0503, /* 32-bit far pointer to void */
+     CV_T_CURRENCY     = 0x0004, /* Basic 8-byte currency value */
+     CV_T_NBASICSTR    = 0x0005, /* Near Basic string */
+     CV_T_FBASICSTR    = 0x0006, /* Far Basic string */
+     CV_T_BIT          = 0x0060, /* Bit */
+     CV_T_PASCHAR      = 0x0061, /* Pascal CHAR */
+     /* Character Types */
+     CV_T_CHAR         = 0x0010, /* 8-bit signed */
+     CV_T_UCHAR                = 0x0020, /* 8-bit unsigned */
+     CV_T_PCHAR                = 0x0110, /* Near pointer to 8-bit signed */
+     CV_T_PUCHAR               = 0x0120, /* Near pointer to 8-bit unsigned */
+     CV_T_PFCHAR               = 0x0210, /* Far pointer to 8-bit signed */
+     CV_T_PFUCHAR      = 0x0220, /* Far pointer to 8-bit unsigned */
+     CV_T_PHCHAR               = 0x0310, /* Huge pointer to 8-bit signed */
+     CV_T_PHUCHAR      = 0x0320, /* Huge pointer to 8-bit unsigned */
+     CV_T_32PCHAR      = 0x0410, /* 16:32 near pointer to 8-bit signed */
+     CV_T_32PUCHAR     = 0x0420, /* 16:32 near pointer to 8-bit unsigned */
+     CV_T_32PFCHAR     = 0x0510, /* 16:32 far pointer to 8-bit signed */
+     CV_T_32PFUCHAR    = 0x0520, /* 16:32 far pointer to 8-bit unsigned */
+     /* Real Character Types */
+     CV_T_RCHAR                = 0x0070, /* Real char */
+     CV_T_PRCHAR               = 0x0170, /* Near pointer to a real char */
+     CV_T_PFRCHAR      = 0x0270, /* Far pointer to a real char */
+     CV_T_PHRCHAR      = 0x0370, /* Huge pointer to a real char */
+     CV_T_32PRCHAR     = 0x0470, /* 16:32 near pointer to a real char */
+     CV_T_32PFRCHAR    = 0x0570, /* 16:32 far pointer to a real char */
+     /* Wide Character Types */
+     CV_T_WCHAR                = 0x0071, /* Wide char */
+     CV_T_PWCHAR               = 0x0171, /* Near pointer to a wide char */
+     CV_T_PFWCHAR      = 0x0271, /* Far pointer to a wide char */
+     CV_T_PHWCHAR      = 0x0371, /* Huge pointer to a wide char */
+     CV_T_32PWCHAR     = 0x0471, /* 16:32 near pointer to a wide char */
+     CV_T_32PFWCHAR    = 0x0571, /* 16:32 far pointer to a wide char */
+     /* Real 16-bit Integer Types */
+     CV_T_INT2         = 0x0072, /* Real 16-bit signed int */
+     CV_T_UINT2                = 0x0073, /* Real 16-bit unsigned int */
+     CV_T_PINT2                = 0x0172, /* Near pointer to 16-bit signed int */
+     CV_T_PUINT2               = 0x0173, /* Near pointer to 16-bit unsigned int */
+     CV_T_PFINT2               = 0x0272, /* Far pointer to 16-bit signed int */
+     CV_T_PFUINT2      = 0x0273, /* Far pointer to 16-bit unsigned int */
+     CV_T_PHINT2               = 0x0372, /* Huge pointer to 16-bit signed int */
+     CV_T_PHUINT2      = 0x0373, /* Huge pointer to 16-bit unsigned int */
+     CV_T_32PINT2      = 0x0472, /* 16:32 near pointer to 16-bit signed int */
+     CV_T_32PUINT2     = 0x0473, /* 16:32 near pointer to 16-bit unsigned int */
+     CV_T_32PFINT2     = 0x0572, /* 16:32 far pointer to 16-bit signed int */
+     CV_T_32PFUINT2    = 0x0573, /* 16:32 far pointer to 16-bit unsigned int */
+     /* 16-bit Short Types */
+     CV_T_SHORT                = 0x0011, /* 16-bit signed */
+     CV_T_USHORT               = 0x0021, /* 16-bit unsigned */
+     CV_T_PSHORT               = 0x0111, /* Near pointer to 16-bit signed */
+     CV_T_PUSHORT      = 0x0121, /* Near pointer to 16-bit unsigned */
+     CV_T_PFSHORT      = 0x0211, /* Far pointer to 16-bit signed */
+     CV_T_PFUSHORT     = 0x0221, /* Far pointer to 16-bit unsigned */
+     CV_T_PHSHORT      = 0x0311, /* Huge pointer to 16-bit signed */
+     CV_T_PHUSHORT     = 0x0321, /* Huge pointer to 16-bit unsigned */
+     CV_T_32PSHORT     = 0x0411, /* 16:32 near pointer to 16-bit signed */
+     CV_T_32PUSHORT    = 0x0421, /* 16:32 near pointer to 16-bit unsigned */
+     CV_T_32PFSHORT    = 0x0511, /* 16:32 far pointer to 16-bit signed */
+     CV_T_32PFUSHORT   = 0x0521, /* 16:32 far pointer to 16-bit unsigned */
+     /* Real 32-bit Integer Types */
+     CV_T_INT4         = 0x0074, /* Real 32-bit signed int */
+     CV_T_UINT4                = 0x0075, /* Real 32-bit unsigned int */
+     CV_T_PINT4                = 0x0174, /* Near pointer to 32-bit signed int */
+     CV_T_PUINT4               = 0x0175, /* Near pointer to 32-bit unsigned int */
+     CV_T_PFINT4               = 0x0274, /* Far pointer to 32-bit signed int */
+     CV_T_PFUINT4      = 0x0275, /* Far pointer to 32-bit unsigned int */
+     CV_T_PHINT4               = 0x0374, /* Huge pointer to 32-bit signed int */
+     CV_T_PHUINT4      = 0x0375, /* Huge pointer to 32-bit unsigned int */
+     CV_T_32PINT4      = 0x0474, /* 16:32 near pointer to 32-bit signed int */
+     CV_T_32PUINT4     = 0x0475, /* 16:32 near pointer to 32-bit unsigned int */
+     CV_T_32PFINT4     = 0x0574, /* 16:32 far pointer to 32-bit signed int */
+     CV_T_32PFUINT4    = 0x0575, /* 16:32 far pointer to 32-bit unsigned int */
+     /* 32-bit Long Types */
+     CV_T_LONG         = 0x0012, /* 32-bit signed */
+     CV_T_ULONG                = 0x0022, /* 32-bit unsigned */
+     CV_T_PLONG                = 0x0112, /* Near pointer to 32-bit signed */
+     CV_T_PULONG               = 0x0122, /* Near pointer to 32-bit unsigned */
+     CV_T_PFLONG               = 0x0212, /* Far pointer to 32-bit signed */
+     CV_T_PFULONG      = 0x0222, /* Far pointer to 32-bit unsigned */
+     CV_T_PHLONG               = 0x0312, /* Huge pointer to 32-bit signed */
+     CV_T_PHULONG      = 0x0322, /* Huge pointer to 32-bit unsigned */
+     CV_T_32PLONG      = 0x0412, /* 16:32 near pointer to 32-bit signed */
+     CV_T_32PULONG     = 0x0422, /* 16:32 near pointer to 32-bit unsigned */
+     CV_T_32PFLONG     = 0x0512, /* 16:32 far pointer to 32-bit signed */
+     CV_T_32PFULONG    = 0x0522, /* 16:32 far pointer to 32-bit unsigned */
+     /* Real 64-bit int Types */
+     CV_T_INT8         = 0x0076, /* 64-bit signed int */
+     CV_T_UINT8                = 0x0077, /* 64-bit unsigned int */
+     CV_T_PINT8                = 0x0176, /* Near pointer to 64-bit signed int */
+     CV_T_PUINT8               = 0x0177, /* Near pointer to 64-bit unsigned int */
+     CV_T_PFINT8               = 0x0276, /* Far pointer to 64-bit signed int */
+     CV_T_PFUINT8      = 0x0277, /* Far pointer to 64-bit unsigned int */
+     CV_T_PHINT8               = 0x0376, /* Huge pointer to 64-bit signed int */
+     CV_T_PHUINT8      = 0x0377, /* Huge pointer to 64-bit unsigned int */
+     CV_T_32PINT8      = 0x0476, /* 16:32 near pointer to 64-bit signed int */
+     CV_T_32PUINT8     = 0x0477, /* 16:32 near pointer to 64-bit unsigned int */
+     CV_T_32PFINT8     = 0x0576, /* 16:32 far pointer to 64-bit signed int */
+     CV_T_32PFUINT8    = 0x0577, /* 16:32 far pointer to 64-bit unsigned int */
+     /* 64-bit Integral Types */
+     CV_T_QUAD         = 0x0013, /* 64-bit signed */
+     CV_T_UQUAD                = 0x0023, /* 64-bit unsigned */
+     CV_T_PQUAD                = 0x0113, /* Near pointer to 64-bit signed */
+     CV_T_PUQUAD               = 0x0123, /* Near pointer to 64-bit unsigned */
+     CV_T_PFQUAD               = 0x0213, /* Far pointer to 64-bit signed */
+     CV_T_PFUQUAD      = 0x0223, /* Far pointer to 64-bit unsigned */
+     CV_T_PHQUAD               = 0x0313, /* Huge pointer to 64-bit signed */
+     CV_T_PHUQUAD      = 0x0323, /* Huge pointer to 64-bit unsigned */
+     CV_T_32PQUAD      = 0x0413, /* 16:32 near pointer to 64-bit signed */
+     CV_T_32PUQUAD     = 0x0423, /* 16:32 near pointer to 64-bit unsigned */
+     CV_T_32PFQUAD     = 0x0513, /* 16:32 far pointer to 64-bit signed */
+     CV_T_32PFUQUAD    = 0x0523, /* 16:32 far pointer to 64-bit unsigned */
+     /* 32-bit Real Types */
+     CV_T_REAL32               = 0x0040, /* 32-bit real */
+     CV_T_PREAL32      = 0x0140, /* Near pointer to 32-bit real */
+     CV_T_PFREAL32     = 0x0240, /* Far pointer to 32-bit real */
+     CV_T_PHREAL32     = 0x0340, /* Huge pointer to 32-bit real */
+     CV_T_32PREAL32    = 0x0440, /* 16:32 near pointer to 32-bit real */
+     CV_T_32PFREAL32   = 0x0540, /* 16:32 far pointer to 32-bit real */
+     /* 48-bit Real Types */
+     CV_T_REAL48               = 0x0044, /* 48-bit real */
+     CV_T_PREAL48      = 0x0144, /* Near pointer to 48-bit real */
+     CV_T_PFREAL48     = 0x0244, /* Far pointer to 48-bit real */
+     CV_T_PHREAL48     = 0x0344, /* Huge pointer to 48-bit real */
+     CV_T_32PREAL48    = 0x0444, /* 16:32 near pointer to 48-bit real */
+     CV_T_32PFREAL48   = 0x0544, /* 16:32 far pointer to 48-bit real */
+     /* 64-bit Real Types */
+     CV_T_REAL64               = 0x0041, /* 64-bit real */
+     CV_T_PREAL64      = 0x0141, /* Near pointer to 64-bit real */
+     CV_T_PFREAL64     = 0x0241, /* Far pointer to 64-bit real */
+     CV_T_PHREAL64     = 0x0341, /* Huge pointer to 64-bit real */
+     CV_T_32PREAL64    = 0x0441, /* 16:32 near pointer to 64-bit real */
+     CV_T_32PFREAL64   = 0x0541, /* 16:32 far pointer to 64-bit real */
+     /* 80-bit Real Types */
+     CV_T_REAL80               = 0x0042, /* 80-bit real */
+     CV_T_PREAL80      = 0x0142, /* Near pointer to 80-bit real */
+     CV_T_PFREAL80     = 0x0242, /* Far pointer to 80-bit real */
+     CV_T_PHREAL80     = 0x0342, /* Huge pointer to 80-bit real */
+     CV_T_32PREAL80    = 0x0442, /* 16:32 near pointer to 80-bit real */
+     CV_T_32PFREAL80   = 0x0542, /* 16:32 far pointer to 80-bit real */
+     /* 128-bit Real Types */
+     CV_T_REAL128      = 0x0043, /* 128-bit real */
+     CV_T_PREAL128     = 0x0143, /* Near pointer to 128-bit real */
+     CV_T_PFREAL128    = 0x0243, /* Far pointer to 128-bit real */
+     CV_T_PHREAL128    = 0x0343, /* Huge pointer to 128-bit real */
+     CV_T_32PREAL128   = 0x0443, /* 16:32 near pointer to 128-bit real */
+     CV_T_32PFREAL128  = 0x0543, /* 16:32 far pointer to 128-bit real */
+     /* 32-bit Complex Types */
+     CV_T_CPLX32               = 0x0050, /* 32-bit complex */
+     CV_T_PCPLX32      = 0x0150, /* Near pointer to 32-bit complex */
+     CV_T_PFCPLX32     = 0x0250, /* Far pointer to 32-bit complex */
+     CV_T_PHCPLX32     = 0x0350, /* Huge pointer to 32-bit complex */
+     CV_T_32PCPLX32    = 0x0450, /* 16:32 near pointer to 32-bit complex */
+     CV_T_32PFCPLX32   = 0x0550, /* 16:32 far pointer to 32-bit complex */
+     /* 64-bit Complex Types */
+     CV_T_CPLX64               = 0x0051, /* 64-bit complex */
+     CV_T_PCPLX64      = 0x0151, /* Near pointer to 64-bit complex */
+     CV_T_PFCPLX64     = 0x0251, /* Far pointer to 64-bit complex */
+     CV_T_PHCPLX64     = 0x0351, /* Huge pointer to 64-bit complex */
+     CV_T_32PCPLX64    = 0x0451, /* 16:32 near pointer to 64-bit complex */
+     CV_T_32PFCPLX64   = 0x0551, /* 16:32 far pointer to 64-bit complex */
+     /* 80-bit Complex Types */
+     CV_T_CPLX80               = 0x0052, /* 80-bit complex */
+     CV_T_PCPLX80      = 0x0152, /* Near pointer to 80-bit complex */
+     CV_T_PFCPLX80     = 0x0252, /* Far pointer to 80-bit complex */
+     CV_T_PHCPLX80     = 0x0352, /* Huge pointer to 80-bit complex */
+     CV_T_32PCPLX80    = 0x0452, /* 16:32 near pointer to 80-bit complex */
+     CV_T_32PFCPLX80   = 0x0552, /* 16:32 far pointer to 80-bit complex */
+     /* 128-bit Complex Types */
+     CV_T_CPLX128      = 0x0053, /* 128-bit complex */
+     CV_T_PCPLX128     = 0x0153, /* Near pointer to 128-bit complex */
+     CV_T_PFCPLX128    = 0x0253, /* Far pointer to 128-bit complex */
+     CV_T_PHCPLX128    = 0x0353, /* Huge pointer to 128-bit real */
+     CV_T_32PCPLX128   = 0x0453, /* 16:32 near pointer to 128-bit complex */
+     CV_T_32PFCPLX128  = 0x0553, /* 16:32 far pointer to 128-bit complex */
+     /* Boolean Types */
+     CV_T_BOOL08               = 0x0030, /* 8-bit Boolean */
+     CV_T_BOOL16               = 0x0031, /* 16-bit Boolean */
+     CV_T_BOOL32               = 0x0032, /* 32-bit Boolean */
+     CV_T_BOOL64               = 0x0033, /* 64-bit Boolean */
+     CV_T_PBOOL08      = 0x0130, /* Near pointer to 8-bit Boolean */
+     CV_T_PBOOL16      = 0x0131, /* Near pointer to 16-bit Boolean */
+     CV_T_PBOOL32      = 0x0132, /* Near pointer to 32-bit Boolean */
+     CV_T_PBOOL64      = 0x0133, /* Near pointer to 64-bit Boolean */
+     CV_T_PFBOOL08     = 0x0230, /* Far pointer to 8-bit Boolean */
+     CV_T_PFBOOL16     = 0x0231, /* Far pointer to 16-bit Boolean */
+     CV_T_PFBOOL32     = 0x0232, /* Far pointer to 32-bit Boolean */
+     CV_T_PFBOOL64     = 0x0233, /* Far pointer to 64-bit Boolean */
+     CV_T_PHBOOL08     = 0x0330, /* Huge pointer to 8-bit Boolean */
+     CV_T_PHBOOL16     = 0x0331, /* Huge pointer to 16-bit Boolean */
+     CV_T_PHBOOL32     = 0x0332, /* Huge pointer to 32-bit Boolean */
+     CV_T_PHBOOL64     = 0x0333, /* Huge pointer to 64-bit Boolean */
+     CV_T_32PBOOL08    = 0x0430, /* 16:32 near pointer to 8-bit Boolean */
+     CV_T_32PBOOL16    = 0x0431, /* 16:32 near pointer to 16-bit Boolean */
+     CV_T_32PBOOL32    = 0x0432, /* 16:32 near pointer to 32-bit Boolean */
+     CV_T_32PBOOL64    = 0x0433, /* 16:32 near pointer to 64-bit Boolean */
+     CV_T_32PFBOOL08   = 0x0530, /* 16:32 far pointer to 8-bit Boolean */
+     CV_T_32PFBOOL16   = 0x0531, /* 16:32 far pointer to 16-bit Boolean */
+     CV_T_32PFBOOL32   = 0x0532, /* 16:32 far pointer to 32-bit Boolean */
+     CV_T_32PFBOOL64   = 0x0533, /* 16:32 far pointer to 64-bit Boolean */
+     /* Non-primitive types are stored in the TYPES section (generated in
+      * cv-type.c) and start at this index (e.g. 0x1000 is the first type
+      * in TYPES, 0x1001 the second, etc.
+      */
+     CV_FIRST_NONPRIM  = 0x1000
+ };
+ enum cv_leaftype {
+     /* Leaf indices for type records that can be referenced from symbols */
+     CV4_LF_MODIFIER   = 0x0001,       /* Type Modifier */
+     CV4_LF_POINTER    = 0x0002,       /* Pointer */
+     CV4_LF_ARRAY      = 0x0003,       /* Simple Array */
+     CV4_LF_CLASS      = 0x0004,       /* Classes */
+     CV4_LF_STRUCTURE  = 0x0005,       /* Structures */
+     CV4_LF_UNION      = 0x0006,       /* Unions */
+     CV4_LF_ENUM               = 0x0007,       /* Enumeration */
+     CV4_LF_PROCEDURE  = 0x0008,       /* Procedure */
+     CV4_LF_MFUNCTION  = 0x0009,       /* Member Function */
+     CV4_LF_VTSHAPE    = 0x000a,       /* Virtual Function Table Shape */
+     CV4_LF_BARRAY     = 0x000d,       /* Basic Array */
+     CV4_LF_LABEL      = 0x000e,       /* Label */
+     CV4_LF_NULL               = 0x000f,       /* Null */
+     CV4_LF_DIMARRAY   = 0x0011,       /* Multiply Dimensioned Array */
+     CV4_LF_VFTPATH    = 0x0012,       /* Path to Virtual Function Table */
+     CV4_LF_PRECOMP    = 0x0013,       /* Reference Precompiled Types */
+     CV4_LF_ENDPRECOMP = 0x0014,       /* End of Precompiled Types */
+     /* CodeView 5.0 version */
+     CV5_LF_MODIFIER   = 0x1001,       /* Type Modifier */
+     CV5_LF_POINTER    = 0x1002,       /* Pointer */
+     CV5_LF_ARRAY      = 0x1003,       /* Simple Array */
+     CV5_LF_CLASS      = 0x1004,       /* Classes */
+     CV5_LF_STRUCTURE  = 0x1005,       /* Structures */
+     CV5_LF_UNION      = 0x1006,       /* Unions */
+     CV5_LF_ENUM               = 0x1007,       /* Enumeration */
+     CV5_LF_PROCEDURE  = 0x1008,       /* Procedure */
+     CV5_LF_MFUNCTION  = 0x1009,       /* Member Function */
+     CV5_LF_VTSHAPE    = 0x000a,       /* Virtual Function Table Shape */
+     CV5_LF_BARRAY     = 0x100d,       /* Basic Array */
+     CV5_LF_LABEL      = 0x000e,       /* Label */
+     CV5_LF_NULL               = 0x000f,       /* Null */
+     CV5_LF_DIMARRAY   = 0x100c,       /* Multiply Dimensioned Array */
+     CV5_LF_VFTPATH    = 0x100d,       /* Path to Virtual Function Table */
+     CV5_LF_PRECOMP    = 0x100e,       /* Reference Precompiled Types */
+     CV5_LF_ENDPRECOMP = 0x0014,       /* End of Precompiled Types */
+     CV5_LF_TYPESERVER = 0x0016,       /* Reference Typeserver */
+     /* Leaf indices for type records that can be referenced from other type
+      * records
+      */
+     CV4_LF_SKIP               = 0x0200,       /* Skip */
+     CV4_LF_ARGLIST    = 0x0201,       /* Argument List */
+     CV4_LF_DEFARG     = 0x0202,       /* Default Argument */
+     CV4_LF_LIST               = 0x0203,       /* Arbitrary List */
+     CV4_LF_FIELDLIST  = 0x0204,       /* Field List */
+     CV4_LF_DERIVED    = 0x0205,       /* Derived Classes */
+     CV4_LF_BITFIELD   = 0x0206,       /* Bit Fields */
+     CV4_LF_METHODLIST = 0x0207,       /* Method List */
+     CV4_LF_DIMCONU    = 0x0208,       /* Dimensioned Array with Constant Upper Bound */
+     CV4_LF_DIMCONLU   = 0x0209,       /* Dimensioned Array with Constant Lower and Upper Bounds */
+     CV4_LF_DIMVARU    = 0x020a,       /* Dimensioned Array with Variable Upper Bound */
+     CV4_LF_DIMVARLU   = 0x020b,       /* Dimensioned Array with Variable Lower and Upper Bounds */
+     CV4_LF_REFSYM     = 0x020c,       /* Referenced Symbol */
+     /* CodeView 5.0 version */
+     CV5_LF_SKIP               = 0x1200,       /* Skip */
+     CV5_LF_ARGLIST    = 0x1201,       /* Argument List */
+     CV5_LF_DEFARG     = 0x1202,       /* Default Argument */
+     CV5_LF_FIELDLIST  = 0x1203,       /* Field List */
+     CV5_LF_DERIVED    = 0x1204,       /* Derived Classes */
+     CV5_LF_BITFIELD   = 0x1205,       /* Bit Fields */
+     CV5_LF_METHODLIST = 0x1206,       /* Method List */
+     CV5_LF_DIMCONU    = 0x1207,       /* Dimensioned Array with Constant Upper Bound */
+     CV5_LF_DIMCONLU   = 0x1208,       /* Dimensioned Array with Constant Lower and Upper Bounds */
+     CV5_LF_DIMVARU    = 0x1209,       /* Dimensioned Array with Variable Upper Bound */
+     CV5_LF_DIMVARLU   = 0x120a,       /* Dimensioned Array with Variable Lower and Upper Bounds */
+     CV5_LF_REFSYM     = 0x020c,       /* Referenced Symbol */
+     /* Leaf indices for fields of complex lists */
+     CV4_LF_BCLASS     = 0x0400,       /* Real Base Class */
+     CV4_LF_VBCLASS    = 0x0401,       /* Direct Virtual Base Class */
+     CV4_LF_IVBCLASS   = 0x0402,       /* Indirect Virtual Base Class */
+     CV4_LF_ENUMERATE  = 0x0403,       /* Enumeration Name and Value */
+     CV4_LF_FRIENDFCN  = 0x0404,       /* Friend Function */
+     CV4_LF_INDEX      = 0x0405,       /* Index To Another Type Record */
+     CV4_LF_MEMBER     = 0x0406,       /* Data Member */
+     CV4_LF_STMEMBER   = 0x0407,       /* Static Data Member */
+     CV4_LF_METHOD     = 0x0408,       /* Method */
+     CV4_LF_NESTTYPE   = 0x0409,       /* Nested Type Definition */
+     CV4_LF_VFUNCTAB   = 0x040a,       /* Virtual Function Table Pointer */
+     CV4_LF_FRIENDCLS  = 0x040b,       /* Friend Class */
+     CV4_LF_ONEMETHOD  = 0x040c,       /* One Method */
+     CV4_LF_VFUNCOFF   = 0x040d,       /* Virtual Function Offset */
+     /* CodeView 5.0 version */
+     CV5_LF_BCLASS     = 0x1400,       /* Real Base Class */
+     CV5_LF_VBCLASS    = 0x1401,       /* Direct Virtual Base Class */
+     CV5_LF_IVBCLASS   = 0x1402,       /* Indirect Virtual Base Class */
+     CV5_LF_ENUMERATE  = 0x0403,       /* Enumeration Name and Value */
+     CV5_LF_FRIENDFCN  = 0x1403,       /* Friend Function */
+     CV5_LF_INDEX      = 0x1404,       /* Index To Another Type Record */
+     CV5_LF_MEMBER     = 0x1405,       /* Data Member */
+     CV5_LF_STMEMBER   = 0x1406,       /* Static Data Member */
+     CV5_LF_METHOD     = 0x1407,       /* Method */
+     CV5_LF_NESTTYPE   = 0x1408,       /* Nested Type Definition */
+     CV5_LF_VFUNCTAB   = 0x1409,       /* Virtual Function Table Pointer */
+     CV5_LF_FRIENDCLS  = 0x140a,       /* Friend Class */
+     CV5_LF_ONEMETHOD  = 0x140b,       /* One Method */
+     CV5_LF_VFUNCOFF   = 0x140c,       /* Virtual Function Offset */
+     CV5_LF_NESTTYPEEX = 0x140d,       /* Nested Type Extended Definition */
+     CV5_LF_MEMBERMODIFY       = 0x140e,       /* Member Modification */
+     /* XXX: CodeView 5.0 spec also lists 0x040f as LF_MEMBERMODIFY? */
+     /* Leaf indices for numeric fields of symbols and type records */
+     CV_LF_NUMERIC     = 0x8000,
+     CV_LF_CHAR                = 0x8000,       /* Signed Char (8-bit) */
+     CV_LF_SHORT               = 0x8001,       /* Signed Short (16-bit) */
+     CV_LF_USHORT      = 0x8002,       /* Unsigned Short (16-bit) */
+     CV_LF_LONG                = 0x8003,       /* Signed Long (32-bit) */
+     CV_LF_ULONG               = 0x8004,       /* Unsigned Long (32-bit) */
+     CV_LF_REAL32      = 0x8005,       /* 32-bit Float */
+     CV_LF_REAL64      = 0x8006,       /* 64-bit Float */
+     CV_LF_REAL80      = 0x8007,       /* 80-bit Float */
+     CV_LF_REAL128     = 0x8008,       /* 128-bit Float */
+     CV_LF_QUADWORD    = 0x8009,       /* Signed Quad Word (64-bit) */
+     CV_LF_UQUADWORD   = 0x800a,       /* Unsigned Quad Word (64-bit) */
+     CV_LF_REAL48      = 0x800b,       /* 48-bit Float */
+     CV_LF_COMPLEX32   = 0x800c,       /* 32-bit Complex */
+     CV_LF_COMPLEX64   = 0x800d,       /* 64-bit Complex */
+     CV_LF_COMPLEX80   = 0x800e,       /* 80-bit Complex */
+     CV_LF_COMPLEX128  = 0x800f,       /* 128-bit Complex */
+     CV_LF_VARSTRING   = 0x8010,       /* Variable-length String */
+     /* Leaf padding bytes */
+     CV_LF_PAD0                = 0xf0,
+     CV_LF_PAD1                = 0xf1,
+     CV_LF_PAD2                = 0xf2,
+     CV_LF_PAD3                = 0xf3,
+     CV_LF_PAD4                = 0xf4,
+     CV_LF_PAD5                = 0xf5,
+     CV_LF_PAD6                = 0xf6,
+     CV_LF_PAD7                = 0xf7,
+     CV_LF_PAD8                = 0xf8,
+     CV_LF_PAD9                = 0xf9,
+     CV_LF_PAD10               = 0xfa,
+     CV_LF_PAD11               = 0xfb,
+     CV_LF_PAD12               = 0xfc,
+     CV_LF_PAD13               = 0xfc,
+     CV_LF_PAD14               = 0xfe,
+     CV_LF_PAD15               = 0xff
+ };
+ /* Leaves use a bit of meta-programming to encode formats: each character
+  * of format represents the output generated, as follows:
+  * 'b' : 1 byte value (integer)
+  * 'h' : 2 byte value (integer)
+  * 'w' : 4 byte value (integer)
+  * 'L' : subleaf, recurses into cv_leaf (pointer)
+  * 'T' : 4 byte type index, pulls cv_type.index from cv_type (pointer)
+  * 'S' : length-prefixed string (pointer)
+  */
+ typedef struct cv_leaf {
+     enum cv_leaftype type;
+     const char *format;           /* format of args */
+     union {
+       unsigned long i;
+       void *p;
+     } args[6];
+ } cv_leaf;
+ typedef struct cv_type {
+     yasm_dbgfmt_cv *dbgfmt_cv;
+     unsigned long indx;           /* type # (must be same as output order) */
+     size_t num_leaves;
+     /*@null@*/ /*@only@*/ cv_leaf **leaves;
+ } cv_type;
+ /* Bytecode callback function prototypes */
+ static void cv_type_bc_destroy(void *contents);
+ static void cv_type_bc_print(const void *contents, FILE *f, int indent_level);
 -    cv_type_bc_resolve,
++static int cv_type_bc_calc_len
++    (yasm_bytecode *bc, yasm_bc_add_span_func add_span, void *add_span_data);
+ static int cv_type_bc_tobytes
+     (yasm_bytecode *bc, unsigned char **bufp, void *d,
+      yasm_output_value_func output_value,
+      /*@null@*/ yasm_output_reloc_func output_reloc);
+ /* Bytecode callback structures */
+ static const yasm_bytecode_callback cv_type_bc_callback = {
+     cv_type_bc_destroy,
+     cv_type_bc_print,
+     yasm_bc_finalize_common,
 -    yasm_bc_resolve(bc, 0, NULL);
++    cv_type_bc_calc_len,
++    yasm_bc_expand_common,
+     cv_type_bc_tobytes,
+     0
+ };
+ static cv_type *cv_type_create(yasm_dbgfmt_cv *dbgfmt_cv, unsigned long indx);
+ static void cv_type_append_leaf(cv_type *type, /*@keep@*/ cv_leaf *leaf);
+ static cv_leaf *
+ cv_leaf_create_label(int is_far)
+ {
+     cv_leaf *leaf = yasm_xmalloc(sizeof(cv_leaf));
+     leaf->type = CV5_LF_LABEL;
+     leaf->format = "h";
+     leaf->args[0].i = is_far ? 4 : 0;
+     return leaf;
+ }
+ yasm_section *
+ yasm_cv__generate_type(yasm_dbgfmt_cv *dbgfmt_cv)
+ {
+     int new;
+     unsigned long indx = CV_FIRST_NONPRIM;
+     yasm_section *debug_type;
+     yasm_bytecode *bc;
+     cv_type *type;
+     debug_type = yasm_object_get_general(dbgfmt_cv->object, ".debug$T", 0, 1,
+                                        0, 0, &new, 0);
+     /* Add label type */
+     type = cv_type_create(dbgfmt_cv, indx++);
+     cv_type_append_leaf(type, cv_leaf_create_label(0));
+     bc = yasm_bc_create_common(&cv_type_bc_callback, type, 0);
+     yasm_bc_finalize(bc, yasm_cv__append_bc(debug_type, bc));
 -static yasm_bc_resolve_flags
 -cv_type_bc_resolve(yasm_bytecode *bc, int save,
 -                 yasm_calc_bc_dist_func calc_bc_dist)
++    yasm_bc_calc_len(bc, NULL, NULL);
+     return debug_type;
+ }
+ static void
+ cv_leaf_destroy(cv_leaf *leaf)
+ {
+     const char *ch = leaf->format;
+     int arg = 0;
+     while (*ch) {
+       switch (*ch) {
+           case 'b':
+           case 'h':
+           case 'w':
+               arg++;
+               break;  /* nothing to destroy */
+           case 'L':
+               cv_leaf_destroy((cv_leaf *)leaf->args[arg++].p);
+               break;
+           case 'T':
+               arg++;  /* nothing to destroy */
+               break;
+           case 'S':
+               yasm_xfree(leaf->args[arg++].p);
+               break;
+           default:
+               yasm_internal_error(N_("unknown leaf format character"));
+       }
+       ch++;
+     }
+ }
+ static unsigned long
+ cv_leaf_size(const cv_leaf *leaf)
+ {
+     const char *ch = leaf->format;
+     unsigned long len = 2;  /* leaf type */
+     unsigned long slen;
+     int arg = 0;
+     while (*ch) {
+       switch (*ch) {
+           case 'b':
+               len++;
+               arg++;
+               break;
+           case 'h':
+               len += 2;
+               arg++;
+               break;
+           case 'w':
+               len += 4;
+               arg++;
+               break;
+           case 'L':
+               len += cv_leaf_size((const cv_leaf *)leaf->args[arg++].p);
+               break;
+           case 'T':
+               len += 4;       /* XXX: will be 2 in CV4 */
+               arg++;
+               break;
+           case 'S':
+               len += 1;       /* XXX: is this 1 or 2? */
+               slen = strlen((const char *)leaf->args[arg++].p);
+               len += slen <= 0xff ? slen : 0xff;
+               break;
+           default:
+               yasm_internal_error(N_("unknown leaf format character"));
+       }
+       ch++;
+     }
+     return len;
+ }
+ static void
+ cv_leaf_tobytes(const cv_leaf *leaf, yasm_bytecode *bc, yasm_arch *arch,
+               unsigned char **bufp, yasm_intnum *cval)
+ {
+     unsigned char *buf = *bufp;
+     const char *ch = leaf->format;
+     size_t len;
+     int arg = 0;
+     /* leaf type */
+     yasm_intnum_set_uint(cval, leaf->type);
+     yasm_arch_intnum_tobytes(arch, cval, buf, 2, 16, 0, bc, 0);
+     buf += 2;
+     while (*ch) {
+       switch (*ch) {
+           case 'b':
+               YASM_WRITE_8(buf, leaf->args[arg].i);
+               arg++;
+               break;
+           case 'h':
+               yasm_intnum_set_uint(cval, leaf->args[arg++].i);
+               yasm_arch_intnum_tobytes(arch, cval, buf, 2, 16, 0, bc, 0);
+               buf += 2;
+               break;
+           case 'w':
+               yasm_intnum_set_uint(cval, leaf->args[arg++].i);
+               yasm_arch_intnum_tobytes(arch, cval, buf, 4, 32, 0, bc, 0);
+               buf += 4;
+               break;
+           case 'L':
+               cv_leaf_tobytes((const cv_leaf *)leaf->args[arg++].p, bc, arch,
+                               &buf, cval);
+               break;
+           case 'T':
+               yasm_intnum_set_uint(cval,
+                   ((const cv_type *)leaf->args[arg++].p)->indx);
+               yasm_arch_intnum_tobytes(arch, cval, buf, 4, 32, 0, bc, 0);
+               buf += 4;       /* XXX: will be 2 in CV4 */
+               break;
+           case 'S':
+               len = strlen((const char *)leaf->args[arg].p);
+               len = len <= 0xff ? len : 0xff;
+               YASM_WRITE_8(buf, len);
+               memcpy(buf, (const char *)leaf->args[arg].p, len);
+               buf += len;
+               arg++;
+               break;
+           default:
+               yasm_internal_error(N_("unknown leaf format character"));
+       }
+       ch++;
+     }
+     *bufp = buf;
+ }
+ static cv_type *
+ cv_type_create(yasm_dbgfmt_cv *dbgfmt_cv, unsigned long indx)
+ {
+     cv_type *type = yasm_xmalloc(sizeof(cv_type));
+     type->dbgfmt_cv = dbgfmt_cv;
+     type->indx = indx;
+     type->num_leaves = 0;
+     type->leaves = NULL;
+     return type;
+ }
+ static void
+ cv_type_append_leaf(cv_type *type, /*@keep@*/ cv_leaf *leaf)
+ {
+     type->num_leaves++;
+     /* This is inefficient for large numbers of leaves, but that won't happen
+      * until we add structure support.
+      */
+     type->leaves = yasm_xrealloc(type->leaves,
+                                type->num_leaves*sizeof(cv_leaf *));
+     type->leaves[type->num_leaves-1] = leaf;
+ }
+ static void
+ cv_type_bc_destroy(void *contents)
+ {
+     cv_type *type = (cv_type *)contents;
+     size_t i;
+     for (i=0; i<type->num_leaves; i++)
+       cv_leaf_destroy(type->leaves[i]);
+     if (type->leaves)
+       yasm_xfree(type->leaves);
+     yasm_xfree(contents);
+ }
+ static void
+ cv_type_bc_print(const void *contents, FILE *f, int indent_level)
+ {
+     /* TODO */
+ }
 -    return YASM_BC_RESOLVE_MIN_LEN;
++static int
++cv_type_bc_calc_len(yasm_bytecode *bc, yasm_bc_add_span_func add_span,
++                  void *add_span_data)
+ {
+     cv_type *type = (cv_type *)bc->contents;
+     size_t i;
+     if (type->indx == CV_FIRST_NONPRIM)
+       bc->len = 4+2;
+     else
+       bc->len = 2;
+     for (i=0; i<type->num_leaves; i++)
+       bc->len += cv_leaf_size(type->leaves[i]);
+     /* Pad to multiple of 4 */
+     if (bc->len & 0x3)
+       bc->len += 4-(bc->len & 0x3);
++    return 0;
+ }
+ static int
+ cv_type_bc_tobytes(yasm_bytecode *bc, unsigned char **bufp, void *d,
+                  yasm_output_value_func output_value,
+                  yasm_output_reloc_func output_reloc)
+ {
+     cv_type *type = (cv_type *)bc->contents;
+     yasm_dbgfmt_cv *dbgfmt_cv = type->dbgfmt_cv;
+     unsigned char *buf = *bufp;
+     yasm_intnum *cval;
+     size_t i;
+     unsigned long reclen = bc->len - 2;
+     cval = yasm_intnum_create_uint(4);            /* version */
+     if (type->indx == CV_FIRST_NONPRIM) {
+       yasm_arch_intnum_tobytes(dbgfmt_cv->arch, cval, buf, 4, 32, 0, bc, 1);
+       buf += 4;
+       reclen -= 4;
+     }
+     /* Total length of record (following this field) - 2 bytes */
+     yasm_intnum_set_uint(cval, reclen);
+     yasm_arch_intnum_tobytes(dbgfmt_cv->arch, cval, buf, 2, 16, 0, bc, 1);
+     buf += 2;
+     /* Leaves */
+     for (i=0; i<type->num_leaves; i++)
+       cv_leaf_tobytes(type->leaves[i], bc, dbgfmt_cv->arch, &buf, cval);
+     /* Pad to multiple of 4 */
+     switch ((buf-(*bufp)) & 0x3) {
+       case 3:
+           YASM_WRITE_8(buf, CV_LF_PAD3);
+       case 2:
+           YASM_WRITE_8(buf, CV_LF_PAD2);
+       case 1:
+           YASM_WRITE_8(buf, CV_LF_PAD1);
+       case 0:
+           break;
+     }
+     *bufp = buf;
+     yasm_intnum_destroy(cval);
+     return 0;
+ }
index 0000000000000000000000000000000000000000,7c4010b0c31da63dc10c93c34fc685399d6cf444..b8056fd638d8f9aa563759f39d0a76d1c9a54c6f
mode 000000,100644..100644
--- /dev/null
@@@ -1,0 -1,126 +1,126 @@@
 -    yasm_bc_resolve(bc, 0, NULL);
+ /*
+  * DWARF2 debugging format - address range table
+  *
+  *  Copyright (C) 2006  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
+ #include <libyasm.h>
+ #include "dwarf2-dbgfmt.h"
+ static void
+ dwarf2_append_arange(yasm_section *debug_aranges, /*@only@*/ yasm_expr *start,
+                    /*@only@*/ yasm_expr *length, size_t sizeof_address)
+ {
+     yasm_datavalhead dvs;
+     yasm_bytecode *bc;
+     yasm_dvs_initialize(&dvs);
+     yasm_dvs_append(&dvs, yasm_dv_create_expr(start));
+     yasm_dvs_append(&dvs, yasm_dv_create_expr(length));
+     bc = yasm_bc_create_data(&dvs, sizeof_address, 0, NULL, 0);
+     yasm_bc_finalize(bc, yasm_dwarf2__append_bc(debug_aranges, bc));
 -    yasm_bc_resolve(bc, 0, NULL);
++    yasm_bc_calc_len(bc, NULL, NULL);
+ }
+ typedef struct dwarf2_aranges_info {
+     yasm_section *debug_aranges;    /* section to which address ranges go */
+     yasm_dbgfmt_dwarf2 *dbgfmt_dwarf2;
+ } dwarf2_aranges_info;
+ static int
+ dwarf2_generate_aranges_section(yasm_section *sect, /*@null@*/ void *d)
+ {
+     dwarf2_aranges_info *info = (dwarf2_aranges_info *)d;
+     yasm_dbgfmt_dwarf2 *dbgfmt_dwarf2 = info->dbgfmt_dwarf2;
+     /*@null@*/ dwarf2_section_data *dsd;
+     /*@only@*/ yasm_expr *start, *length;
+     dsd = yasm_section_get_data(sect, &yasm_dwarf2__section_data_cb);
+     if (!dsd)
+       return 0;       /* no line data for this section */
+     /* Create address range descriptor */
+     start = yasm_expr_create_ident(
+       yasm_expr_sym(yasm_dwarf2__bc_sym(dbgfmt_dwarf2->symtab,
+                                         yasm_section_bcs_first(sect))), 0);
+     length = yasm_expr_create_ident(
+       yasm_expr_int(yasm_common_calc_bc_dist(
+           yasm_section_bcs_first(sect), yasm_section_bcs_last(sect))), 0);
+     dwarf2_append_arange(info->debug_aranges, start, length,
+                        dbgfmt_dwarf2->sizeof_address);
+     return 0;
+ }
+ yasm_section *
+ yasm_dwarf2__generate_aranges(yasm_dbgfmt_dwarf2 *dbgfmt_dwarf2,
+                             yasm_section *debug_info)
+ {
+     int new;
+     yasm_section *debug_aranges;
+     yasm_bytecode *bc;
+     dwarf2_head *head;
+     dwarf2_aranges_info info;
+     debug_aranges =
+       yasm_object_get_general(dbgfmt_dwarf2->object, ".debug_aranges", 0,
+                               2*dbgfmt_dwarf2->sizeof_address, 0, 0, &new,
+                               0);
+     /* header */
+     head = yasm_dwarf2__add_head(dbgfmt_dwarf2, debug_aranges, debug_info, 1,
+                                1);
+     /* align ranges to 2x address size (range size) */
+     bc = yasm_bc_create_align(
+       yasm_expr_create_ident(yasm_expr_int(
+           yasm_intnum_create_uint(dbgfmt_dwarf2->sizeof_address*2)), 0),
+       NULL, NULL, NULL, 0);
+     yasm_bc_finalize(bc, yasm_dwarf2__append_bc(debug_aranges, bc));
++    yasm_bc_calc_len(bc, NULL, NULL);
+     info.debug_aranges = debug_aranges;
+     info.dbgfmt_dwarf2 = dbgfmt_dwarf2;
+     yasm_object_sections_traverse(dbgfmt_dwarf2->object, (void *)&info,
+                                 dwarf2_generate_aranges_section);
+     /* Terminate with empty address range descriptor */
+     dwarf2_append_arange(debug_aranges,
+       yasm_expr_create_ident(yasm_expr_int(yasm_intnum_create_uint(0)), 0),
+       yasm_expr_create_ident(yasm_expr_int(yasm_intnum_create_uint(0)), 0),
+       dbgfmt_dwarf2->sizeof_address);
+     /* mark end of aranges information */
+     yasm_dwarf2__set_head_end(head, yasm_section_bcs_last(debug_aranges));
+     return debug_aranges;
+ }
index 0000000000000000000000000000000000000000,f9e9dac5c907a9626f2ce69132aab2241a7d2cbf..54f10f4f8c6fed023609898ae59f20edcca9735d
mode 000000,100644..100644
--- /dev/null
@@@ -1,0 -1,356 +1,357 @@@
 -static yasm_bc_resolve_flags dwarf2_head_bc_resolve
 -    (yasm_bytecode *bc, int save, yasm_calc_bc_dist_func calc_bc_dist);
+ /*
+  * DWARF2 debugging format
+  *
+  *  Copyright (C) 2006  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
+ #include <libyasm.h>
+ #include "dwarf2-dbgfmt.h"
+ struct dwarf2_head {
+     yasm_dbgfmt_dwarf2 *dbgfmt_dwarf2;
+     yasm_bytecode *start_prevbc;
+     yasm_bytecode *end_prevbc;
+     /*@null@*/ yasm_section *debug_ptr;
+     int with_address;
+     int with_segment;
+ };
+ /* Bytecode callback function prototypes */
+ static void dwarf2_head_bc_destroy(void *contents);
+ static void dwarf2_head_bc_print(const void *contents, FILE *f,
+                                int indent_level);
 -    dwarf2_head_bc_resolve,
++static int dwarf2_head_bc_calc_len
++    (yasm_bytecode *bc, yasm_bc_add_span_func add_span, void *add_span_data);
+ static int dwarf2_head_bc_tobytes
+     (yasm_bytecode *bc, unsigned char **bufp, void *d,
+      yasm_output_value_func output_value,
+      /*@null@*/ yasm_output_reloc_func output_reloc);
+ /* Bytecode callback structures */
+ static const yasm_bytecode_callback dwarf2_head_bc_callback = {
+     dwarf2_head_bc_destroy,
+     dwarf2_head_bc_print,
+     yasm_bc_finalize_common,
 -static yasm_bc_resolve_flags
 -dwarf2_head_bc_resolve(yasm_bytecode *bc, int save,
 -                     yasm_calc_bc_dist_func calc_bc_dist)
++    dwarf2_head_bc_calc_len,
++    yasm_bc_expand_common,
+     dwarf2_head_bc_tobytes,
+     0
+ };
+ /* Section data callback function prototypes */
+ static void dwarf2_section_data_destroy(void *data);
+ static void dwarf2_section_data_print(void *data, FILE *f, int indent_level);
+ /* Section data callback */
+ const yasm_assoc_data_callback yasm_dwarf2__section_data_cb = {
+     dwarf2_section_data_destroy,
+     dwarf2_section_data_print
+ };
+ yasm_dbgfmt_module yasm_dwarf2_LTX_dbgfmt;
+ static /*@null@*/ /*@only@*/ yasm_dbgfmt *
+ dwarf2_dbgfmt_create(yasm_object *object, yasm_objfmt *of, yasm_arch *a)
+ {
+     yasm_dbgfmt_dwarf2 *dbgfmt_dwarf2 =
+       yasm_xmalloc(sizeof(yasm_dbgfmt_dwarf2));
+     size_t i;
+     dbgfmt_dwarf2->dbgfmt.module = &yasm_dwarf2_LTX_dbgfmt;
+     dbgfmt_dwarf2->object = object;
+     dbgfmt_dwarf2->symtab = yasm_object_get_symtab(object);
+     dbgfmt_dwarf2->linemap = yasm_object_get_linemap(object);
+     dbgfmt_dwarf2->arch = a;
+     dbgfmt_dwarf2->dirs_allocated = 32;
+     dbgfmt_dwarf2->dirs_size = 0;
+     dbgfmt_dwarf2->dirs =
+       yasm_xmalloc(sizeof(char *)*dbgfmt_dwarf2->dirs_allocated);
+     dbgfmt_dwarf2->filenames_allocated = 32;
+     dbgfmt_dwarf2->filenames_size = 0;
+     dbgfmt_dwarf2->filenames =
+       yasm_xmalloc(sizeof(dwarf2_filename)*dbgfmt_dwarf2->filenames_allocated);
+     for (i=0; i<dbgfmt_dwarf2->filenames_allocated; i++) {
+       dbgfmt_dwarf2->filenames[i].pathname = NULL;
+       dbgfmt_dwarf2->filenames[i].filename = NULL;
+       dbgfmt_dwarf2->filenames[i].dir = 0;
+     }
+     dbgfmt_dwarf2->format = DWARF2_FORMAT_32BIT;    /* TODO: flexible? */
+     dbgfmt_dwarf2->sizeof_address = yasm_arch_get_address_size(a)/8;
+     switch (dbgfmt_dwarf2->format) {
+       case DWARF2_FORMAT_32BIT:
+           dbgfmt_dwarf2->sizeof_offset = 4;
+           break;
+       case DWARF2_FORMAT_64BIT:
+           dbgfmt_dwarf2->sizeof_offset = 8;
+           break;
+     }
+     dbgfmt_dwarf2->min_insn_len = yasm_arch_min_insn_len(a);
+     return (yasm_dbgfmt *)dbgfmt_dwarf2;
+ }
+ static void
+ dwarf2_dbgfmt_destroy(/*@only@*/ yasm_dbgfmt *dbgfmt)
+ {
+     yasm_dbgfmt_dwarf2 *dbgfmt_dwarf2 = (yasm_dbgfmt_dwarf2 *)dbgfmt;
+     size_t i;
+     for (i=0; i<dbgfmt_dwarf2->dirs_size; i++)
+       if (dbgfmt_dwarf2->dirs[i])
+           yasm_xfree(dbgfmt_dwarf2->dirs[i]);
+     yasm_xfree(dbgfmt_dwarf2->dirs);
+     for (i=0; i<dbgfmt_dwarf2->filenames_size; i++) {
+       if (dbgfmt_dwarf2->filenames[i].pathname)
+           yasm_xfree(dbgfmt_dwarf2->filenames[i].pathname);
+       if (dbgfmt_dwarf2->filenames[i].filename)
+           yasm_xfree(dbgfmt_dwarf2->filenames[i].filename);
+     }
+     yasm_xfree(dbgfmt_dwarf2->filenames);
+     yasm_xfree(dbgfmt);
+ }
+ /* Add a bytecode to a section, updating offset on insertion;
+  * no optimization necessary.
+  */
+ yasm_bytecode *
+ yasm_dwarf2__append_bc(yasm_section *sect, yasm_bytecode *bc)
+ {
+     yasm_bytecode *precbc = yasm_section_bcs_last(sect);
+     bc->offset = precbc ? precbc->offset + precbc->len : 0;
+     yasm_section_bcs_append(sect, bc);
+     return precbc;
+ }
+ static void
+ dwarf2_dbgfmt_generate(yasm_dbgfmt *dbgfmt, yasm_errwarns *errwarns)
+ {
+     yasm_dbgfmt_dwarf2 *dbgfmt_dwarf2 = (yasm_dbgfmt_dwarf2 *)dbgfmt;
+     size_t num_line_sections;
+     /*@null@*/ yasm_section *debug_info, *debug_line, *main_code;
+     /* If we don't have any .file directives, generate line information
+      * based on the asm source.
+      */
+     debug_line = yasm_dwarf2__generate_line(dbgfmt_dwarf2, errwarns,
+                                           dbgfmt_dwarf2->filenames_size == 0,
+                                           &main_code, &num_line_sections);
+     /* If we don't have a .debug_info (or it's empty), generate the minimal
+      * set of .debug_info, .debug_aranges, and .debug_abbrev so that the
+      * .debug_line we're generating is actually useful.
+      */
+     debug_info = yasm_object_find_general(dbgfmt_dwarf2->object, ".debug_info");
+     if (num_line_sections > 0 &&
+       (!debug_info || yasm_section_bcs_first(debug_info)
+                       == yasm_section_bcs_last(debug_info))) {
+       debug_info = yasm_dwarf2__generate_info(dbgfmt_dwarf2, debug_line,
+                                               main_code);
+       yasm_dwarf2__generate_aranges(dbgfmt_dwarf2, debug_info);
+       /*yasm_dwarf2__generate_pubnames(dbgfmt_dwarf2, debug_info);*/
+     }
+ }
+ yasm_symrec *
+ yasm_dwarf2__bc_sym(yasm_symtab *symtab, yasm_bytecode *bc)
+ {
+     /*@dependent@*/ yasm_symrec *sym;
+     if (bc->symrecs && bc->symrecs[0])
+       sym = bc->symrecs[0];
+     else
+       sym = yasm_symtab_define_label(symtab, ".bcsym", bc, 0, 0);
+     return sym;
+ }
+ dwarf2_head *
+ yasm_dwarf2__add_head
+     (yasm_dbgfmt_dwarf2 *dbgfmt_dwarf2, yasm_section *sect,
+      /*@null@*/ yasm_section *debug_ptr, int with_address, int with_segment)
+ {
+     dwarf2_head *head;
+     yasm_bytecode *bc;
+     head = yasm_xmalloc(sizeof(dwarf2_head));
+     head->dbgfmt_dwarf2 = dbgfmt_dwarf2;
+     head->start_prevbc = yasm_section_bcs_last(sect);
+     bc = yasm_bc_create_common(&dwarf2_head_bc_callback, head, 0);
+     bc->len = dbgfmt_dwarf2->sizeof_offset + 2;
+     if (dbgfmt_dwarf2->format == DWARF2_FORMAT_64BIT)
+       bc->len += 4;
+     if (debug_ptr) {
+       head->debug_ptr = debug_ptr;
+       bc->len += dbgfmt_dwarf2->sizeof_offset;
+     } else
+       head->debug_ptr = NULL;
+     head->with_address = with_address;
+     head->with_segment = with_segment;
+     if (with_address)
+       bc->len++;
+     if (with_segment)
+       bc->len++;
+     head->end_prevbc = bc;
+     yasm_dwarf2__append_bc(sect, bc);
+     return head;
+ }
+ void
+ yasm_dwarf2__set_head_end(dwarf2_head *head, yasm_bytecode *end_prevbc)
+ {
+     head->end_prevbc = end_prevbc;
+ }
+ static void
+ dwarf2_head_bc_destroy(void *contents)
+ {
+     yasm_xfree(contents);
+ }
+ static void
+ dwarf2_head_bc_print(const void *contents, FILE *f, int indent_level)
+ {
+     /* TODO */
+ }
 -    yasm_internal_error(N_("tried to resolve a dwarf2 head bytecode"));
++static int
++dwarf2_head_bc_calc_len(yasm_bytecode *bc, yasm_bc_add_span_func add_span,
++                      void *add_span_data)
+ {
 -    return YASM_BC_RESOLVE_MIN_LEN;
++    yasm_internal_error(N_("tried to calc_len a dwarf2 head bytecode"));
+     /*@notreached@*/
++    return 0;
+ }
+ static int
+ dwarf2_head_bc_tobytes(yasm_bytecode *bc, unsigned char **bufp, void *d,
+                      yasm_output_value_func output_value,
+                      yasm_output_reloc_func output_reloc)
+ {
+     dwarf2_head *head = (dwarf2_head *)bc->contents;
+     yasm_dbgfmt_dwarf2 *dbgfmt_dwarf2 = head->dbgfmt_dwarf2;
+     unsigned char *buf = *bufp;
+     yasm_intnum *intn, *cval;
+     if (dbgfmt_dwarf2->format == DWARF2_FORMAT_64BIT) {
+       YASM_WRITE_8(buf, 0xff);
+       YASM_WRITE_8(buf, 0xff);
+       YASM_WRITE_8(buf, 0xff);
+       YASM_WRITE_8(buf, 0xff);
+     }
+     /* Total length of aranges info (following this field) */
+     cval = yasm_intnum_create_uint(dbgfmt_dwarf2->sizeof_offset);
+     intn = yasm_common_calc_bc_dist(head->start_prevbc, head->end_prevbc);
+     yasm_intnum_calc(intn, YASM_EXPR_SUB, cval);
+     yasm_arch_intnum_tobytes(dbgfmt_dwarf2->arch, intn, buf,
+                            dbgfmt_dwarf2->sizeof_offset,
+                            dbgfmt_dwarf2->sizeof_offset*8, 0, bc, 0);
+     buf += dbgfmt_dwarf2->sizeof_offset;
+     yasm_intnum_destroy(intn);
+     /* DWARF version */
+     yasm_intnum_set_uint(cval, 2);
+     yasm_arch_intnum_tobytes(dbgfmt_dwarf2->arch, cval, buf, 2, 16, 0, bc, 0);
+     buf += 2;
+     /* Pointer to another debug section */
+     if (head->debug_ptr) {
+       yasm_value value;
+       yasm_value_init_sym(&value,
+           yasm_dwarf2__bc_sym(dbgfmt_dwarf2->symtab,
+                               yasm_section_bcs_first(head->debug_ptr)),
+           dbgfmt_dwarf2->sizeof_offset*8);
+       output_value(&value, buf, dbgfmt_dwarf2->sizeof_offset,
+                    (unsigned long)(buf-*bufp), bc, 0, d);
+       buf += dbgfmt_dwarf2->sizeof_offset;
+     }
+     /* Size of the offset portion of the address */
+     if (head->with_address)
+       YASM_WRITE_8(buf, dbgfmt_dwarf2->sizeof_address);
+     /* Size of a segment descriptor.  0 = flat address space */
+     if (head->with_segment)
+       YASM_WRITE_8(buf, 0);
+     *bufp = buf;
+     yasm_intnum_destroy(cval);
+     return 0;
+ }
+ static void
+ dwarf2_section_data_destroy(void *data)
+ {
+     dwarf2_section_data *dsd = data;
+     dwarf2_loc *n1, *n2;
+     /* Delete locations */
+     n1 = STAILQ_FIRST(&dsd->locs);
+     while (n1) {
+       n2 = STAILQ_NEXT(n1, link);
+       yasm_xfree(n1);
+       n1 = n2;
+     }
+     yasm_xfree(data);
+ }
+ static void
+ dwarf2_section_data_print(void *data, FILE *f, int indent_level)
+ {
+     /* TODO */
+ }
+ static int
+ dwarf2_dbgfmt_directive(yasm_dbgfmt *dbgfmt, const char *name,
+                       yasm_section *sect, yasm_valparamhead *valparams,
+                       unsigned long line)
+ {
+     yasm_dbgfmt_dwarf2 *dbgfmt_dwarf2 = (yasm_dbgfmt_dwarf2 *)dbgfmt;
+     return yasm_dwarf2__line_directive(dbgfmt_dwarf2, name, sect, valparams,
+                                      line);
+ }
+ /* Define dbgfmt structure -- see dbgfmt.h for details */
+ yasm_dbgfmt_module yasm_dwarf2_LTX_dbgfmt = {
+     "DWARF2 debugging format",
+     "dwarf2",
+     dwarf2_dbgfmt_create,
+     dwarf2_dbgfmt_destroy,
+     dwarf2_dbgfmt_directive,
+     dwarf2_dbgfmt_generate
+ };
index 0000000000000000000000000000000000000000,c2692fe5da9841909eec331beaec4a6439e58613..11ac620b764e824ffd1b73c356fe968ad0dbf9cf
mode 000000,100644..100644
--- /dev/null
@@@ -1,0 -1,440 +1,441 @@@
 -static yasm_bc_resolve_flags dwarf2_abbrev_bc_resolve
 -    (yasm_bytecode *bc, int save, yasm_calc_bc_dist_func calc_bc_dist);
+ /*
+  * DWARF2 debugging format - info and abbreviation tables
+  *
+  *  Copyright (C) 2006  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.
+  */
+ #ifdef HAVE_CONFIG_H
+ #include <config.h>
+ #undef HAVE_CONFIG_H
+ #endif
+ /* Need either unistd.h or direct.h (on Windows) to prototype getcwd() */
+ #ifdef HAVE_UNISTD_H
+ #include <unistd.h>
+ #elif defined(WIN32) || defined(_WIN32)
+ #include <direct.h>
+ #endif
+ #include <util.h>
+ /*@unused@*/ RCSID("$Id$");
+ #define YASM_LIB_INTERNAL
+ #define YASM_BC_INTERNAL
+ #include <libyasm.h>
+ #include "dwarf2-dbgfmt.h"
+ #define DW_LANG_Mips_Assembler        0x8001
+ /* Tag encodings */
+ typedef enum {
+     DW_TAG_padding = 0x00,
+     DW_TAG_array_type = 0x01,
+     DW_TAG_class_type = 0x02,
+     DW_TAG_entry_point = 0x03,
+     DW_TAG_enumeration_type = 0x04,
+     DW_TAG_formal_parameter = 0x05,
+     DW_TAG_imported_declaration = 0x08,
+     DW_TAG_label = 0x0a,
+     DW_TAG_lexical_block = 0x0b,
+     DW_TAG_member = 0x0d,
+     DW_TAG_pointer_type = 0x0f,
+     DW_TAG_reference_type = 0x10,
+     DW_TAG_compile_unit = 0x11,
+     DW_TAG_string_type = 0x12,
+     DW_TAG_structure_type = 0x13,
+     DW_TAG_subroutine_type = 0x15,
+     DW_TAG_typedef = 0x16,
+     DW_TAG_union_type = 0x17,
+     DW_TAG_unspecified_parameters = 0x18,
+     DW_TAG_variant = 0x19,
+     DW_TAG_common_block = 0x1a,
+     DW_TAG_common_inclusion = 0x1b,
+     DW_TAG_inheritance = 0x1c,
+     DW_TAG_inlined_subroutine = 0x1d,
+     DW_TAG_module = 0x1e,
+     DW_TAG_ptr_to_member_type = 0x1f,
+     DW_TAG_set_type = 0x20,
+     DW_TAG_subrange_type = 0x21,
+     DW_TAG_with_stmt = 0x22,
+     DW_TAG_access_declaration = 0x23,
+     DW_TAG_base_type = 0x24,
+     DW_TAG_catch_block = 0x25,
+     DW_TAG_const_type = 0x26,
+     DW_TAG_constant = 0x27,
+     DW_TAG_enumerator = 0x28,
+     DW_TAG_file_type = 0x29,
+     DW_TAG_friend = 0x2a,
+     DW_TAG_namelist = 0x2b,
+     DW_TAG_namelist_item = 0x2c,
+     DW_TAG_packed_type = 0x2d,
+     DW_TAG_subprogram = 0x2e,
+     DW_TAG_template_type_param = 0x2f,
+     DW_TAG_template_value_param = 0x30,
+     DW_TAG_thrown_type = 0x31,
+     DW_TAG_try_block = 0x32,
+     DW_TAG_variant_part = 0x33,
+     DW_TAG_variable = 0x34,
+     DW_TAG_volatile_type = 0x35
+ } dwarf_tag;
+ /* Attribute form encodings */
+ typedef enum {
+     DW_FORM_addr = 0x01,
+     DW_FORM_block2 = 0x03,
+     DW_FORM_block4 = 0x04,
+     DW_FORM_data2 = 0x05,
+     DW_FORM_data4 = 0x06,
+     DW_FORM_data8 = 0x07,
+     DW_FORM_string = 0x08,
+     DW_FORM_block = 0x09,
+     DW_FORM_block1 = 0x0a,
+     DW_FORM_data1 = 0x0b,
+     DW_FORM_flag = 0x0c,
+     DW_FORM_sdata = 0x0d,
+     DW_FORM_strp = 0x0e,
+     DW_FORM_udata = 0x0f,
+     DW_FORM_ref_addr = 0x10,
+     DW_FORM_ref1 = 0x11,
+     DW_FORM_ref2 = 0x12,
+     DW_FORM_ref4 = 0x13,
+     DW_FORM_ref8 = 0x14,
+     DW_FORM_ref_udata = 0x15,
+     DW_FORM_indirect = 0x16
+ } dwarf_form;
+ /* Attribute encodings */
+ typedef enum {
+     DW_AT_sibling = 0x01,
+     DW_AT_location = 0x02,
+     DW_AT_name = 0x03,
+     DW_AT_ordering = 0x09,
+     DW_AT_subscr_data = 0x0a,
+     DW_AT_byte_size = 0x0b,
+     DW_AT_bit_offset = 0x0c,
+     DW_AT_bit_size = 0x0d,
+     DW_AT_element_list = 0x0f,
+     DW_AT_stmt_list = 0x10,
+     DW_AT_low_pc = 0x11,
+     DW_AT_high_pc = 0x12,
+     DW_AT_language = 0x13,
+     DW_AT_member = 0x14,
+     DW_AT_discr = 0x15,
+     DW_AT_discr_value = 0x16,
+     DW_AT_visibility = 0x17,
+     DW_AT_import = 0x18,
+     DW_AT_string_length = 0x19,
+     DW_AT_common_reference = 0x1a,
+     DW_AT_comp_dir = 0x1b,
+     DW_AT_const_value = 0x1c,
+     DW_AT_containing_type = 0x1d,
+     DW_AT_default_value = 0x1e,
+     DW_AT_inline = 0x20,
+     DW_AT_is_optional = 0x21,
+     DW_AT_lower_bound = 0x22,
+     DW_AT_producer = 0x25,
+     DW_AT_prototyped = 0x27,
+     DW_AT_return_addr = 0x2a,
+     DW_AT_start_scope = 0x2c,
+     DW_AT_stride_size = 0x2e,
+     DW_AT_upper_bound = 0x2f,
+     DW_AT_abstract_origin = 0x31,
+     DW_AT_accessibility = 0x32,
+     DW_AT_address_class = 0x33,
+     DW_AT_artificial = 0x34,
+     DW_AT_base_types = 0x35,
+     DW_AT_calling_convention = 0x36,
+     DW_AT_count = 0x37,
+     DW_AT_data_member_location = 0x38,
+     DW_AT_decl_column = 0x39,
+     DW_AT_decl_file = 0x3a,
+     DW_AT_decl_line = 0x3b,
+     DW_AT_declaration = 0x3c,
+     DW_AT_discr_list = 0x3d,
+     DW_AT_encoding = 0x3e,
+     DW_AT_external = 0x3f,
+     DW_AT_frame_base = 0x40,
+     DW_AT_friend = 0x41,
+     DW_AT_identifier_case = 0x42,
+     DW_AT_macro_info = 0x43,
+     DW_AT_namelist_items = 0x44,
+     DW_AT_priority = 0x45,
+     DW_AT_segment = 0x46,
+     DW_AT_specification = 0x47,
+     DW_AT_static_link = 0x48,
+     DW_AT_type = 0x49,
+     DW_AT_use_location = 0x4a,
+     DW_AT_variable_parameter = 0x4b,
+     DW_AT_virtuality = 0x4c,
+     DW_AT_vtable_elem_location = 0x4d
+ } dwarf_attribute;
+ typedef struct dwarf2_abbrev_attr {
+     STAILQ_ENTRY(dwarf2_abbrev_attr) link;
+     dwarf_attribute name;
+     dwarf_form form;
+ } dwarf2_abbrev_attr;
+ typedef struct dwarf2_abbrev {
+     unsigned long id;
+     dwarf_tag tag;
+     int has_children;
+     STAILQ_HEAD(dwarf2_abbrev_attrhead, dwarf2_abbrev_attr) attrs;
+ } dwarf2_abbrev;
+ /* Bytecode callback function prototypes */
+ static void dwarf2_abbrev_bc_destroy(void *contents);
+ static void dwarf2_abbrev_bc_print(const void *contents, FILE *f,
+                                  int indent_level);
 -    dwarf2_abbrev_bc_resolve,
++static int dwarf2_abbrev_bc_calc_len
++    (yasm_bytecode *bc, yasm_bc_add_span_func add_span, void *add_span_data);
+ static int dwarf2_abbrev_bc_tobytes
+     (yasm_bytecode *bc, unsigned char **bufp, void *d,
+      yasm_output_value_func output_value,
+      /*@null@*/ yasm_output_reloc_func output_reloc);
+ /* Bytecode callback structures */
+ static const yasm_bytecode_callback dwarf2_abbrev_bc_callback = {
+     dwarf2_abbrev_bc_destroy,
+     dwarf2_abbrev_bc_print,
+     yasm_bc_finalize_common,
 -    yasm_bc_resolve(bc, 0, NULL);
++    dwarf2_abbrev_bc_calc_len,
++    yasm_bc_expand_common,
+     dwarf2_abbrev_bc_tobytes,
+     0
+ };
+ static unsigned long
+ dwarf2_add_abbrev_attr(dwarf2_abbrev *abbrev, dwarf_attribute name,
+                      dwarf_form form)
+ {
+     dwarf2_abbrev_attr *attr = yasm_xmalloc(sizeof(dwarf2_abbrev_attr));
+     attr->name = name;
+     attr->form = form;
+     STAILQ_INSERT_TAIL(&abbrev->attrs, attr, link);
+     return yasm_size_uleb128(name) + yasm_size_uleb128(form);
+ }
+ static void
+ dwarf2_append_expr(yasm_section *sect, /*@only@*/ yasm_expr *expr, size_t size,
+                  int leb)
+ {
+     yasm_datavalhead dvs;
+     yasm_bytecode *bc;
+     yasm_dvs_initialize(&dvs);
+     yasm_dvs_append(&dvs, yasm_dv_create_expr(expr));
+     if (leb == 0)
+       bc = yasm_bc_create_data(&dvs, size, 0, NULL, 0);
+     else
+       bc = yasm_bc_create_leb128(&dvs, leb<0, 0);
+     yasm_bc_finalize(bc, yasm_dwarf2__append_bc(sect, bc));
 -    yasm_bc_resolve(bc, 0, NULL);
++    yasm_bc_calc_len(bc, NULL, NULL);
+ }
+ static void
+ dwarf2_append_str(yasm_section *sect, const char *str)
+ {
+     yasm_datavalhead dvs;
+     yasm_bytecode *bc;
+     yasm_dvs_initialize(&dvs);
+     yasm_dvs_append(&dvs, yasm_dv_create_string(yasm__xstrdup(str),
+                                               strlen(str)));
+     bc = yasm_bc_create_data(&dvs, 1, 1, NULL, 0);
+     yasm_bc_finalize(bc, yasm_dwarf2__append_bc(sect, bc));
 -static yasm_bc_resolve_flags
 -dwarf2_abbrev_bc_resolve(yasm_bytecode *bc, int save,
 -                       yasm_calc_bc_dist_func calc_bc_dist)
++    yasm_bc_calc_len(bc, NULL, NULL);
+ }
+ yasm_section *
+ yasm_dwarf2__generate_info(yasm_dbgfmt_dwarf2 *dbgfmt_dwarf2,
+                          yasm_section *debug_line, yasm_section *main_code)
+ {
+     int new;
+     yasm_bytecode *abc;
+     dwarf2_abbrev *abbrev;
+     dwarf2_head *head;
+     char *buf;
+     yasm_section *debug_abbrev =
+       yasm_object_get_general(dbgfmt_dwarf2->object, ".debug_abbrev", 0,
+                               4, 0, 0, &new, 0);
+     yasm_section *debug_info =
+       yasm_object_get_general(dbgfmt_dwarf2->object, ".debug_info", 0, 4, 0,
+                               0, &new, 0);
+     yasm_section_set_align(debug_abbrev, 0, 0);
+     yasm_section_set_align(debug_info, 0, 0);
+     /* Create abbreviation table entry for compilation unit */
+     abbrev = yasm_xmalloc(sizeof(dwarf2_abbrev));
+     abc = yasm_bc_create_common(&dwarf2_abbrev_bc_callback, abbrev, 0);
+     abbrev->id = 1;
+     abbrev->tag = DW_TAG_compile_unit;
+     abbrev->has_children = 0;
+     abc->len = yasm_size_uleb128(abbrev->id) + yasm_size_uleb128(abbrev->tag)
+       + 3;
+     STAILQ_INIT(&abbrev->attrs);
+     yasm_dwarf2__append_bc(debug_abbrev, abc);
+     /* info header */
+     head = yasm_dwarf2__add_head(dbgfmt_dwarf2, debug_info, debug_abbrev, 1, 0);
+     /* Generate abbreviations at the same time as info (since they're linked
+      * and we're only generating one piece of info).
+      */
+     /* generating info using abbrev 1 */
+     dwarf2_append_expr(debug_info,
+       yasm_expr_create_ident(yasm_expr_int(yasm_intnum_create_uint(1)), 0),
+       0, 1);
+     /* statement list (line numbers) */
+     abc->len += dwarf2_add_abbrev_attr(abbrev, DW_AT_stmt_list, DW_FORM_data4);
+     dwarf2_append_expr(debug_info,
+       yasm_expr_create_ident(yasm_expr_sym(
+           yasm_dwarf2__bc_sym(dbgfmt_dwarf2->symtab,
+                               yasm_section_bcs_first(debug_line))), 0),
+       dbgfmt_dwarf2->sizeof_offset, 0);
+     if (main_code) {
+       yasm_symrec *first;
+       first = yasm_dwarf2__bc_sym(dbgfmt_dwarf2->symtab,
+                                   yasm_section_bcs_first(main_code));
+       /* All code is contiguous in one section */
+       abc->len += dwarf2_add_abbrev_attr(abbrev, DW_AT_low_pc, DW_FORM_addr);
+       dwarf2_append_expr(debug_info,
+           yasm_expr_create_ident(yasm_expr_sym(first), 0),
+           dbgfmt_dwarf2->sizeof_address, 0);
+       abc->len += dwarf2_add_abbrev_attr(abbrev, DW_AT_high_pc, DW_FORM_addr);
+       dwarf2_append_expr(debug_info,
+           yasm_expr_create(YASM_EXPR_ADD, yasm_expr_sym(first),
+               yasm_expr_int(yasm_common_calc_bc_dist(
+                   yasm_section_bcs_first(main_code),
+                   yasm_section_bcs_last(main_code))), 0),
+           dbgfmt_dwarf2->sizeof_address, 0);
+     }
+     /* input filename */
+     abc->len += dwarf2_add_abbrev_attr(abbrev, DW_AT_name, DW_FORM_string);
+     dwarf2_append_str(debug_info,
+                     yasm_object_get_source_fn(dbgfmt_dwarf2->object));
+     /* compile directory (current working directory) */
+     abc->len += dwarf2_add_abbrev_attr(abbrev, DW_AT_comp_dir, DW_FORM_string);
+     buf = getcwd(NULL, 0);
+     dwarf2_append_str(debug_info, buf);
+     free(buf);
+     /* producer - assembler name */
+     abc->len += dwarf2_add_abbrev_attr(abbrev, DW_AT_producer, DW_FORM_string);
+     dwarf2_append_str(debug_info, PACKAGE " " VERSION);
+     /* language - no standard code for assembler, use MIPS as a substitute */
+     abc->len += dwarf2_add_abbrev_attr(abbrev, DW_AT_language, DW_FORM_data2);
+     dwarf2_append_expr(debug_info,
+       yasm_expr_create_ident(yasm_expr_int(
+           yasm_intnum_create_uint(DW_LANG_Mips_Assembler)), 0), 2, 0);
+     /* Terminate list of abbreviations */
+     abbrev = yasm_xmalloc(sizeof(dwarf2_abbrev));
+     abc = yasm_bc_create_common(&dwarf2_abbrev_bc_callback, abbrev, 0);
+     abbrev->id = 0;
+     abbrev->tag = 0;
+     abbrev->has_children = 0;
+     STAILQ_INIT(&abbrev->attrs);
+     abc->len = 1;
+     yasm_dwarf2__append_bc(debug_abbrev, abc);
+     /* mark end of info */
+     yasm_dwarf2__set_head_end(head, yasm_section_bcs_last(debug_info));
+     return debug_info;
+ }
+ static void
+ dwarf2_abbrev_bc_destroy(void *contents)
+ {
+     dwarf2_abbrev *abbrev = (dwarf2_abbrev *)contents;
+     dwarf2_abbrev_attr *n1, *n2;
+     /* Delete attributes */
+     n1 = STAILQ_FIRST(&abbrev->attrs);
+     while (n1) {
+       n2 = STAILQ_NEXT(n1, link);
+       yasm_xfree(n1);
+       n1 = n2;
+     }
+     yasm_xfree(contents);
+ }
+ static void
+ dwarf2_abbrev_bc_print(const void *contents, FILE *f, int indent_level)
+ {
+     /* TODO */
+ }
 -    yasm_internal_error(N_("tried to resolve a dwarf2 aranges head bytecode"));
++static int
++dwarf2_abbrev_bc_calc_len(yasm_bytecode *bc, yasm_bc_add_span_func add_span,
++                        void *add_span_data)
+ {
 -    return YASM_BC_RESOLVE_MIN_LEN;
++    yasm_internal_error(N_("tried to calc_len a dwarf2 aranges head bytecode"));
+     /*@notreached@*/
++    return 0;
+ }
+ static int
+ dwarf2_abbrev_bc_tobytes(yasm_bytecode *bc, unsigned char **bufp, void *d,
+                        yasm_output_value_func output_value,
+                        yasm_output_reloc_func output_reloc)
+ {
+     dwarf2_abbrev *abbrev = (dwarf2_abbrev *)bc->contents;
+     unsigned char *buf = *bufp;
+     dwarf2_abbrev_attr *attr;
+     if (abbrev->id == 0) {
+       YASM_WRITE_8(buf, 0);
+       *bufp = buf;
+       return 0;
+     }
+     buf += yasm_get_uleb128(abbrev->id, buf);
+     buf += yasm_get_uleb128(abbrev->tag, buf);
+     YASM_WRITE_8(buf, abbrev->has_children);
+     STAILQ_FOREACH(attr, &abbrev->attrs, link) {
+       buf += yasm_get_uleb128(attr->name, buf);
+       buf += yasm_get_uleb128(attr->form, buf);
+     }
+     YASM_WRITE_8(buf, 0);
+     YASM_WRITE_8(buf, 0);
+     *bufp = buf;
+     return 0;
+ }
index 0000000000000000000000000000000000000000,5245a73ca147f60b43c808a42d26de420d9f72b4..e4c35fdcafa80de53069ea7d28f3d9780409c6bf
mode 000000,100644..100644
--- /dev/null
@@@ -1,0 -1,998 +1,1000 @@@
 -static yasm_bc_resolve_flags dwarf2_spp_bc_resolve
 -    (yasm_bytecode *bc, int save, yasm_calc_bc_dist_func calc_bc_dist);
+ /*
+  * DWARF2 debugging format - line information
+  *
+  *  Copyright (C) 2006  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.
+  * 3. Neither the name of the author nor the names of other contributors
+  *    may be used to endorse or promote products derived from this
+  *    software without specific prior written permission.
+  *
+  * 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
+ #include <libyasm.h>
+ #include "dwarf2-dbgfmt.h"
+ /* DWARF line number opcodes */
+ typedef enum {
+     DW_LNS_extended_op = 0,
+     DW_LNS_copy,
+     DW_LNS_advance_pc,
+     DW_LNS_advance_line,
+     DW_LNS_set_file,
+     DW_LNS_set_column,
+     DW_LNS_negate_stmt,
+     DW_LNS_set_basic_block,
+     DW_LNS_const_add_pc,
+     DW_LNS_fixed_advance_pc,
+ #ifdef WITH_DWARF3
+     /* DWARF 3 extensions */
+     DW_LNS_set_prologue_end,
+     DW_LNS_set_epilogue_begin,
+     DW_LNS_set_isa,
+ #endif
+     DWARF2_LINE_OPCODE_BASE
+ } dwarf_line_number_op;
+ /* # of LEB128 operands needed for each of the above opcodes */
+ static unsigned char line_opcode_num_operands[DWARF2_LINE_OPCODE_BASE-1] = {
+     0,        /* DW_LNS_copy */
+     1,        /* DW_LNS_advance_pc */
+     1,        /* DW_LNS_advance_line */
+     1,        /* DW_LNS_set_file */
+     1,        /* DW_LNS_set_column */
+     0,        /* DW_LNS_negate_stmt */
+     0,        /* DW_LNS_set_basic_block */
+     0,        /* DW_LNS_const_add_pc */
+     1,        /* DW_LNS_fixed_advance_pc */
+ #ifdef WITH_DWARF3
+     0,        /* DW_LNS_set_prologue_end */
+     0,        /* DW_LNS_set_epilogue_begin */
+     1 /* DW_LNS_set_isa */
+ #endif
+ };
+ /* Line number extended opcodes */
+ typedef enum {
+     DW_LNE_end_sequence = 1,
+     DW_LNE_set_address,
+     DW_LNE_define_file
+ } dwarf_line_number_ext_op;
+ /* Base and range for line offsets in special opcodes */
+ #define DWARF2_LINE_BASE              -5
+ #define DWARF2_LINE_RANGE             14
+ #define DWARF2_MAX_SPECIAL_ADDR_DELTA \
+     (((255-DWARF2_LINE_OPCODE_BASE)/DWARF2_LINE_RANGE)*\
+      dbgfmt_dwarf2->min_insn_len)
+ /* Initial value of is_stmt register */
+ #define DWARF2_LINE_DEFAULT_IS_STMT   1
+ /* Line number state machine register state */
+ typedef struct dwarf2_line_state {
+     /* static configuration */
+     yasm_dbgfmt_dwarf2 *dbgfmt_dwarf2;
+     /* DWARF2 state machine registers */
+     unsigned long address;
+     unsigned long file;
+     unsigned long line;
+     unsigned long column;
+     unsigned long isa;
+     int is_stmt;
+     /* other state information */
+     /*@null@*/ yasm_bytecode *precbc;
+ } dwarf2_line_state;
+ typedef struct dwarf2_spp {
+     yasm_dbgfmt_dwarf2 *dbgfmt_dwarf2;
+     yasm_bytecode *line_start_prevbc;
+     yasm_bytecode *line_end_prevbc;
+ } dwarf2_spp;
+ typedef struct dwarf2_line_op {
+     dwarf_line_number_op opcode;
+     /*@owned@*/ /*@null@*/ yasm_intnum *operand;
+     /* extended opcode */
+     dwarf_line_number_ext_op ext_opcode;
+     /*@null@*/ /*@dependent@*/ yasm_symrec *ext_operand;  /* unsigned */
+     unsigned long ext_operandsize;
+ } dwarf2_line_op;
+ /* Bytecode callback function prototypes */
+ static void dwarf2_spp_bc_destroy(void *contents);
+ static void dwarf2_spp_bc_print(const void *contents, FILE *f,
+                               int indent_level);
 -static yasm_bc_resolve_flags dwarf2_line_op_bc_resolve
 -    (yasm_bytecode *bc, int save, yasm_calc_bc_dist_func calc_bc_dist);
++static int dwarf2_spp_bc_calc_len
++    (yasm_bytecode *bc, yasm_bc_add_span_func add_span, void *add_span_data);
+ static int dwarf2_spp_bc_tobytes
+     (yasm_bytecode *bc, unsigned char **bufp, void *d,
+      yasm_output_value_func output_value,
+      /*@null@*/ yasm_output_reloc_func output_reloc);
+ static void dwarf2_line_op_bc_destroy(void *contents);
+ static void dwarf2_line_op_bc_print(const void *contents, FILE *f,
+                                   int indent_level);
 -    dwarf2_spp_bc_resolve,
++static int dwarf2_line_op_bc_calc_len
++    (yasm_bytecode *bc, yasm_bc_add_span_func add_span, void *add_span_data);
+ static int dwarf2_line_op_bc_tobytes
+     (yasm_bytecode *bc, unsigned char **bufp, void *d,
+      yasm_output_value_func output_value,
+      /*@null@*/ yasm_output_reloc_func output_reloc);
+ /* Bytecode callback structures */
+ static const yasm_bytecode_callback dwarf2_spp_bc_callback = {
+     dwarf2_spp_bc_destroy,
+     dwarf2_spp_bc_print,
+     yasm_bc_finalize_common,
 -    dwarf2_line_op_bc_resolve,
++    dwarf2_spp_bc_calc_len,
++    yasm_bc_expand_common,
+     dwarf2_spp_bc_tobytes,
+     0
+ };
+ static const yasm_bytecode_callback dwarf2_line_op_bc_callback = {
+     dwarf2_line_op_bc_destroy,
+     dwarf2_line_op_bc_print,
+     yasm_bc_finalize_common,
 -static yasm_bc_resolve_flags
 -dwarf2_spp_bc_resolve(yasm_bytecode *bc, int save,
 -                    yasm_calc_bc_dist_func calc_bc_dist)
++    dwarf2_line_op_bc_calc_len,
++    yasm_bc_expand_common,
+     dwarf2_line_op_bc_tobytes,
+     0
+ };
+ static size_t
+ dwarf2_dbgfmt_add_file(yasm_dbgfmt_dwarf2 *dbgfmt_dwarf2, size_t filenum,
+                      const char *pathname)
+ {
+     size_t dirlen;
+     const char *filename;
+     size_t i, dir;
+     /* Put the directory into the directory table */
+     dir = 0;
+     dirlen = yasm__splitpath(pathname, &filename);
+     if (dirlen > 0) {
+       /* Look to see if we already have that dir in the table */
+       for (dir=1; dir<dbgfmt_dwarf2->dirs_size+1; dir++) {
+           if (strncmp(dbgfmt_dwarf2->dirs[dir-1], pathname, dirlen) == 0
+               && dbgfmt_dwarf2->dirs[dir-1][dirlen] == '\0')
+               break;
+       }
+       if (dir >= dbgfmt_dwarf2->dirs_size+1) {
+           /* Not found in table, add to end, reallocing if necessary */
+           if (dir >= dbgfmt_dwarf2->dirs_allocated+1) {
+               dbgfmt_dwarf2->dirs_allocated = dir+32;
+               dbgfmt_dwarf2->dirs = yasm_xrealloc(dbgfmt_dwarf2->dirs,
+                   sizeof(char *)*dbgfmt_dwarf2->dirs_allocated);
+           }
+           dbgfmt_dwarf2->dirs[dir-1] = yasm__xstrndup(pathname, dirlen);
+           dbgfmt_dwarf2->dirs_size = dir;
+       }
+     }
+     /* Put the filename into the filename table */
+     if (filenum == 0) {
+       /* Look to see if we already have that filename in the table */
+       for (; filenum<dbgfmt_dwarf2->filenames_size; filenum++) {
+           if (!dbgfmt_dwarf2->filenames[filenum].filename ||
+               (dbgfmt_dwarf2->filenames[filenum].dir == dir
+                && strcmp(dbgfmt_dwarf2->filenames[filenum].filename,
+                          filename) == 0))
+               break;
+       }
+     } else
+       filenum--;      /* array index is 0-based */
+     /* Realloc table if necessary */
+     if (filenum >= dbgfmt_dwarf2->filenames_allocated) {
+       size_t old_allocated = dbgfmt_dwarf2->filenames_allocated;
+       dbgfmt_dwarf2->filenames_allocated = filenum+32;
+       dbgfmt_dwarf2->filenames = yasm_xrealloc(dbgfmt_dwarf2->filenames,
+           sizeof(dwarf2_filename)*dbgfmt_dwarf2->filenames_allocated);
+       for (i=old_allocated; i<dbgfmt_dwarf2->filenames_allocated; i++) {
+           dbgfmt_dwarf2->filenames[i].pathname = NULL;
+           dbgfmt_dwarf2->filenames[i].filename = NULL;
+           dbgfmt_dwarf2->filenames[i].dir = 0;
+       }
+     }
+     /* Actually save in table */
+     if (dbgfmt_dwarf2->filenames[filenum].pathname)
+       yasm_xfree(dbgfmt_dwarf2->filenames[filenum].pathname);
+     if (dbgfmt_dwarf2->filenames[filenum].filename)
+       yasm_xfree(dbgfmt_dwarf2->filenames[filenum].filename);
+     dbgfmt_dwarf2->filenames[filenum].pathname = yasm__xstrdup(pathname);
+     dbgfmt_dwarf2->filenames[filenum].filename = yasm__xstrdup(filename);
+     dbgfmt_dwarf2->filenames[filenum].dir = dir;
+     /* Update table size */
+     if (filenum >= dbgfmt_dwarf2->filenames_size)
+       dbgfmt_dwarf2->filenames_size = filenum + 1;
+     return filenum;
+ }
+ /* Create and add a new line opcode to a section, updating offset on insertion;
+  * no optimization necessary.
+  */
+ static yasm_bytecode *
+ dwarf2_dbgfmt_append_line_op(yasm_section *sect, dwarf_line_number_op opcode,
+                            /*@only@*/ /*@null@*/ yasm_intnum *operand)
+ {
+     dwarf2_line_op *line_op = yasm_xmalloc(sizeof(dwarf2_line_op));
+     yasm_bytecode *bc;
+     line_op->opcode = opcode;
+     line_op->operand = operand;
+     line_op->ext_opcode = 0;
+     line_op->ext_operand = NULL;
+     line_op->ext_operandsize = 0;
+     bc = yasm_bc_create_common(&dwarf2_line_op_bc_callback, line_op, 0);
+     bc->len = 1;
+     if (operand)
+       bc->len += yasm_intnum_size_leb128(operand,
+                                          opcode == DW_LNS_advance_line);
+     yasm_dwarf2__append_bc(sect, bc);
+     return bc;
+ }
+ /* Create and add a new extended line opcode to a section, updating offset on
+  * insertion; no optimization necessary.
+  */
+ static yasm_bytecode *
+ dwarf2_dbgfmt_append_line_ext_op(yasm_section *sect,
+                                dwarf_line_number_ext_op ext_opcode,
+                                unsigned long ext_operandsize,
+                                /*@null@*/ yasm_symrec *ext_operand)
+ {
+     dwarf2_line_op *line_op = yasm_xmalloc(sizeof(dwarf2_line_op));
+     yasm_bytecode *bc;
+     line_op->opcode = DW_LNS_extended_op;
+     line_op->operand = yasm_intnum_create_uint(ext_operandsize+1);
+     line_op->ext_opcode = ext_opcode;
+     line_op->ext_operand = ext_operand;
+     line_op->ext_operandsize = ext_operandsize;
+     bc = yasm_bc_create_common(&dwarf2_line_op_bc_callback, line_op, 0);
+     bc->len = 2 + yasm_intnum_size_leb128(line_op->operand, 0) +
+       ext_operandsize;
+     yasm_dwarf2__append_bc(sect, bc);
+     return bc;
+ }
+ static void
+ dwarf2_dbgfmt_finalize_locs(yasm_section *sect, dwarf2_section_data *dsd)
+ {
+     /*@dependent@*/ yasm_symrec *lastsym = NULL;
+     /*@null@*/ yasm_bytecode *bc;
+     /*@null@*/ dwarf2_loc *loc;
+     bc = yasm_section_bcs_first(sect);
+     STAILQ_FOREACH(loc, &dsd->locs, link) {
+       /* Find the first bytecode following this loc by looking at
+        * the virtual line numbers.  XXX: this assumes the source file
+        * order will be the same as the actual section order.  If we ever
+        * implement subsegs this will NOT necessarily be true and this logic
+        * will need to be fixed to handle it!
+        *
+        * Keep track of last symbol seen prior to the loc.
+        */
+       while (bc && bc->line <= loc->vline) {
+           if (bc->symrecs) {
+               int i = 0;
+               while (bc->symrecs[i]) {
+                   lastsym = bc->symrecs[i];
+                   i++;
+               }
+           }
+           bc = yasm_bc__next(bc);
+       }
+       loc->sym = lastsym;
+       loc->bc = bc;
+     }
+ }
+ static int
+ dwarf2_dbgfmt_gen_line_op(yasm_section *debug_line, dwarf2_line_state *state,
+                         const dwarf2_loc *loc,
+                         /*@null@*/ const dwarf2_loc *nextloc)
+ {
+     unsigned long addr_delta;
+     long line_delta;
+     int opcode1, opcode2;
+     yasm_dbgfmt_dwarf2 *dbgfmt_dwarf2 = state->dbgfmt_dwarf2;
+     if (state->file != loc->file) {
+       state->file = loc->file;
+       dwarf2_dbgfmt_append_line_op(debug_line, DW_LNS_set_file,
+                                    yasm_intnum_create_uint(state->file));
+     }
+     if (state->column != loc->column) {
+       state->column = loc->column;
+       dwarf2_dbgfmt_append_line_op(debug_line, DW_LNS_set_column,
+                                    yasm_intnum_create_uint(state->column));
+     }
+ #ifdef WITH_DWARF3
+     if (loc->isa_change) {
+       state->isa = loc->isa;
+       dwarf2_dbgfmt_append_line_op(debug_line, DW_LNS_set_isa,
+                                    yasm_intnum_create_uint(state->isa));
+     }
+ #endif
+     if (state->is_stmt == 0 && loc->is_stmt == IS_STMT_SET) {
+       state->is_stmt = 1;
+       dwarf2_dbgfmt_append_line_op(debug_line, DW_LNS_negate_stmt, NULL);
+     } else if (state->is_stmt == 1 && loc->is_stmt == IS_STMT_CLEAR) {
+       state->is_stmt = 0;
+       dwarf2_dbgfmt_append_line_op(debug_line, DW_LNS_negate_stmt, NULL);
+     }
+     if (loc->basic_block) {
+       dwarf2_dbgfmt_append_line_op(debug_line, DW_LNS_set_basic_block, NULL);
+     }
+ #ifdef WITH_DWARF3
+     if (loc->prologue_end) {
+       dwarf2_dbgfmt_append_line_op(debug_line, DW_LNS_set_prologue_end, NULL);
+     }
+     if (loc->epilogue_begin) {
+       dwarf2_dbgfmt_append_line_op(debug_line, DW_LNS_set_epilogue_begin,
+                                    NULL);
+     }
+ #endif
+     /* If multiple loc for the same location, use last */
+     if (nextloc && nextloc->bc->offset == loc->bc->offset)
+       return 0;
+     if (!state->precbc) {
+       /* Set the starting address for the section */
+       if (!loc->sym) {
+           /* shouldn't happen! */
+           yasm_error_set(YASM_ERROR_GENERAL,
+                          N_("could not find label prior to loc"));
+           return 1;
+       }
+       dwarf2_dbgfmt_append_line_ext_op(debug_line, DW_LNE_set_address,
+           dbgfmt_dwarf2->sizeof_address, loc->sym);
+       addr_delta = 0;
+     } else if (loc->bc) {
+       if (state->precbc->offset > loc->bc->offset)
+           yasm_internal_error(N_("dwarf2 address went backwards?"));
+       addr_delta = loc->bc->offset - state->precbc->offset;
+     } else
+       return 0;       /* ran out of bytecodes!  XXX: do something? */
+     /* Generate appropriate opcode(s).  Address can only increment,
+      * whereas line number can go backwards.
+      */
+     line_delta = loc->line - state->line;
+     state->line = loc->line;
+     /* First handle the line delta */
+     if (line_delta < DWARF2_LINE_BASE
+       || line_delta >= DWARF2_LINE_BASE+DWARF2_LINE_RANGE) {
+       /* Won't fit in special opcode, use (signed) line advance */
+       dwarf2_dbgfmt_append_line_op(debug_line, DW_LNS_advance_line,
+                                    yasm_intnum_create_int(line_delta));
+       line_delta = 0;
+     }
+     /* Next handle the address delta */
+     opcode1 = DWARF2_LINE_OPCODE_BASE + line_delta - DWARF2_LINE_BASE +
+       DWARF2_LINE_RANGE * (addr_delta / dbgfmt_dwarf2->min_insn_len);
+     opcode2 = DWARF2_LINE_OPCODE_BASE + line_delta - DWARF2_LINE_BASE +
+       DWARF2_LINE_RANGE * ((addr_delta - DWARF2_MAX_SPECIAL_ADDR_DELTA) /
+                            dbgfmt_dwarf2->min_insn_len);
+     if (line_delta == 0 && addr_delta == 0) {
+       /* Both line and addr deltas are 0: do DW_LNS_copy */
+       dwarf2_dbgfmt_append_line_op(debug_line, DW_LNS_copy, NULL);
+     } else if (addr_delta <= DWARF2_MAX_SPECIAL_ADDR_DELTA && opcode1 <= 255) {
+       /* Addr delta in range of special opcode */
+       dwarf2_dbgfmt_append_line_op(debug_line, opcode1, NULL);
+     } else if (addr_delta <= 2*DWARF2_MAX_SPECIAL_ADDR_DELTA
+              && opcode2 <= 255) {
+       /* Addr delta in range of const_add_pc + special */
+       dwarf2_dbgfmt_append_line_op(debug_line, DW_LNS_const_add_pc, NULL);
+       dwarf2_dbgfmt_append_line_op(debug_line, opcode2, NULL);
+     } else {
+       /* Need advance_pc */
+       dwarf2_dbgfmt_append_line_op(debug_line, DW_LNS_advance_pc,
+                                    yasm_intnum_create_uint(addr_delta));
+       /* Take care of any remaining line_delta and add entry to matrix */
+       if (line_delta == 0)
+           dwarf2_dbgfmt_append_line_op(debug_line, DW_LNS_copy, NULL);
+       else {
+           unsigned int opcode;
+           opcode = DWARF2_LINE_OPCODE_BASE + line_delta - DWARF2_LINE_BASE;
+           dwarf2_dbgfmt_append_line_op(debug_line, opcode, NULL);
+       }
+     }
+     state->precbc = loc->bc;
+     return 0;
+ }
+ typedef struct dwarf2_line_bc_info {
+     yasm_section *debug_line;
+     yasm_dbgfmt_dwarf2 *dbgfmt_dwarf2;
+     dwarf2_line_state *state;
+     dwarf2_loc loc;
+     size_t lastfile;
+ } dwarf2_line_bc_info;
+ static int
+ dwarf2_generate_line_bc(yasm_bytecode *bc, /*@null@*/ void *d)
+ {
+     dwarf2_line_bc_info *info = (dwarf2_line_bc_info *)d;
+     yasm_dbgfmt_dwarf2 *dbgfmt_dwarf2 = info->dbgfmt_dwarf2;
+     size_t i;
+     const char *filename;
+     /*@null@*/ yasm_bytecode *nextbc = yasm_bc__next(bc);
+     if (nextbc && bc->offset == nextbc->offset)
+       return 0;
+     info->loc.vline = bc->line;
+     info->loc.bc = bc;
+     /* Keep track of last symbol seen */
+     if (bc->symrecs) {
+       i = 0;
+       while (bc->symrecs[i]) {
+           info->loc.sym = bc->symrecs[i];
+           i++;
+       }
+     }
+     yasm_linemap_lookup(dbgfmt_dwarf2->linemap, bc->line, &filename,
+                       &info->loc.line);
+     /* Find file index; just linear search it unless it was the last used */
+     if (info->lastfile > 0
+       && strcmp(filename, dbgfmt_dwarf2->filenames[info->lastfile-1].pathname)
+          == 0)
+       info->loc.file = info->lastfile;
+     else {
+       for (i=0; i<dbgfmt_dwarf2->filenames_size; i++) {
+           if (strcmp(filename, dbgfmt_dwarf2->filenames[i].pathname) == 0)
+               break;
+       }
+       if (i >= dbgfmt_dwarf2->filenames_size)
+           yasm_internal_error(N_("could not find filename in table"));
+       info->loc.file = i+1;
+       info->lastfile = i+1;
+     }
+     if (dwarf2_dbgfmt_gen_line_op(info->debug_line, info->state, &info->loc,
+                                 NULL))
+       return 1;
+     return 0;
+ }
+ typedef struct dwarf2_line_info {
+     yasm_section *debug_line; /* section to which line number info goes */
+     yasm_dbgfmt_dwarf2 *dbgfmt_dwarf2;
+     yasm_errwarns *errwarns;
+     /* Generate based on bytecodes (1) or locs (0)?  Use bytecodes if we're
+      * generating line numbers for the actual assembly source file.
+      */
+     int asm_source;
+     /* number of sections line number info generated for */
+     size_t num_sections;
+     /* last section line number info generated for */
+     /*@null@*/ yasm_section *last_code;
+ } dwarf2_line_info;
+ static int
+ dwarf2_generate_line_section(yasm_section *sect, /*@null@*/ void *d)
+ {
+     dwarf2_line_info *info = (dwarf2_line_info *)d;
+     yasm_dbgfmt_dwarf2 *dbgfmt_dwarf2 = info->dbgfmt_dwarf2;
+     /*@null@*/ dwarf2_section_data *dsd;
+     /*@null@*/ yasm_bytecode *bc;
+     dwarf2_line_state state;
+     unsigned long addr_delta;
+     dsd = yasm_section_get_data(sect, &yasm_dwarf2__section_data_cb);
+     if (!dsd) {
+       if (info->asm_source && yasm_section_is_code(sect)) {
+           /* Create line data for asm code sections */
+           dsd = yasm_xmalloc(sizeof(dwarf2_section_data));
+           STAILQ_INIT(&dsd->locs);
+           yasm_section_add_data(sect, &yasm_dwarf2__section_data_cb, dsd);
+       } else
+           return 0;   /* no line data for this section */
+     }
+     info->num_sections++;
+     info->last_code = sect;
+     /* initialize state machine registers for each sequence */
+     state.dbgfmt_dwarf2 = dbgfmt_dwarf2;
+     state.address = 0;
+     state.file = 1;
+     state.line = 1;
+     state.column = 0;
+     state.isa = 0;
+     state.is_stmt = DWARF2_LINE_DEFAULT_IS_STMT;
+     state.precbc = NULL;
+     if (info->asm_source) {
+       dwarf2_line_bc_info bcinfo;
+       bcinfo.debug_line = info->debug_line;
+       bcinfo.dbgfmt_dwarf2 = dbgfmt_dwarf2;
+       bcinfo.state = &state;
+       bcinfo.lastfile = 0;
+       bcinfo.loc.isa_change = 0;
+       bcinfo.loc.column = 0;
+       bcinfo.loc.is_stmt = IS_STMT_NOCHANGE;
+       bcinfo.loc.basic_block = 0;
+       bcinfo.loc.prologue_end = 0;
+       bcinfo.loc.epilogue_begin = 0;
+       bcinfo.loc.sym = NULL;
+       /* bcs_traverse() skips first "dummy" bytecode, so look at it
+        * separately to determine the initial symrec.
+        */
+       bc = yasm_section_bcs_first(sect);
+       if (bc->symrecs) {
+           size_t i = 0;
+           while (bc->symrecs[i]) {
+               bcinfo.loc.sym = bc->symrecs[i];
+               i++;
+           }
+       }
+       yasm_section_bcs_traverse(sect, info->errwarns, &bcinfo,
+                                 dwarf2_generate_line_bc);
+     } else {
+       /*@null@*/ dwarf2_loc *loc;
+       dwarf2_dbgfmt_finalize_locs(sect, dsd);
+       STAILQ_FOREACH(loc, &dsd->locs, link) {
+           if (dwarf2_dbgfmt_gen_line_op(info->debug_line, &state, loc,
+                                         STAILQ_NEXT(loc, link)))
+               return 1;
+       }
+     }
+     /* End sequence: bring address to end of section, then output end
+      * sequence opcode.  Don't use a special opcode to do this as we don't
+      * want an extra entry in the line matrix.
+      */
+     if (!state.precbc)
+       state.precbc = yasm_section_bcs_first(sect);
+     bc = yasm_section_bcs_last(sect);
+     addr_delta = bc->offset + bc->len - state.precbc->offset;
+     if (addr_delta == DWARF2_MAX_SPECIAL_ADDR_DELTA)
+       dwarf2_dbgfmt_append_line_op(info->debug_line, DW_LNS_const_add_pc,
+                                    NULL);
+     else if (addr_delta > 0)
+       dwarf2_dbgfmt_append_line_op(info->debug_line, DW_LNS_advance_pc,
+                                    yasm_intnum_create_uint(addr_delta));
+     dwarf2_dbgfmt_append_line_ext_op(info->debug_line, DW_LNE_end_sequence, 0,
+                                    NULL);
+     return 0;
+ }
+ static int
+ dwarf2_generate_filename(const char *filename, void *d)
+ {
+     yasm_dbgfmt_dwarf2 *dbgfmt_dwarf2 = (yasm_dbgfmt_dwarf2 *)d;
+     dwarf2_dbgfmt_add_file(dbgfmt_dwarf2, 0, filename);
+     return 0;
+ }
+ yasm_section *
+ yasm_dwarf2__generate_line(yasm_dbgfmt_dwarf2 *dbgfmt_dwarf2,
+                          yasm_errwarns *errwarns, int asm_source,
+                          /*@out@*/ yasm_section **main_code,
+                          /*@out@*/ size_t *num_line_sections)
+ {
+     dwarf2_line_info info;
+     int new;
+     size_t i;
+     yasm_bytecode *last, *sppbc;
+     dwarf2_spp *spp;
+     dwarf2_head *head;
+     if (asm_source) {
+       /* Generate dirs and filenames based on linemap */
+       yasm_linemap_traverse_filenames(dbgfmt_dwarf2->linemap, dbgfmt_dwarf2,
+                                       dwarf2_generate_filename);
+     }
+     info.num_sections = 0;
+     info.last_code = NULL;
+     info.asm_source = asm_source;
+     info.dbgfmt_dwarf2 = dbgfmt_dwarf2;
+     info.debug_line = yasm_object_get_general(dbgfmt_dwarf2->object,
+                                             ".debug_line", 0, 1, 0, 0, &new,
+                                             0);
+     last = yasm_section_bcs_last(info.debug_line);
+     /* header */
+     head = yasm_dwarf2__add_head(dbgfmt_dwarf2, info.debug_line, NULL, 0, 0);
+     /* statement program prologue */
+     spp = yasm_xmalloc(sizeof(dwarf2_spp));
+     spp->dbgfmt_dwarf2 = dbgfmt_dwarf2;
+     sppbc = yasm_bc_create_common(&dwarf2_spp_bc_callback, spp, 0);
+     sppbc->len = dbgfmt_dwarf2->sizeof_offset + 5 +
+       NELEMS(line_opcode_num_operands);
+     /* directory list */
+     for (i=0; i<dbgfmt_dwarf2->dirs_size; i++)
+       sppbc->len += strlen(dbgfmt_dwarf2->dirs[i])+1;
+     sppbc->len++;
+     /* filename list */
+     for (i=0; i<dbgfmt_dwarf2->filenames_size; i++) {
+       if (!dbgfmt_dwarf2->filenames[i].filename) {
+           yasm_error_set(YASM_ERROR_GENERAL,
+                          N_("dwarf2 file number %d unassigned"), i+1);
+           yasm_errwarn_propagate(errwarns, 0);
+           continue;
+       }
+       sppbc->len += strlen(dbgfmt_dwarf2->filenames[i].filename) + 1 +
+           yasm_size_uleb128(dbgfmt_dwarf2->filenames[i].dir) + 2;
+     }
+     sppbc->len++;
+     yasm_dwarf2__append_bc(info.debug_line, sppbc);
+     /* statement program */
+     yasm_object_sections_traverse(dbgfmt_dwarf2->object, (void *)&info,
+                                 dwarf2_generate_line_section);
+     /* mark end of line information */
+     yasm_dwarf2__set_head_end(head, yasm_section_bcs_last(info.debug_line));
+     *num_line_sections = info.num_sections;
+     if (info.num_sections == 1)
+       *main_code = info.last_code;
+     else
+       *main_code = NULL;
+     return info.debug_line;
+ }
+ static void
+ dwarf2_spp_bc_destroy(void *contents)
+ {
+     yasm_xfree(contents);
+ }
+ static void
+ dwarf2_spp_bc_print(const void *contents, FILE *f, int indent_level)
+ {
+     /* TODO */
+ }
 -    yasm_internal_error(N_("tried to resolve a dwarf2 spp bytecode"));
++static int
++dwarf2_spp_bc_calc_len(yasm_bytecode *bc, yasm_bc_add_span_func add_span,
++                     void *add_span_data)
+ {
 -    return YASM_BC_RESOLVE_MIN_LEN;
++    yasm_internal_error(N_("tried to calc_len a dwarf2 spp bytecode"));
+     /*@notreached@*/
 -static yasm_bc_resolve_flags
 -dwarf2_line_op_bc_resolve(yasm_bytecode *bc, int save,
 -                        yasm_calc_bc_dist_func calc_bc_dist)
++    return 0;
+ }
+ static int
+ dwarf2_spp_bc_tobytes(yasm_bytecode *bc, unsigned char **bufp, void *d,
+                     yasm_output_value_func output_value,
+                     yasm_output_reloc_func output_reloc)
+ {
+     dwarf2_spp *spp = (dwarf2_spp *)bc->contents;
+     yasm_dbgfmt_dwarf2 *dbgfmt_dwarf2 = spp->dbgfmt_dwarf2;
+     unsigned char *buf = *bufp;
+     yasm_intnum *cval;
+     size_t i, len;
+     /* Prologue length (following this field) */
+     cval = yasm_intnum_create_uint(bc->len - (buf-*bufp) -
+                                  dbgfmt_dwarf2->sizeof_offset);
+     yasm_arch_intnum_tobytes(dbgfmt_dwarf2->arch, cval, buf,
+                            dbgfmt_dwarf2->sizeof_offset,
+                            dbgfmt_dwarf2->sizeof_offset*8, 0, bc, 0);
+     buf += dbgfmt_dwarf2->sizeof_offset;
+     YASM_WRITE_8(buf, dbgfmt_dwarf2->min_insn_len);   /* minimum_instr_len */
+     YASM_WRITE_8(buf, DWARF2_LINE_DEFAULT_IS_STMT);   /* default_is_stmt */
+     YASM_WRITE_8(buf, DWARF2_LINE_BASE);              /* line_base */
+     YASM_WRITE_8(buf, DWARF2_LINE_RANGE);             /* line_range */
+     YASM_WRITE_8(buf, DWARF2_LINE_OPCODE_BASE);               /* opcode_base */
+     /* Standard opcode # operands array */
+     for (i=0; i<NELEMS(line_opcode_num_operands); i++)
+       YASM_WRITE_8(buf, line_opcode_num_operands[i]);
+     /* directory list */
+     for (i=0; i<dbgfmt_dwarf2->dirs_size; i++) {
+       len = strlen(dbgfmt_dwarf2->dirs[i])+1;
+       memcpy(buf, dbgfmt_dwarf2->dirs[i], len);
+       buf += len;
+     }
+     /* finish with single 0 byte */
+     YASM_WRITE_8(buf, 0);
+     /* filename list */
+     for (i=0; i<dbgfmt_dwarf2->filenames_size; i++) {
+       len = strlen(dbgfmt_dwarf2->filenames[i].filename)+1;
+       memcpy(buf, dbgfmt_dwarf2->filenames[i].filename, len);
+       buf += len;
+       /* dir */
+       buf += yasm_get_uleb128(dbgfmt_dwarf2->filenames[i].dir, buf);
+       YASM_WRITE_8(buf, 0);   /* time */
+       YASM_WRITE_8(buf, 0);   /* length */
+     }
+     /* finish with single 0 byte */
+     YASM_WRITE_8(buf, 0);
+     *bufp = buf;
+     yasm_intnum_destroy(cval);
+     return 0;
+ }
+ static void
+ dwarf2_line_op_bc_destroy(void *contents)
+ {
+     dwarf2_line_op *line_op = (dwarf2_line_op *)contents;
+     if (line_op->operand)
+       yasm_intnum_destroy(line_op->operand);
+     yasm_xfree(contents);
+ }
+ static void
+ dwarf2_line_op_bc_print(const void *contents, FILE *f, int indent_level)
+ {
+     /* TODO */
+ }
 -    yasm_internal_error(N_("tried to resolve a dwarf2 line_op bytecode"));
++static int
++dwarf2_line_op_bc_calc_len(yasm_bytecode *bc, yasm_bc_add_span_func add_span,
++                         void *add_span_data)
+ {
 -    return YASM_BC_RESOLVE_MIN_LEN;
++    yasm_internal_error(N_("tried to calc_len a dwarf2 line_op bytecode"));
+     /*@notreached@*/
++    return 0;
+ }
+ static int
+ dwarf2_line_op_bc_tobytes(yasm_bytecode *bc, unsigned char **bufp, void *d,
+                         yasm_output_value_func output_value,
+                         yasm_output_reloc_func output_reloc)
+ {
+     dwarf2_line_op *line_op = (dwarf2_line_op *)bc->contents;
+     unsigned char *buf = *bufp;
+     YASM_WRITE_8(buf, line_op->opcode);
+     if (line_op->operand)
+       buf += yasm_intnum_get_leb128(line_op->operand, buf,
+                                     line_op->opcode == DW_LNS_advance_line);
+     if (line_op->ext_opcode > 0) {
+       YASM_WRITE_8(buf, line_op->ext_opcode);
+       if (line_op->ext_operand) {
+           yasm_value value;
+           yasm_value_init_sym(&value, line_op->ext_operand,
+                               line_op->ext_operandsize*8);
+           output_value(&value, buf, line_op->ext_operandsize,
+                        (unsigned long)(buf-*bufp), bc, 0, d);
+           buf += line_op->ext_operandsize;
+       }
+     }
+     *bufp = buf;
+     return 0;
+ }
+ int
+ yasm_dwarf2__line_directive(yasm_dbgfmt_dwarf2 *dbgfmt_dwarf2,
+                           const char *name, yasm_section *sect,
+                           yasm_valparamhead *valparams, unsigned long line)
+ {
+     if (yasm__strcasecmp(name, "loc") == 0) {
+       /*@dependent@*/ /*@null@*/ const yasm_intnum *intn;
+       dwarf2_section_data *dsd;
+       dwarf2_loc *loc = yasm_xmalloc(sizeof(dwarf2_loc));
+       /* File number (required) */
+       yasm_valparam *vp = yasm_vps_first(valparams);
+       if (!vp || !vp->param) {
+           yasm_error_set(YASM_ERROR_SYNTAX, N_("file number required"));
+           yasm_xfree(loc);
+           return 0;
+       }
+       intn = yasm_expr_get_intnum(&vp->param, NULL);
+       if (!intn) {
+           yasm_error_set(YASM_ERROR_NOT_CONSTANT,
+                          N_("file number is not a constant"));
+           yasm_xfree(loc);
+           return 0;
+       }
+       if (yasm_intnum_sign(intn) != 1) {
+           yasm_error_set(YASM_ERROR_VALUE,
+                          N_("file number less than one"));
+           yasm_xfree(loc);
+           return 0;
+       }
+       loc->file = yasm_intnum_get_uint(intn);
+       /* Line number (required) */
+       vp = yasm_vps_next(vp);
+       if (!vp || !vp->param) {
+           yasm_error_set(YASM_ERROR_SYNTAX, N_("line number required"));
+           yasm_xfree(loc);
+           return 0;
+       }
+       intn = yasm_expr_get_intnum(&vp->param, NULL);
+       if (!intn) {
+           yasm_error_set(YASM_ERROR_NOT_CONSTANT,
+                          N_("file number is not a constant"));
+           yasm_xfree(loc);
+           return 0;
+       }
+       loc->line = yasm_intnum_get_uint(intn);
+       /* Generate new section data if it doesn't already exist */
+       dsd = yasm_section_get_data(sect, &yasm_dwarf2__section_data_cb);
+       if (!dsd) {
+           dsd = yasm_xmalloc(sizeof(dwarf2_section_data));
+           STAILQ_INIT(&dsd->locs);
+           yasm_section_add_data(sect, &yasm_dwarf2__section_data_cb, dsd);
+       }
+       /* Defaults for optional settings */
+       loc->column = 0;
+       loc->isa_change = 0;
+       loc->isa = 0;
+       loc->is_stmt = IS_STMT_NOCHANGE;
+       loc->basic_block = 0;
+       loc->prologue_end = 0;
+       loc->epilogue_begin = 0;
+       /* Optional column number */
+       vp = yasm_vps_next(vp);
+       if (vp && vp->param) {
+           intn = yasm_expr_get_intnum(&vp->param, NULL);
+           if (!intn) {
+               yasm_error_set(YASM_ERROR_NOT_CONSTANT,
+                              N_("column number is not a constant"));
+               yasm_xfree(loc);
+               return 0;
+           }
+           loc->column = yasm_intnum_get_uint(intn);
+           vp = yasm_vps_next(vp);
+       }
+       /* Other options */
+       while (vp && vp->val) {
+           if (yasm__strcasecmp(vp->val, "basic_block") == 0)
+               loc->basic_block = 1;
+           else if (yasm__strcasecmp(vp->val, "prologue_end") == 0)
+               loc->prologue_end = 1;
+           else if (yasm__strcasecmp(vp->val, "epilogue_begin") == 0)
+               loc->epilogue_begin = 1;
+           else if (yasm__strcasecmp(vp->val, "is_stmt") == 0) {
+               if (!vp->param) {
+                   yasm_error_set(YASM_ERROR_SYNTAX,
+                                  N_("is_stmt requires value"));
+                   yasm_xfree(loc);
+                   return 0;
+               }
+               intn = yasm_expr_get_intnum(&vp->param, NULL);
+               if (!intn) {
+                   yasm_error_set(YASM_ERROR_NOT_CONSTANT,
+                                  N_("is_stmt value is not a constant"));
+                   yasm_xfree(loc);
+                   return 0;
+               }
+               if (yasm_intnum_is_zero(intn))
+                   loc->is_stmt = IS_STMT_SET;
+               else if (yasm_intnum_is_pos1(intn))
+                   loc->is_stmt = IS_STMT_CLEAR;
+               else {
+                   yasm_error_set(YASM_ERROR_VALUE,
+                                  N_("is_stmt value not 0 or 1"));
+                   yasm_xfree(loc);
+                   return 0;
+               }
+           } else if (yasm__strcasecmp(vp->val, "isa") == 0) {
+               if (!vp->param) {
+                   yasm_error_set(YASM_ERROR_SYNTAX, N_("isa requires value"));
+                   yasm_xfree(loc);
+                   return 0;
+               }
+               intn = yasm_expr_get_intnum(&vp->param, NULL);
+               if (!intn) {
+                   yasm_error_set(YASM_ERROR_NOT_CONSTANT,
+                                  N_("isa value is not a constant"));
+                   yasm_xfree(loc);
+                   return 0;
+               }
+               if (yasm_intnum_sign(intn) < 0) {
+                   yasm_error_set(YASM_ERROR_VALUE,
+                                  N_("isa value less than zero"));
+                   yasm_xfree(loc);
+                   return 0;
+               }
+               loc->isa_change = 1;
+               loc->isa = yasm_intnum_get_uint(intn);
+           } else
+               yasm_warn_set(YASM_WARN_GENERAL,
+                             N_("unrecognized loc option `%s'"), vp->val);
+       }
+       /* Append new location */
+       loc->vline = line;
+       loc->bc = NULL;
+       loc->sym = NULL;
+       STAILQ_INSERT_TAIL(&dsd->locs, loc, link);
+       return 0;
+     } else if (yasm__strcasecmp(name, "file") == 0) {
+       /*@dependent@*/ /*@null@*/ const yasm_intnum *file_intn;
+       size_t filenum;
+       yasm_valparam *vp = yasm_vps_first(valparams);
+       if (vp->val) {
+           /* Just a bare filename */
+           yasm_object_set_source_fn(dbgfmt_dwarf2->object, vp->val);
+           return 0;
+       }
+       /* Otherwise.. first vp is the file number */
+       file_intn = yasm_expr_get_intnum(&vp->param, NULL);
+       if (!file_intn) {
+           yasm_error_set(YASM_ERROR_NOT_CONSTANT,
+                          N_("file number is not a constant"));
+           return 0;
+       }
+       filenum = (size_t)yasm_intnum_get_uint(file_intn);
+       vp = yasm_vps_next(vp);
+       if (!vp || !vp->val) {
+           yasm_error_set(YASM_ERROR_SYNTAX,
+                          N_("file number given but no filename"));
+           return 0;
+       }
+       dwarf2_dbgfmt_add_file(dbgfmt_dwarf2, filenum, vp->val);
+       return 0;
+     }
+     return 1;
+ }