]> granicus.if.org Git - yasm/commitdiff
Massive cleanup of relocation and WRT handling. Closes #49 and lays the
authorPeter Johnson <peter@tortall.net>
Sun, 19 Mar 2006 04:18:10 +0000 (04:18 -0000)
committerPeter Johnson <peter@tortall.net>
Sun, 19 Mar 2006 04:18:10 +0000 (04:18 -0000)
groundwork for further features and possible cleanups.

Note: this commit changes the way in which relocations in the
COFF/Win32/Win64 target can be forced to reference a different symbol than
is being pointed to; instead of the ambiguous "trap+(trap.end-trap)" to get
the reloc to point at trap.end but reference the trap symbol, after this
commit "trap.end wrt trap" is the way to say this.  This also reads a lot
more clearly and is not ambiguous.  This should really only affect people
who write .pdata sections for Win64.  See the
objfmts/win64/tests/win64-dataref.asm testcase for an example of usage.

This cleanup adds a new data structure, yasm_value, which is used for all
expressions that can be potentially relocatable.  This data structure
splits the absolute portion of the expression away from the relative
portion and any modifications to the relative portion (SEG, WRT,
PC-relative, etc).  A large amount of code in the new value module breaks
a general expression into its absolute and relative parts
(yasm_value_finalize_expr) and provides a common set of code for writing
out non-relocated values (yasm_value_output_basic).

All bytecode handling in both libyasm and the architecture modules was
rewritten to use yasm_values when appropriate (e.g. data values,
immediates, and effective addresses).  The yasm_output_expr_func is now
yasm_output_value_func and all users and implementors (mainly in object
formats) have been updated to handle yasm_values.

Simultaneously with this change, yasm_effaddr and yasm_immval full
structure definitions have been moved from bc-int.h to bytecode.h.
The data hiding provided by bc-int.h was relatively minimal and probably
overkill.  Also, great simplifications have been made to x86 effective
address expression handling.

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

40 files changed:
Mkfiles/Makefile.dj
Mkfiles/Makefile.flat
Mkfiles/vc/libyasm/libyasm.vcproj
Mkfiles/vc8/libyasm/libyasm.vcproj
libyasm.h
libyasm/Makefile.inc
libyasm/arch.h
libyasm/bc-int.h
libyasm/bytecode.c
libyasm/bytecode.h
libyasm/coretype.h
libyasm/expr.c
libyasm/expr.h
libyasm/tests/Makefile.inc
libyasm/tests/absloop-err.errwarn
libyasm/tests/value-err.asm [new file with mode: 0644]
libyasm/tests/value-err.errwarn [new file with mode: 0644]
libyasm/value.c [new file with mode: 0644]
libyasm/value.h [new file with mode: 0644]
modules/arch/lc3b/lc3barch.c
modules/arch/lc3b/lc3barch.h
modules/arch/lc3b/lc3bbc.c
modules/arch/lc3b/lc3bid.re
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/dwarf2/dwarf2-dbgfmt.c
modules/dbgfmts/dwarf2/dwarf2-dbgfmt.h
modules/dbgfmts/dwarf2/dwarf2-info.c
modules/dbgfmts/dwarf2/dwarf2-line.c
modules/dbgfmts/stabs/stabs-dbgfmt.c
modules/listfmts/nasm/nasm-listfmt.c
modules/objfmts/bin/bin-objfmt.c
modules/objfmts/bin/tests/reserve-err.errwarn
modules/objfmts/coff/coff-objfmt.c
modules/objfmts/elf/elf-objfmt.c
modules/objfmts/win64/tests/win64-dataref.asm
modules/objfmts/xdf/xdf-objfmt.c

index dc64559bffadad40a80281a2acb71fb64c0db466..ced5700a84747d158a8f5843ad36dfbbcce5766e 100644 (file)
@@ -22,6 +22,7 @@ LIBYASM_OBJS= \
  libyasm/bytecode.o \
  libyasm/errwarn.o \
  libyasm/expr.o \
+ libyasm/value.o \
  libyasm/file.o \
  libyasm/floatnum.o \
  libyasm/hamt.o \
index c17d00f11656eb71e46f71e47e23b0aef7e9f9ab..284f68a3005a06bb9431f50b2e2b25b1868956e0 100644 (file)
@@ -25,6 +25,7 @@ LIBYASM_OBJS= \
  libyasm/bytecode.o \
  libyasm/errwarn.o \
  libyasm/expr.o \
+ libyasm/value.o \
  libyasm/file.o \
  libyasm/floatnum.o \
  libyasm/hamt.o \
index d4f8a1a423837b89083b55f5599cf6a6bf212cc8..09f9da06ef58ad4e7d4c236dede2b37897bf3ccd 100644 (file)
                                                BasicRuntimeChecks="3"/>\r
                                </FileConfiguration>\r
                        </File>\r
+                       <File\r
+                               RelativePath="..\..\..\libyasm\value.c">\r
+                       </File>\r
                        <File\r
                                RelativePath="..\..\..\libyasm\xmalloc.c">\r
                                <FileConfiguration\r
                        <File\r
                                RelativePath="..\..\..\libyasm\valparam.h">\r
                        </File>\r
+                       <File\r
+                               RelativePath="..\..\..\libyasm\value.h">\r
+                       </File>\r
                </Filter>\r
        </Files>\r
        <Globals>\r
index 15b221be3e4dcec1dad0925337d2784c0c92b742..36e6450311b5351d99455ce7bee8e4dad37f2a99 100644 (file)
                                        />\r
                                </FileConfiguration>\r
                        </File>\r
+                       <File\r
+                               RelativePath="..\..\..\libyasm\value.c"\r
+                               >\r
+                       </File>\r
                        <File\r
                                RelativePath="..\..\..\libyasm\xmalloc.c"\r
                                >\r
                                RelativePath="..\..\..\libyasm\valparam.h"\r
                                >\r
                        </File>\r
+                       <File\r
+                               RelativePath="..\..\..\libyasm\value.h"\r
+                               >\r
+                       </File>\r
                </Filter>\r
        </Files>\r
        <Globals>\r
index e3c8cc320ebe0ea3ed80a0d75e0c7a615d07eef1..b35d5e5228e2675c2f716375291990787bc04a3b 100644 (file)
--- a/libyasm.h
+++ b/libyasm.h
@@ -60,6 +60,7 @@
 #include <libyasm/intnum.h>
 #include <libyasm/floatnum.h>
 #include <libyasm/expr.h>
+#include <libyasm/value.h>
 #include <libyasm/symrec.h>
 
 #include <libyasm/bytecode.h>
index 3dba3592554b697f83ad0af69793d73bff442964..23147a10137aef18335277dff69a8f48177898f6 100644 (file)
@@ -2,6 +2,7 @@
 
 libyasm_a_SOURCES += libyasm/bytecode.c
 libyasm_a_SOURCES += libyasm/expr.c
+libyasm_a_SOURCES += libyasm/value.c
 libyasm_a_SOURCES += libyasm/symrec.c
 libyasm_a_SOURCES += libyasm/file.c
 libyasm_a_SOURCES += libyasm/section.c
@@ -48,6 +49,7 @@ modinclude_HEADERS += libyasm/bc-int.h
 modinclude_HEADERS += libyasm/errwarn.h
 modinclude_HEADERS += libyasm/expr.h
 modinclude_HEADERS += libyasm/expr-int.h
+modinclude_HEADERS += libyasm/value.h
 modinclude_HEADERS += libyasm/symrec.h
 modinclude_HEADERS += libyasm/linemgr.h
 modinclude_HEADERS += libyasm/coretype.h
index 1afce594c6bf904ebbb28bc3a95e8b13f4ead368..e7846f58a5b60e1d06af3407013f4ea6a621c5cb 100644 (file)
@@ -184,13 +184,6 @@ typedef struct yasm_arch_module {
                             size_t valsize, size_t shift, int warn,
                             unsigned long line);
 
-    /** Module-level implementation of yasm_arch_intnum_fixup_rel().
-     * Call yasm_arch_intnum_fixup_rel() instead of calling this function.
-     */
-    int (*intnum_fixup_rel) (yasm_arch *arch, yasm_intnum *intn,
-                            size_t valsize, const yasm_bytecode *bc,
-                            unsigned long line);
-
     /** Module-level implementation of yasm_arch_intnum_tobytes().
      * Call yasm_arch_intnum_tobytes() instead of calling this function.
      */
@@ -463,19 +456,6 @@ int yasm_arch_floatnum_tobytes(yasm_arch *arch, const yasm_floatnum *flt,
                               size_t valsize, size_t shift, int warn,
                               unsigned long line);
 
-/** Adjust #yasm_intnum for relative displacement from bc.  Displacement
- * is modified in-place.
- * \param arch         architecture
- * \param intn         integer value
- * \param valsize      size (in bits)
- * \param bc           bytecode being output ("parent" of value)
- * \param line         virtual line; may be 0 if warn is 0
- * \return Nonzero on error.
- */
-int yasm_arch_intnum_fixup_rel(yasm_arch *arch, yasm_intnum *intn,
-                              size_t valsize, const yasm_bytecode *bc,
-                              unsigned long line);
-
 /** Output #yasm_intnum to buffer.  Puts the value into the least
  * significant bits of the destination, or may be shifted into more
  * significant bits by the shift parameter.  The destination bits are
@@ -588,9 +568,6 @@ yasm_effaddr *yasm_arch_ea_create(yasm_arch *arch, /*@keep@*/ yasm_expr *e);
                                   warn, line) \
     ((yasm_arch_base *)arch)->module->floatnum_tobytes \
        (arch, flt, buf, destsize, valsize, shift, warn, line)
-#define yasm_arch_intnum_fixup_rel(arch, intn, valsize, bc, line) \
-    ((yasm_arch_base *)arch)->module->intnum_fixup_rel \
-       (arch, intn, valsize, bc, line)
 #define yasm_arch_intnum_tobytes(arch, intn, buf, destsize, valsize, shift, \
                                 bc, warn, line) \
     ((yasm_arch_base *)arch)->module->intnum_tobytes \
index fbf8fced2b316dcccead49b2e9fdd915b8eeaa7e..ff0636b12dde4d873510b7eb8f9daef4ace137d3 100644 (file)
 #ifndef YASM_BC_INT_H
 #define YASM_BC_INT_H
 
-typedef struct yasm_effaddr_callback {
-    void (*destroy) (yasm_effaddr *ea);
-    void (*print) (const yasm_effaddr *ea, FILE *f, int indent_level);
-} yasm_effaddr_callback;
-
-struct yasm_effaddr {
-    const yasm_effaddr_callback *callback;     /* callback functions */
-
-    /*@only@*/ /*@null@*/ yasm_expr *disp;     /* address displacement */
-    unsigned long segreg;      /* segment register override (0 if none) */
-    unsigned char len;         /* length of disp (in bytes), 0 if unknown,
-                                * 0xff if unknown and required to be >0.
-                                */
-    unsigned char nosplit;     /* 1 if reg*2 should not be split into
-                                  reg+reg. (0 if not) */
-    unsigned char strong;      /* 1 if effective address is *definitely*
-                                * an effective address, e.g. in GAS if
-                                * expr(,1) form is used vs. just expr.
-                                */
-};
-
-struct yasm_immval {
-    /*@only@*/ /*@null@*/ yasm_expr *val;
-
-    unsigned char len;         /* final length (in bytes), 0 if unknown */
-    unsigned char sign;                /* 1 if final imm is treated as signed */
-};
-
 typedef struct yasm_bytecode_callback {
     void (*destroy) (/*@only@*/ void *contents);
     void (*print) (const void *contents, FILE *f, int indent_level);
@@ -62,7 +34,7 @@ typedef struct yasm_bytecode_callback {
     yasm_bc_resolve_flags (*resolve)
        (yasm_bytecode *bc, int save, yasm_calc_bc_dist_func calc_bc_dist);
     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);
 } yasm_bytecode_callback;
 
index dae30af871d07e54207e3d5c2ef15b619b8d749d..69893e2da61467ebcce686f6e86013ee49b6e5f4 100644 (file)
@@ -34,6 +34,8 @@
 #include "errwarn.h"
 #include "intnum.h"
 #include "expr.h"
+#include "value.h"
+#include "symrec.h"
 
 #include "bytecode.h"
 #include "arch.h"
 struct yasm_dataval {
     /*@reldef@*/ STAILQ_ENTRY(yasm_dataval) link;
 
-    enum { DV_EMPTY, DV_EXPR, DV_STRING } type;
+    enum { DV_EMPTY, DV_VALUE, DV_STRING } type;
 
     union {
-       /*@only@*/ yasm_expr *expn;
+       yasm_value val;
        struct {
            /*@only@*/ char *contents;
            size_t len;
@@ -83,7 +85,7 @@ typedef struct bytecode_leb128 {
 } bytecode_leb128;
 
 typedef struct bytecode_reserve {
-    /*@only@*/ yasm_expr *numitems; /* number of items to reserve */
+    /*@only@*/ /*@null@*/ yasm_expr *numitems; /* number of items to reserve */
     unsigned char itemsize;        /* size of each item (in bytes) */
 } bytecode_reserve;
 
@@ -134,10 +136,11 @@ typedef struct bytecode_insn {
 
 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);
 static yasm_bc_resolve_flags bc_data_resolve
     (yasm_bytecode *bc, int save, yasm_calc_bc_dist_func calc_bc_dist);
 static int bc_data_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);
 
 static void bc_leb128_destroy(void *contents);
@@ -146,23 +149,25 @@ static void bc_leb128_finalize(yasm_bytecode *bc, yasm_bytecode *prev_bc);
 static yasm_bc_resolve_flags bc_leb128_resolve
     (yasm_bytecode *bc, int save, yasm_calc_bc_dist_func calc_bc_dist);
 static int bc_leb128_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);
 
 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);
 static yasm_bc_resolve_flags bc_reserve_resolve
     (yasm_bytecode *bc, int save, yasm_calc_bc_dist_func calc_bc_dist);
 static int bc_reserve_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);
 
 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);
 static yasm_bc_resolve_flags bc_incbin_resolve
     (yasm_bytecode *bc, int save, yasm_calc_bc_dist_func calc_bc_dist);
 static int bc_incbin_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);
 
 static void bc_align_destroy(void *contents);
@@ -171,15 +176,16 @@ static void bc_align_finalize(yasm_bytecode *bc, yasm_bytecode *prev_bc);
 static yasm_bc_resolve_flags bc_align_resolve
     (yasm_bytecode *bc, int save, yasm_calc_bc_dist_func calc_bc_dist);
 static int bc_align_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);
 
 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);
 static yasm_bc_resolve_flags bc_org_resolve
     (yasm_bytecode *bc, int save, yasm_calc_bc_dist_func calc_bc_dist);
 static int bc_org_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);
 
 static void bc_insn_destroy(void *contents);
@@ -188,7 +194,7 @@ static void bc_insn_finalize(yasm_bytecode *bc, yasm_bytecode *prev_bc);
 static yasm_bc_resolve_flags bc_insn_resolve
     (yasm_bytecode *bc, int save, yasm_calc_bc_dist_func calc_bc_dist);
 static int bc_insn_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);
 
 /* Standard bytecode callback structures */
@@ -196,7 +202,7 @@ static int bc_insn_tobytes(yasm_bytecode *bc, unsigned char **bufp, void *d,
 static const yasm_bytecode_callback bc_data_callback = {
     bc_data_destroy,
     bc_data_print,
-    yasm_bc_finalize_common,
+    bc_data_finalize,
     bc_data_resolve,
     bc_data_tobytes
 };
@@ -212,7 +218,7 @@ static const yasm_bytecode_callback bc_leb128_callback = {
 static const yasm_bytecode_callback bc_reserve_callback = {
     bc_reserve_destroy,
     bc_reserve_print,
-    yasm_bc_finalize_common,
+    bc_reserve_finalize,
     bc_reserve_resolve,
     bc_reserve_tobytes
 };
@@ -220,7 +226,7 @@ static const yasm_bytecode_callback bc_reserve_callback = {
 static const yasm_bytecode_callback bc_incbin_callback = {
     bc_incbin_destroy,
     bc_incbin_print,
-    yasm_bc_finalize_common,
+    bc_incbin_finalize,
     bc_incbin_resolve,
     bc_incbin_tobytes
 };
@@ -236,7 +242,7 @@ static const yasm_bytecode_callback bc_align_callback = {
 static const yasm_bytecode_callback bc_org_callback = {
     bc_org_destroy,
     bc_org_print,
-    yasm_bc_finalize_common,
+    bc_org_finalize,
     bc_org_resolve,
     bc_org_tobytes
 };
@@ -255,19 +261,12 @@ unsigned char bytes_static[16];
 
 
 yasm_immval *
-yasm_imm_create_int(unsigned long int_val, unsigned long line)
-{
-    return yasm_imm_create_expr(
-       yasm_expr_create_ident(yasm_expr_int(yasm_intnum_create_uint(int_val)),
-                              line));
-}
-
-yasm_immval *
-yasm_imm_create_expr(yasm_expr *expr_ptr)
+yasm_imm_create_expr(yasm_expr *e)
 {
     yasm_immval *im = yasm_xmalloc(sizeof(yasm_immval));
 
-    im->val = expr_ptr;
+    if (yasm_value_finalize_expr(&im->val, e))
+       yasm__error(e->line, N_("immediate expression too complex"));
     im->len = 0;
     im->sign = 0;
 
@@ -275,9 +274,9 @@ yasm_imm_create_expr(yasm_expr *expr_ptr)
 }
 
 const yasm_expr *
-yasm_ea_get_disp(const yasm_effaddr *ptr)
+yasm_ea_get_disp(const yasm_effaddr *ea)
 {
-    return ptr->disp;
+    return ea->disp.abs;
 }
 
 void
@@ -290,7 +289,7 @@ yasm_ea_set_len(yasm_effaddr *ptr, unsigned int len)
      * an explicit override, where we expect the user knows what they're doing.
      */
 
-    ptr->len = (unsigned char)len;
+    ptr->disp_len = (unsigned char)len;
 }
 
 void
@@ -329,7 +328,7 @@ void
 yasm_ea_destroy(yasm_effaddr *ea)
 {
     ea->callback->destroy(ea);
-    yasm_expr_destroy(ea->disp);
+    yasm_value_delete(&ea->disp);
     yasm_xfree(ea);
 }
 /*@=nullstate@*/
@@ -338,9 +337,9 @@ yasm_ea_destroy(yasm_effaddr *ea)
 void
 yasm_ea_print(const yasm_effaddr *ea, FILE *f, int indent_level)
 {
-    fprintf(f, "%*sDisp=", indent_level, "");
-    yasm_expr_print(ea->disp, f);
-    fprintf(f, "\n%*sLen=%u\n", indent_level, "", (unsigned int)ea->len);
+    fprintf(f, "%*sDisp:\n", indent_level, "");
+    yasm_value_print(&ea->disp, f, indent_level+1);
+    fprintf(f, "%*sLen=%u\n", indent_level, "", (unsigned int)ea->disp_len);
     fprintf(f, "%*sNoSplit=%u\n", indent_level, "", (unsigned int)ea->nosplit);
     ea->callback->print(ea, f, indent_level);
 }
@@ -416,6 +415,21 @@ bc_data_print(const void *contents, FILE *f, int indent_level)
     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;
+
+    /* Convert values from simple expr to value. */
+    STAILQ_FOREACH(dv, &bc_data->datahead, link) {
+       if (dv->type == DV_VALUE) {
+           if (yasm_value_finalize(&dv->data.val))
+               yasm__error(bc->line, N_("expression too complex"));
+       }
+    }
+}
+
 static yasm_bc_resolve_flags
 bc_data_resolve(yasm_bytecode *bc, int save,
                yasm_calc_bc_dist_func calc_bc_dist)
@@ -429,7 +443,7 @@ bc_data_resolve(yasm_bytecode *bc, int save,
        switch (dv->type) {
            case DV_EMPTY:
                break;
-           case DV_EXPR:
+           case DV_VALUE:
                bc->len += bc_data->size;
                break;
            case DV_STRING:
@@ -448,7 +462,7 @@ bc_data_resolve(yasm_bytecode *bc, int save,
 
 static int
 bc_data_tobytes(yasm_bytecode *bc, unsigned char **bufp, void *d,
-               yasm_output_expr_func output_expr,
+               yasm_output_value_func output_value,
                /*@unused@*/ yasm_output_reloc_func output_reloc)
 {
     bytecode_data *bc_data = (bytecode_data *)bc->contents;
@@ -461,10 +475,10 @@ bc_data_tobytes(yasm_bytecode *bc, unsigned char **bufp, void *d,
        switch (dv->type) {
            case DV_EMPTY:
                break;
-           case DV_EXPR:
-               if (output_expr(&dv->data.expn, *bufp, bc_data->size,
-                               (size_t)(bc_data->size*8), 0,
-                               (unsigned long)(*bufp-bufp_orig), bc, 0, 1, d))
+           case DV_VALUE:
+               if (output_value(&dv->data.val, *bufp, bc_data->size,
+                                (size_t)(bc_data->size*8), 0,
+                                (unsigned long)(*bufp-bufp_orig), bc, 1, d))
                    return 1;
                *bufp += bc_data->size;
                break;
@@ -535,8 +549,8 @@ bc_leb128_finalize(yasm_bytecode *bc, yasm_bytecode *prev_bc)
        switch (dv->type) {
            case DV_EMPTY:
                break;
-           case DV_EXPR:
-               intn = yasm_expr_get_intnum(&dv->data.expn, NULL);
+           case DV_VALUE:
+               intn = yasm_expr_get_intnum(&dv->data.val.abs, NULL);
                if (!intn) {
                    yasm__error(bc->line,
                                N_("LEB128 requires constant values"));
@@ -571,7 +585,7 @@ bc_leb128_resolve(yasm_bytecode *bc, int save,
 
 static int
 bc_leb128_tobytes(yasm_bytecode *bc, unsigned char **bufp, void *d,
-                 yasm_output_expr_func output_expr,
+                 yasm_output_value_func output_value,
                  /*@unused@*/ yasm_output_reloc_func output_reloc)
 {
     bytecode_leb128 *bc_leb128 = (bytecode_leb128 *)bc->contents;
@@ -582,8 +596,8 @@ bc_leb128_tobytes(yasm_bytecode *bc, unsigned char **bufp, void *d,
        switch (dv->type) {
            case DV_EMPTY:
                break;
-           case DV_EXPR:
-               intn = yasm_expr_get_intnum(&dv->data.expn, NULL);
+           case DV_VALUE:
+               intn = yasm_expr_get_intnum(&dv->data.val.abs, NULL);
                if (!intn)
                    yasm_internal_error(N_("non-constant in leb128_tobytes"));
                *bufp += yasm_intnum_get_leb128(intn, *bufp, bc_leb128->sign);
@@ -626,6 +640,22 @@ bc_reserve_print(const void *contents, FILE *f, int 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))
+       yasm__error(bc->line, N_("expression too complex"));
+    else if (val.rel)
+       yasm__error(bc->line, N_("reserve expression not absolute"));
+    else if (val.abs && yasm_expr__contains(val.abs, YASM_EXPR_FLOAT))
+       yasm__error(bc->line,
+                   N_("expression must not contain floating point value"));
+    reserve->numitems = val.abs;
+}
+
 static yasm_bc_resolve_flags
 bc_reserve_resolve(yasm_bytecode *bc, int save,
                   yasm_calc_bc_dist_func calc_bc_dist)
@@ -636,6 +666,9 @@ bc_reserve_resolve(yasm_bytecode *bc, int save,
     yasm_expr **tempp;
     /*@dependent@*/ /*@null@*/ const yasm_intnum *num;
 
+    if (!reserve->numitems)
+       return YASM_BC_RESOLVE_MIN_LEN;
+
     if (save) {
        temp = NULL;
        tempp = &reserve->numitems;
@@ -649,12 +682,8 @@ bc_reserve_resolve(yasm_bytecode *bc, int save,
        /* For reserve, just say non-constant quantity instead of allowing
         * the circular reference error to filter through.
         */
-       if (temp && yasm_expr__contains(temp, YASM_EXPR_FLOAT))
-           yasm__error(bc->line,
-               N_("expression must not contain floating point value"));
-       else
-           yasm__error(bc->line,
-               N_("attempt to reserve non-constant quantity of space"));
+       yasm__error(bc->line,
+                   N_("attempt to reserve non-constant quantity of space"));
        retval = YASM_BC_RESOLVE_ERROR | YASM_BC_RESOLVE_UNKNOWN_LEN;
     } else
        bc->len += yasm_intnum_get_uint(num)*reserve->itemsize;
@@ -664,7 +693,7 @@ bc_reserve_resolve(yasm_bytecode *bc, int save,
 
 static int
 bc_reserve_tobytes(yasm_bytecode *bc, unsigned char **bufp, void *d,
-                  yasm_output_expr_func output_expr,
+                  yasm_output_value_func output_value,
                   /*@unused@*/ yasm_output_reloc_func output_reloc)
 {
     yasm_internal_error(N_("bc_reserve_tobytes called"));
@@ -716,6 +745,25 @@ bc_incbin_print(const void *contents, FILE *f, int indent_level)
     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))
+       yasm__error(bc->line, N_("start expression too complex"));
+    else if (val.rel)
+       yasm__error(bc->line, N_("start expression not absolute"));
+    incbin->start = val.abs;
+
+    if (yasm_value_finalize_expr(&val, incbin->maxlen))
+       yasm__error(bc->line, N_("maximum length expression too complex"));
+    else if (val.rel)
+       yasm__error(bc->line, N_("maximum length expression not absolute"));
+    incbin->maxlen = val.abs;
+}
+
 static yasm_bc_resolve_flags
 bc_incbin_resolve(yasm_bytecode *bc, int save,
                  yasm_calc_bc_dist_func calc_bc_dist)
@@ -799,7 +847,7 @@ bc_incbin_resolve(yasm_bytecode *bc, int save,
 
 static int
 bc_incbin_tobytes(yasm_bytecode *bc, unsigned char **bufp, void *d,
-                 yasm_output_expr_func output_expr,
+                 yasm_output_value_func output_value,
                  /*@unused@*/ yasm_output_reloc_func output_reloc)
 {
     bytecode_incbin *incbin = (bytecode_incbin *)bc->contents;
@@ -931,7 +979,7 @@ bc_align_resolve(yasm_bytecode *bc, int save,
 
 static int
 bc_align_tobytes(yasm_bytecode *bc, unsigned char **bufp, void *d,
-                yasm_output_expr_func output_expr,
+                yasm_output_value_func output_value,
                 /*@unused@*/ yasm_output_reloc_func output_reloc)
 {
     bytecode_align *align = (bytecode_align *)bc->contents;
@@ -1022,6 +1070,11 @@ bc_org_print(const void *contents, FILE *f, int indent_level)
     fprintf(f, "%*sStart=%lu\n", indent_level, "", org->start);
 }
 
+static void
+bc_org_finalize(yasm_bytecode *bc, yasm_bytecode *prev_bc)
+{
+}
+
 static yasm_bc_resolve_flags
 bc_org_resolve(yasm_bytecode *bc, int save,
               yasm_calc_bc_dist_func calc_bc_dist)
@@ -1041,7 +1094,7 @@ bc_org_resolve(yasm_bytecode *bc, int save,
 
 static int
 bc_org_tobytes(yasm_bytecode *bc, unsigned char **bufp, void *d,
-              yasm_output_expr_func output_expr,
+              yasm_output_value_func output_value,
               /*@unused@*/ yasm_output_reloc_func output_reloc)
 {
     bytecode_org *org = (bytecode_org *)bc->contents;
@@ -1095,6 +1148,7 @@ bc_insn_finalize(yasm_bytecode *bc, yasm_bytecode *prev_bc)
 {
     bytecode_insn *insn = (bytecode_insn *)bc->contents;
     int i;
+    int error = 0;
     yasm_insn_operand *op;
 
     /* Simplify the operands' expressions first. */
@@ -1105,15 +1159,28 @@ bc_insn_finalize(yasm_bytecode *bc, yasm_bytecode *prev_bc)
            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 identities.
+                * simplify reg*1 identities.
                 */
                if (op->data.ea)
-                   op->data.ea->disp =
-                       yasm_expr__level_tree(op->data.ea->disp, 1, 0, NULL,
-                                             NULL, NULL, NULL);
+                   op->data.ea->disp.abs =
+                       yasm_expr__level_tree(op->data.ea->disp.abs, 1, 1, 0,
+                                             NULL, NULL, NULL, NULL, &error);
+               if (error) {
+                   /* Follow up error with a pointer to where it was used */
+                   yasm__error(bc->line, N_("(used in memory expression)"));
+                   return;
+               }
                break;
            case YASM_INSN__OPERAND_IMM:
-               op->data.val = yasm_expr_simplify(op->data.val, NULL);
+               op->data.val =
+                   yasm_expr__level_tree(op->data.val, 1, 1, 1, NULL, NULL,
+                                         NULL, NULL, &error);
+               if (error) {
+                   /* Follow up error with a pointer to where it was used */
+                   yasm__error(bc->line,
+                               N_("(used in immediate expression)"));
+                   return;
+               }
                break;
            default:
                break;
@@ -1137,7 +1204,7 @@ bc_insn_resolve(yasm_bytecode *bc, int save,
 
 static int
 bc_insn_tobytes(yasm_bytecode *bc, unsigned char **bufp, void *d,
-               yasm_output_expr_func output_expr,
+               yasm_output_value_func output_value,
                /*@unused@*/ yasm_output_reloc_func output_reloc)
 {
     yasm_internal_error(N_("bc_insn_tobytes() is not implemented"));
@@ -1286,36 +1353,34 @@ yasm_bc_finalize(yasm_bytecode *bc, yasm_bytecode *prev_bc)
 {
     if (bc->callback)
        bc->callback->finalize(bc, prev_bc);
+    if (bc->multiple) {
+       yasm_value val;
+
+       if (yasm_value_finalize_expr(&val, bc->multiple))
+           yasm__error(bc->line, N_("multiple expression too complex"));
+       else if (val.rel)
+           yasm__error(bc->line, N_("multiple expression not absolute"));
+       bc->multiple = val.abs;
+    }
 }
 
 /*@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, precbc1->line);
+       return intn;
     }
+    dist -= precbc1->offset + precbc1->len;
+    return yasm_intnum_create_uint(dist);
 }
 
 yasm_bc_resolve_flags
@@ -1371,7 +1436,7 @@ yasm_bc_resolve(yasm_bytecode *bc, int save,
 /*@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,
+               void *d, yasm_output_value_func output_value,
                /*@null@*/ yasm_output_reloc_func output_reloc)
     /*@sets *buf@*/
 {
@@ -1423,7 +1488,7 @@ yasm_bc_tobytes(yasm_bytecode *bc, unsigned char *buf, unsigned long *bufsize,
     if (!bc->callback)
        yasm_internal_error(N_("got empty bytecode in bc_tobytes"));
     else
-       error = bc->callback->tobytes(bc, &destbuf, d, output_expr,
+       error = bc->callback->tobytes(bc, &destbuf, d, output_value,
                                      output_reloc);
 
     if (!error && ((unsigned long)(destbuf - origbuf) != datasize))
@@ -1433,12 +1498,12 @@ yasm_bc_tobytes(yasm_bytecode *bc, unsigned char *buf, unsigned long *bufsize,
 }
 
 yasm_dataval *
-yasm_dv_create_expr(yasm_expr *expn)
+yasm_dv_create_expr(yasm_expr *e)
 {
     yasm_dataval *retval = yasm_xmalloc(sizeof(yasm_dataval));
 
-    retval->type = DV_EXPR;
-    retval->data.expn = expn;
+    retval->type = DV_VALUE;
+    yasm_value_initialize(&retval->data.val, e);
 
     return retval;
 }
@@ -1464,8 +1529,8 @@ yasm_dvs_destroy(yasm_datavalhead *headp)
     while (cur) {
        next = STAILQ_NEXT(cur, link);
        switch (cur->type) {
-           case DV_EXPR:
-               yasm_expr_destroy(cur->data.expn);
+           case DV_VALUE:
+               yasm_value_delete(&cur->data.val);
                break;
            case DV_STRING:
                yasm_xfree(cur->data.str.contents);
@@ -1499,10 +1564,9 @@ yasm_dvs_print(const yasm_datavalhead *head, FILE *f, int indent_level)
            case DV_EMPTY:
                fprintf(f, "%*sEmpty\n", indent_level, "");
                break;
-           case DV_EXPR:
-               fprintf(f, "%*sExpr=", indent_level, "");
-               yasm_expr_print(cur->data.expn, f);
-               fprintf(f, "\n");
+           case DV_VALUE:
+               fprintf(f, "%*sValue:\n", indent_level, "");
+               yasm_value_print(&cur->data.val, f, indent_level+1);
                break;
            case DV_STRING:
                fprintf(f, "%*sLength=%lu\n", indent_level, "",
index 7408d9bbc554ab0293eb6141e5d91aa81319c2c3..dd44ac0e24f3b9b6dee9ee6f6d83d6baa892fe4b 100644 (file)
 #ifndef YASM_BYTECODE_H
 #define YASM_BYTECODE_H
 
-/** An effective address (opaque type). */
+/** An effective address. */
 typedef struct yasm_effaddr yasm_effaddr;
-/** An immediate value (opaque type). */
-typedef struct yasm_immval yasm_immval;
+
+/** Callbacks for effective address implementations. */
+typedef struct yasm_effaddr_callback {
+    /** Destroy the effective address (freeing it).
+     * \param ea       effective address
+     */
+    void (*destroy) (/*@only@*/ yasm_effaddr *ea);
+
+    /** Print the effective address.
+     * \param ea               effective address
+     * \param f                        file to output to
+     * \param indent_level     indentation level
+     */
+    void (*print) (const yasm_effaddr *ea, FILE *f, int indent_level);
+} yasm_effaddr_callback;
+
+/** An effective address. */
+struct yasm_effaddr {
+    const yasm_effaddr_callback *callback;     /**< callback functions */
+
+    yasm_value disp;           /**< address displacement */
+
+    unsigned long segreg;      /**< segment register override (0 if none) */
+
+    unsigned char disp_len;    /**< length of disp (in bytes), 0 if unknown,
+                                *   0xff if unknown and required to be >0.
+                                */
+    unsigned char need_disp;   /**< 1 if a displacement should be present
+                                *   in the output.
+                                */
+    unsigned char nosplit;     /**< 1 if reg*2 should not be split into
+                                *   reg+reg. (0 if not)
+                                */
+    unsigned char strong;      /**< 1 if effective address is *definitely*
+                                *   an effective address, e.g. in GAS if
+                                *   expr(,1) form is used vs. just expr.
+                                */
+};
+
+/** An immediate value. */
+typedef struct yasm_immval {
+    yasm_value val;            /**< the immediate value itself */
+
+    unsigned char len;         /**< final length (in bytes), 0 if unknown */
+    unsigned char sign;                /**< 1 if final imm is treated as signed */
+} yasm_immval;
+
 /** A data value (opaque type). */
 typedef struct yasm_dataval yasm_dataval;
 /** A list of data values (opaque type). */
@@ -55,14 +100,6 @@ typedef enum {
     YASM_BC_RESOLVE_UNKNOWN_LEN = 1<<2 /**< Length indeterminate. */
 } yasm_bc_resolve_flags;
 
-/** 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);
-
 /** Create an immediate value from an expression.
  * \param e    expression (kept, do not free).
  * \return Newly allocated immediate value.
@@ -278,8 +315,8 @@ void yasm_bc_finalize(yasm_bytecode *bc, yasm_bytecode *prev_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.
@@ -310,8 +347,8 @@ yasm_bc_resolve_flags yasm_bc_resolve(yasm_bytecode *bc, int save,
  * \param gap          if nonzero, indicates the data does not really need to
  *                     exist in the object file; if nonzero, contents of buf
  *                     are undefined [output]
- * \param d            data to pass to each call to output_expr/output_reloc
- * \param output_expr  function to call to convert expressions into their byte
+ * \param d            data to pass to each call to output_value/output_reloc
+ * \param output_value function to call to convert values into their byte
  *                     representation
  * \param output_reloc function to call to output relocation entries
  *                     for a single sym
@@ -325,7 +362,7 @@ yasm_bc_resolve_flags yasm_bc_resolve(yasm_bytecode *bc, int save,
 /*@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,
+     yasm_output_value_func output_value,
      /*@null@*/ yasm_output_reloc_func output_reloc)
     /*@sets *buf@*/;
 
index 47c508f429243ea908d719010288499d8cb5a6b6..bb06ca9033dd2c09d6c0c47ec3849fbd3ba4e518 100644 (file)
@@ -96,6 +96,48 @@ typedef struct yasm_intnum yasm_intnum;
  */
 typedef struct yasm_floatnum yasm_floatnum;
 
+/** A value.  May be absolute or relative.  Outside the parser, yasm_expr
+ * should only be used for absolute exprs.  Anything that could contain
+ * a relocatable value should use this structure instead.
+ * \see value.h for related functions.
+ */
+typedef struct yasm_value {
+    /** The absolute portion of the value.  May contain *differences* between
+     * symrecs but not standalone symrecs.  May be NULL if there is no
+     * absolute portion (e.g. the absolute portion is 0).
+     */
+    /*@null@*/ /*@only@*/ yasm_expr *abs;
+
+    /** The relative portion of the value.  This is the portion that may
+     * need to generate a relocation.  May be NULL if no relative portion.
+     */
+    /*@null@*/ /*@dependent@*/ yasm_symrec *rel;
+
+    /** What the relative portion is in reference to.  NULL if the default. */
+    /*@null@*/ /*@dependent@*/ yasm_symrec *wrt;
+
+    /** If the segment of the relative portion should be used, not the
+     * relative portion itself.  Boolean.
+     */
+    unsigned int seg_of : 1;
+
+    /** If the relative portion of the value should be shifted right
+     * (supported only by a few object formats).  If just the absolute portion
+     * should be shifted, that must be in the abs expr, not here!
+     */
+    unsigned int rshift : 7;
+
+    /** Indicates the relative portion of the value should be relocated
+     * relative to the current assembly position rather than relative to the
+     * section start.  "Current assembly position" here refers to the starting
+     * address of the bytecode containing this value.  Boolean.
+     */
+    unsigned int curpos_rel : 1;
+} yasm_value;
+
+/** Maximum value of #yasm_value.rshift */
+#define YASM_VALUE_RSHIFT_MAX  127
+
 /** Line number mapping repository (opaque type).  \see linemgr.h for related
  * functions.
  */
@@ -168,25 +210,24 @@ typedef enum {
  * \return Distance in bytes between the two bytecodes (bc2-bc1), or NULL if
  *        the distance was indeterminate.
  */
-typedef /*@null@*/ yasm_intnum * (*yasm_calc_bc_dist_func)
+typedef /*@null@*/ /*@only@*/ yasm_intnum * (*yasm_calc_bc_dist_func)
     (yasm_bytecode *precbc1, yasm_bytecode *precbc2);
 
-/** Convert yasm_expr to its byte representation.  Usually implemented by
+/** Convert yasm_value to its byte representation.  Usually implemented by
  * object formats to keep track of relocations and verify legal expressions.
  * Must put the value into the least significant bits of the destination,
  * unless shifted into more significant bits by the shift parameter.  The
  * destination bits must be cleared before being set.
- * \param ep           (double) pointer to expression
+ * \param value                value
  * \param buf          buffer for byte representation
  * \param destsize     destination size (in bytes)
  * \param valsize      size (in bits)
  * \param shift                left shift (in bits); may be negative to specify right
  *                     shift (standard warnings include truncation to boundary)
  * \param offset       offset (in bytes) of the expr contents from the start
- *                     of the bytecode (sometimes needed for conditional jumps)
+ *                     of the bytecode (needed for relative)
  * \param bc           current bytecode (usually passed into higher-level
  *                     calling function)
- * \param rel          if nonzero, expr should be treated as PC/IP-relative
  * \param warn         enables standard warnings: zero for none;
  *                     nonzero for overflow/underflow floating point warnings;
  *                     negative for signed integer warnings,
@@ -195,10 +236,10 @@ typedef /*@null@*/ yasm_intnum * (*yasm_calc_bc_dist_func)
  *                     function)
  * \return Nonzero if an error occurred, 0 otherwise.
  */
-typedef int (*yasm_output_expr_func)
-    (yasm_expr **ep, /*@out@*/ unsigned char *buf, size_t destsize,
+typedef int (*yasm_output_value_func)
+    (yasm_value *value, /*@out@*/ unsigned char *buf, size_t destsize,
      size_t valsize, int shift, unsigned long offset, yasm_bytecode *bc,
-     int rel, int warn, /*@null@*/ void *d) /*@uses *ep@*/;
+     int warn, /*@null@*/ void *d) /*@uses *ep@*/;
 
 /** Convert a symbol reference to its byte representation.  Usually implemented
  * by object formats and debug formats to keep track of relocations generated
index f207b1fe03e7f102905c754a5a7403b88deb0637..2037c5650396cbb39d1093fd0f673060277df915 100644 (file)
@@ -410,28 +410,40 @@ expr_can_destroy_int_right(yasm_expr_op op, yasm_intnum *intn)
  * NOTE: Really designed to only be used by expr_level_op().
  */
 static int
-expr_simplify_identity(yasm_expr *e, int numterms, int int_term)
+expr_simplify_identity(yasm_expr *e, int numterms, int int_term,
+                      int simplify_reg_mul)
 {
     int i;
+    int save_numterms;
 
-    /* Check for simple identities that delete the intnum.
-     * Don't delete if the intnum is the only thing in the expn.
+    /* Don't do this step if it's 1*REG.  Save and restore numterms so
+     * yasm_expr__contains() works correctly.
      */
-    if ((int_term == 0 && numterms > 1 &&
-        expr_can_destroy_int_left(e->op, e->terms[0].data.intn)) ||
-       (int_term > 0 &&
-        expr_can_destroy_int_right(e->op, e->terms[int_term].data.intn))) {
-       /* Delete the intnum */
-       yasm_intnum_destroy(e->terms[int_term].data.intn);
-
-       /* Slide everything to its right over by 1 */
-       if (int_term != numterms-1) /* if it wasn't last.. */
-           memmove(&e->terms[int_term], &e->terms[int_term+1],
-                   (numterms-1-int_term)*sizeof(yasm_expr__item));
-
-       /* Update numterms */
-       numterms--;
+    save_numterms = e->numterms;
+    e->numterms = numterms;
+    if (simplify_reg_mul || e->op != YASM_EXPR_MUL
+       || !yasm_intnum_is_pos1(e->terms[int_term].data.intn)
+       || !yasm_expr__contains(e, YASM_EXPR_REG)) {
+       /* Check for simple identities that delete the intnum.
+        * Don't delete if the intnum is the only thing in the expn.
+        */
+       if ((int_term == 0 && numterms > 1 &&
+            expr_can_destroy_int_left(e->op, e->terms[0].data.intn)) ||
+           (int_term > 0 &&
+            expr_can_destroy_int_right(e->op, e->terms[int_term].data.intn))) {
+           /* Delete the intnum */
+           yasm_intnum_destroy(e->terms[int_term].data.intn);
+
+           /* Slide everything to its right over by 1 */
+           if (int_term != numterms-1) /* if it wasn't last.. */
+               memmove(&e->terms[int_term], &e->terms[int_term+1],
+                       (numterms-1-int_term)*sizeof(yasm_expr__item));
+
+           /* Update numterms */
+           numterms--;
+       }
     }
+    e->numterms = save_numterms;
 
     /* Check for simple identites that delete everything BUT the intnum.
      * Don't bother if the intnum is the only thing in the expn.
@@ -490,7 +502,7 @@ expr_simplify_identity(yasm_expr *e, int numterms, int int_term)
 /*@-mustfree@*/
 static /*@only@*/ yasm_expr *
 expr_level_op(/*@returned@*/ /*@only@*/ yasm_expr *e, int fold_const,
-             int simplify_ident)
+             int simplify_ident, int simplify_reg_mul)
 {
     int i, j, o, fold_numterms, level_numterms, level_fold_numterms;
     int first_int_term = -1;
@@ -570,8 +582,9 @@ expr_level_op(/*@returned@*/ /*@only@*/ yasm_expr *e, int fold_const,
        if (simplify_ident) {
            int new_fold_numterms;
            /* Simplify identities and make IDENT if possible. */
-           new_fold_numterms = expr_simplify_identity(e, fold_numterms,
-                                                      first_int_term);
+           new_fold_numterms =
+               expr_simplify_identity(e, fold_numterms, first_int_term,
+                                      simplify_reg_mul);
            level_numterms -= fold_numterms-new_fold_numterms;
            fold_numterms = new_fold_numterms;
        }
@@ -660,7 +673,7 @@ expr_level_op(/*@returned@*/ /*@only@*/ yasm_expr *e, int fold_const,
     /* Simplify identities, make IDENT if possible, and save to e->numterms. */
     if (simplify_ident && first_int_term != -1) {
        e->numterms = expr_simplify_identity(e, level_numterms,
-                                            first_int_term);
+                                            first_int_term, simplify_reg_mul);
     } else {
        e->numterms = level_numterms;
        if (level_numterms == 1)
@@ -679,9 +692,10 @@ typedef struct yasm__exprentry {
 /* Level an entire expn tree, expanding equ's as we go */
 yasm_expr *
 yasm_expr__level_tree(yasm_expr *e, int fold_const, int simplify_ident,
-                     yasm_calc_bc_dist_func calc_bc_dist,
+                     int simplify_reg_mul, yasm_calc_bc_dist_func calc_bc_dist,
                      yasm_expr_xform_func expr_xform_extra,
-                     void *expr_xform_extra_data, yasm__exprhead *eh)
+                     void *expr_xform_extra_data, yasm__exprhead *eh,
+                     int *error)
 {
     int i;
     yasm__exprhead eh_local;
@@ -717,7 +731,9 @@ yasm_expr__level_tree(yasm_expr *e, int fold_const, int simplify_ident,
                SLIST_FOREACH(np, eh, next) {
                    if (np->e == equ_expr) {
                        yasm__error(e->line,
-                                   N_("circular reference detected."));
+                                   N_("circular reference detected"));
+                       if (error)
+                           *error = 1;
                        return e;
                    }
                }
@@ -737,7 +753,9 @@ yasm_expr__level_tree(yasm_expr *e, int fold_const, int simplify_ident,
                SLIST_FOREACH(np, eh, next) {
                    if (np->e == start) {
                        yasm__error(e->line,
-                                   N_("circular reference detected."));
+                                   N_("circular reference detected"));
+                       if (error)
+                           *error = 1;
                        return e;
                    }
                }
@@ -772,9 +790,9 @@ yasm_expr__level_tree(yasm_expr *e, int fold_const, int simplify_ident,
        if (e->terms[i].type == YASM_EXPR_EXPR)
            e->terms[i].data.expn =
                yasm_expr__level_tree(e->terms[i].data.expn, fold_const,
-                                     simplify_ident, calc_bc_dist,
-                                     expr_xform_extra, expr_xform_extra_data,
-                                     eh);
+                                     simplify_ident, simplify_reg_mul,
+                                     calc_bc_dist, expr_xform_extra,
+                                     expr_xform_extra_data, eh, error);
 
        if (ee.e) {
            SLIST_REMOVE_HEAD(eh, next);
@@ -783,14 +801,15 @@ yasm_expr__level_tree(yasm_expr *e, int fold_const, int simplify_ident,
     }
 
     /* do callback */
-    e = expr_level_op(e, fold_const, simplify_ident);
+    e = expr_level_op(e, fold_const, simplify_ident, simplify_reg_mul);
     if (calc_bc_dist || expr_xform_extra) {
        if (calc_bc_dist)
            e = expr_xform_bc_dist(e, calc_bc_dist);
        if (expr_xform_extra)
            e = expr_xform_extra(e, expr_xform_extra_data);
-       e = yasm_expr__level_tree(e, fold_const, simplify_ident, NULL, NULL,
-                                 NULL, NULL);
+       e = yasm_expr__level_tree(e, fold_const, simplify_ident,
+                                 simplify_reg_mul, NULL, NULL, NULL, NULL,
+                                 error);
     }
     return e;
 }
@@ -1018,76 +1037,6 @@ yasm_expr__traverse_leaves_in(yasm_expr *e, void *d,
     return 0;
 }
 
-yasm_symrec *
-yasm_expr_extract_symrec(yasm_expr **ep,
-                        yasm_symrec_relocate_action relocate_action,
-                        yasm_calc_bc_dist_func calc_bc_dist)
-{
-    yasm_symrec *sym = NULL;
-    int i, symterm = -1;
-
-    switch ((*ep)->op) {
-       case YASM_EXPR_IDENT:
-           /* Be kind, recurse */
-           if ((*ep)->terms[0].type == YASM_EXPR_EXPR)
-               return yasm_expr_extract_symrec(&((*ep)->terms[0].data.expn),
-                                               relocate_action, calc_bc_dist);
-           /* Replace sym with 0 value, return sym */
-           if ((*ep)->terms[0].type == YASM_EXPR_SYM ||
-               (*ep)->terms[0].type == YASM_EXPR_SYMEXP) {
-               sym = (*ep)->terms[0].data.sym;
-               symterm = 0;
-           }
-           break;
-       case YASM_EXPR_ADD:
-           /* Search for sym, if found, delete it from expr and return it */
-           for (i=0; i<(*ep)->numterms; i++) {
-               if ((*ep)->terms[i].type == YASM_EXPR_SYM ||
-                   (*ep)->terms[i].type == YASM_EXPR_SYMEXP) {
-                   sym = (*ep)->terms[i].data.sym;
-                   symterm = i;
-                   break;
-               }
-           }
-           break;
-       default:
-           break;
-    }
-    if (sym) {
-       /*@dependent@*/ /*@null@*/ yasm_bytecode *precbc;
-       /*@null@*/ yasm_intnum *intn;
-
-       if (yasm_symrec_get_label(sym, &precbc)
-           && (relocate_action == YASM_SYMREC_REPLACE_VALUE ||
-               (relocate_action == YASM_SYMREC_REPLACE_VALUE_IF_LOCAL
-                && yasm_symrec_get_visibility(sym) == YASM_SYM_LOCAL))) {
-           intn = calc_bc_dist(yasm_section_bcs_first(
-                                   yasm_bc_get_section(precbc)), precbc);
-           if (!intn)
-               return NULL;
-       } else
-           intn = yasm_intnum_create_uint(0);
-       (*ep)->terms[symterm].type = YASM_EXPR_INT;
-       (*ep)->terms[symterm].data.intn = intn;
-    }
-    return sym;
-}
-
-yasm_expr *
-yasm_expr_extract_seg(yasm_expr **ep)
-{
-    yasm_expr *e = *ep;
-
-    /* If not SEG, we can't do this transformation */
-    if (e->op != YASM_EXPR_SEG)
-       return NULL;
-
-    /* Remove the SEG by changing the expression into an IDENT */
-    e->op = YASM_EXPR_IDENT;
-
-    return e;
-}
-
 yasm_expr *
 yasm_expr_extract_segoff(yasm_expr **ep)
 {
@@ -1145,34 +1094,6 @@ yasm_expr_extract_wrt(yasm_expr **ep)
     return retval;
 }
 
-yasm_expr *
-yasm_expr_extract_shr(yasm_expr **ep)
-{
-    yasm_expr *retval;
-    yasm_expr *e = *ep;
-
-    /* If not SHR, we can't do this transformation */
-    if (e->op != YASM_EXPR_SHR)
-       return NULL;
-
-    /* Extract the right side portion out to its own expression */
-    if (e->terms[1].type == YASM_EXPR_EXPR)
-       retval = e->terms[1].data.expn;
-    else {
-       /* Need to build IDENT expression to hold non-expression contents */
-       retval = yasm_xmalloc(sizeof(yasm_expr));
-       retval->op = YASM_EXPR_IDENT;
-       retval->numterms = 1;
-       retval->terms[0] = e->terms[1]; /* structure copy */
-    }
-
-    /* Delete the right side portion by changing the expr into an IDENT */
-    e->op = YASM_EXPR_IDENT;
-    e->numterms = 1;
-
-    return retval;
-}
-
 /*@-unqualifiedtrans -nullderef -nullstate -onlytrans@*/
 yasm_intnum *
 yasm_expr_get_intnum(yasm_expr **ep, yasm_calc_bc_dist_func calc_bc_dist)
@@ -1186,20 +1107,6 @@ yasm_expr_get_intnum(yasm_expr **ep, yasm_calc_bc_dist_func calc_bc_dist)
 }
 /*@=unqualifiedtrans =nullderef -nullstate -onlytrans@*/
 
-/*@-unqualifiedtrans -nullderef -nullstate -onlytrans@*/
-const yasm_floatnum *
-yasm_expr_get_floatnum(yasm_expr **ep)
-{
-    *ep = yasm_expr_simplify(*ep, NULL);
-
-    if ((*ep)->op == YASM_EXPR_IDENT &&
-       (*ep)->terms[0].type == YASM_EXPR_FLOAT)
-       return (*ep)->terms[0].data.flt;
-    else
-       return (yasm_floatnum *)NULL;
-}
-/*@=unqualifiedtrans =nullderef -nullstate -onlytrans@*/
-
 /*@-unqualifiedtrans -nullderef -nullstate -onlytrans@*/
 const yasm_symrec *
 yasm_expr_get_symrec(yasm_expr **ep, int simplify)
index 87268d5108e084988c03967da3970dd9e4cf08ce..f21907a319760086822e38ec341dbbdf7a0078ce 100644 (file)
@@ -147,17 +147,22 @@ SLIST_HEAD(yasm__exprhead, yasm__exprentry);
  * \param e                expression
  * \param fold_const       enable constant folding if nonzero
  * \param simplify_ident    simplify identities
+ * \param simplify_reg_mul  simplify REG*1 identities
  * \param calc_bc_dist     bytecode distance-calculation function
  * \param expr_xform_extra  extra transformation function
  * \param expr_xform_extra_data        data to pass to expr_xform_extra
  * \param eh               call with NULL (for internal use in recursion)
+ * \param error                    if non-NULL, set to 1 if an error is encountered
+ *                         (e.g. circular reference errors)
  * \return Leveled expression.
  */
 /*@only@*/ /*@null@*/ yasm_expr *yasm_expr__level_tree
     (/*@returned@*/ /*@only@*/ /*@null@*/ yasm_expr *e, int fold_const,
-     int simplify_ident, /*@null@*/ yasm_calc_bc_dist_func calc_bc_dist,
+     int simplify_ident, int simplify_reg_mul,
+     /*@null@*/ yasm_calc_bc_dist_func calc_bc_dist,
      /*@null@*/ yasm_expr_xform_func expr_xform_extra,
-     /*@null@*/ void *expr_xform_extra_data, /*@null@*/ yasm__exprhead *eh);
+     /*@null@*/ void *expr_xform_extra_data, /*@null@*/ yasm__exprhead *eh,
+     /*@null@*/ int *error);
 
 /** Simplify an expression as much as possible.  Eliminates extraneous
  * branches and simplifies integer-only subexpressions.  Simplified version
@@ -167,39 +172,7 @@ SLIST_HEAD(yasm__exprhead, yasm__exprentry);
  * \return Simplified expression.
  */
 #define yasm_expr_simplify(e, cbd) \
-    yasm_expr__level_tree(e, 1, 1, cbd, NULL, NULL, NULL)
-
-/** Relocation actions for yasm_expr_extract_symrec(). */
-typedef enum yasm_symrec_relocate_action {
-    YASM_SYMREC_REPLACE_ZERO = 0,   /**< Replace the symbol with 0 */
-    YASM_SYMREC_REPLACE_VALUE,     /**< Replace with symbol's value (offset)
-                                    * if symbol is a label.
-                                    */
-    YASM_SYMREC_REPLACE_VALUE_IF_LOCAL /**< Replace with symbol's value only
-                                        * if symbol is label and declared
-                                        * local.
-                                        */
-} yasm_symrec_relocate_action;
-
-/** Extract a single symbol out of an expression.  Replaces it with 0, or
- * optionally the symbol's value (if it's a label).
- * \param ep               expression (pointer to)
- * \param relocate_action   replacement action to take on symbol in expr
- * \param calc_bc_dist     bytecode distance-calculation function
- * \return NULL if unable to extract a symbol (too complex of expr, none
- *         present, etc); otherwise returns the extracted symbol.
- */
-/*@dependent@*/ /*@null@*/ yasm_symrec *yasm_expr_extract_symrec
-    (yasm_expr **ep, yasm_symrec_relocate_action relocate_action,
-     yasm_calc_bc_dist_func calc_bc_dist);
-
-/** Remove the SEG unary operator if present, leaving the lower level
- * expression.
- * \param ep           expression (pointer to)
- * \return NULL if the expression does not have a top-level operator of SEG;
- * otherwise the modified input expression (without the SEG).
- */
-/*@only@*/ /*@null@*/ yasm_expr *yasm_expr_extract_seg(yasm_expr **ep);
+    yasm_expr__level_tree(e, 1, 1, 1, cbd, NULL, NULL, NULL, NULL)
 
 /** Extract the segment portion of a SEG:OFF expression, leaving the offset.
  * \param ep           expression (pointer to)
@@ -220,16 +193,6 @@ typedef enum yasm_symrec_relocate_action {
  */
 /*@only@*/ /*@null@*/ yasm_expr *yasm_expr_extract_wrt(yasm_expr **ep);
 
-/** Extract the right portion (y) of a x SHR y expression, leaving the left
- * portion (x).
- * \param ep           expression (pointer to)
- * \return NULL if unable to extract (YASM_EXPR_SHR not the top-level
- *         operator), otherwise the right side of the SHR expression.  The
- *         input expression is modified such that on return, it's the left side
- *         of the SHR expression.
- */
-/*@only@*/ /*@null@*/ yasm_expr *yasm_expr_extract_shr(yasm_expr **ep);
-
 /** Get the integer value of an expression if it's just an integer.
  * \param ep           expression (pointer to)
  * \param calc_bc_dist bytecode distance-calculation function
@@ -240,15 +203,6 @@ typedef enum yasm_symrec_relocate_action {
 /*@dependent@*/ /*@null@*/ yasm_intnum *yasm_expr_get_intnum
     (yasm_expr **ep, /*@null@*/ yasm_calc_bc_dist_func calc_bc_dist);
 
-/** Get the floating point value of an expression if it's just an floatnum.
- * \param ep           expression (pointer to)
- * \return NULL if the expression is too complex (contains anything other than
- *         floats, ie integers, non-valued labels, registers); otherwise the
- *         floatnum value of the expression.
- */
-/*@dependent@*/ /*@null@*/ const yasm_floatnum *yasm_expr_get_floatnum
-    (yasm_expr **ep);
-
 /** Get the symbol value of an expression if it's just a symbol.
  * \param ep           expression (pointer to)
  * \param simplify     if nonzero, simplify the expression first
index f14ec4d7336333d6ad07972d45a2e8ac9cb36aaa..4011fc9eb820d22986fed440932bd016ee649cea 100644 (file)
@@ -25,6 +25,8 @@ EXTRA_DIST += libyasm/tests/timesover-err.errwarn
 EXTRA_DIST += libyasm/tests/unary.asm
 EXTRA_DIST += libyasm/tests/unary.errwarn
 EXTRA_DIST += libyasm/tests/unary.hex
+EXTRA_DIST += libyasm/tests/value-err.asm
+EXTRA_DIST += libyasm/tests/value-err.errwarn
 
 check_PROGRAMS += bitvect_test
 check_PROGRAMS += floatnum_test
index df8172d3f5dbb55552f18f93d2530aa3713e11c8..6cda28a774ba5a02a54e71b30b160d16984483a8 100644 (file)
@@ -1 +1,2 @@
--:1: circular reference detected.
+-:1: circular reference detected
+-:6: (used in memory expression)
diff --git a/libyasm/tests/value-err.asm b/libyasm/tests/value-err.asm
new file mode 100644 (file)
index 0000000..883fa6f
--- /dev/null
@@ -0,0 +1,9 @@
+label:
+mov [label/2+1], ax
+mov ax, label*2
+mov [label+5], ax
+mov ax, label wrt foo
+foo:
+dd label
+dd label<<5
+dd label>>2
diff --git a/libyasm/tests/value-err.errwarn b/libyasm/tests/value-err.errwarn
new file mode 100644 (file)
index 0000000..ae659a9
--- /dev/null
@@ -0,0 +1,3 @@
+-:2: effective address too complex
+-:3: immediate expression too complex
+-:8: expression too complex
diff --git a/libyasm/value.c b/libyasm/value.c
new file mode 100644 (file)
index 0000000..8b39819
--- /dev/null
@@ -0,0 +1,500 @@
+/*
+ * Value handling
+ *
+ *  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.
+ */
+#define YASM_LIB_INTERNAL
+#include "util.h"
+/*@unused@*/ RCSID("$Id$");
+
+#include "coretype.h"
+#include "bitvect.h"
+
+#include "errwarn.h"
+#include "intnum.h"
+#include "floatnum.h"
+#include "expr.h"
+#include "value.h"
+#include "symrec.h"
+
+#include "bytecode.h"
+#include "section.h"
+
+#include "arch.h"
+
+#include "expr-int.h"
+#include "bc-int.h"
+
+static int
+value_finalize_scan(yasm_value *value, yasm_expr *e, int ssym_not_ok)
+{
+    int i;
+    /*@dependent@*/ yasm_section *sect;
+    /*@dependent@*/ /*@null@*/ yasm_bytecode *precbc;
+
+    unsigned long shamt;    /* for SHR */
+
+    /* Yes, this has a maximum upper bound on 32 terms, based on an
+     * "insane number of terms" (and ease of implementation) WAG.
+     * The right way to do this would be a stack-based alloca, but that's
+     * not ISO C.  We really don't want to malloc here as this function is
+     * hit a lot!
+     *
+     * This is a bitmask to keep things small, as this is a recursive
+     * routine and we don't want to eat up stack space.
+     */
+    unsigned long used;            /* for ADD */
+
+    /* Thanks to this running after a simplify, we don't need to iterate
+     * down through IDENTs or handle SUB.
+     *
+     * We scan for a single symrec, gathering info along the way.  After
+     * we've found the symrec, we keep scanning but error if we find
+     * another one.  We pull out the single symrec and any legal operations
+     * performed on it.
+     *
+     * Also, if we find a float anywhere, we don't allow mixing of a single
+     * symrec with it.
+     */
+    switch (e->op) {
+       case YASM_EXPR_ADD:
+           /* Okay for single symrec anywhere in expr.
+            * Check for single symrec anywhere.
+            * Handle symrec-symrec by checking for (-1*symrec)
+            * and symrec term pairs (where both symrecs are in the same
+            * segment).
+            */
+           if (e->numterms > 32)
+               yasm__fatal(N_("expression on line %d has too many add terms;"
+                              " internal limit of 32"), e->line);
+
+           used = 0;
+
+           for (i=0; i<e->numterms; i++) {
+               int j;
+               yasm_expr *sube;
+               yasm_intnum *intn;
+               yasm_symrec *sym;
+               /*@dependent@*/ yasm_section *sect2;
+               /*@dependent@*/ /*@null@*/ yasm_bytecode *precbc2;
+
+               /* First look for an (-1*symrec) term */
+               if (e->terms[i].type != YASM_EXPR_EXPR)
+                   continue;
+               sube = e->terms[i].data.expn;
+
+               if (sube->op != YASM_EXPR_MUL || sube->numterms != 2) {
+                   /* recurse instead */
+                   if (value_finalize_scan(value, sube, ssym_not_ok))
+                       return 1;
+                   continue;
+               }
+
+               if (sube->terms[0].type == YASM_EXPR_INT &&
+                   (sube->terms[1].type == YASM_EXPR_SYM ||
+                    sube->terms[1].type == YASM_EXPR_SYMEXP)) {
+                   intn = sube->terms[0].data.intn;
+                   sym = sube->terms[1].data.sym;
+               } else if ((sube->terms[0].type == YASM_EXPR_SYM ||
+                           sube->terms[0].type == YASM_EXPR_SYMEXP) &&
+                          sube->terms[1].type == YASM_EXPR_INT) {
+                   sym = sube->terms[0].data.sym;
+                   intn = sube->terms[1].data.intn;
+               } else {
+                   if (value_finalize_scan(value, sube, ssym_not_ok))
+                       return 1;
+                   continue;
+               }
+
+               if (!yasm_intnum_is_neg1(intn)) {
+                   if (value_finalize_scan(value, sube, ssym_not_ok))
+                       return 1;
+                   continue;
+               }
+
+               if (!yasm_symrec_get_label(sym, &precbc)) {
+                   if (value_finalize_scan(value, sube, ssym_not_ok))
+                       return 1;
+                   continue;
+               }
+               sect2 = yasm_bc_get_section(precbc);
+
+               /* Now look for a unused symrec term in the same segment */
+               for (j=0; j<e->numterms; j++) {
+                   if ((e->terms[j].type == YASM_EXPR_SYM
+                        || e->terms[j].type == YASM_EXPR_SYMEXP)
+                       && yasm_symrec_get_label(e->terms[j].data.sym, &precbc2)
+                       && (sect = yasm_bc_get_section(precbc2))
+                       && sect == sect2
+                       && (used & (1<<j)) == 0) {
+                       /* Mark as used */
+                       used |= 1<<j;
+                       break;  /* stop looking */
+                   }
+               }
+           }
+
+           /* Look for unmatched symrecs.  If we've already found one or
+           * we don't WANT to find one, error out.
+           */
+           for (i=0; i<e->numterms; i++) {
+               if ((e->terms[i].type == YASM_EXPR_SYM
+                    || e->terms[i].type == YASM_EXPR_SYMEXP)
+                   && (used & (1<<i)) == 0) {
+                   if (value->rel || ssym_not_ok)
+                       return 1;
+                   value->rel = e->terms[i].data.sym;
+                   /* and replace with 0 */
+                   e->terms[i].type = YASM_EXPR_INT;
+                   e->terms[i].data.intn = yasm_intnum_create_uint(0);
+               }
+           }
+           break;
+       case YASM_EXPR_SHR:
+           /* Okay for single symrec in LHS and constant on RHS.
+            * Single symrecs are not okay on RHS.
+            * If RHS is non-constant, don't allow single symrec on LHS.
+            * XXX: should rshift be an expr instead??
+            */
+
+           /* Check for not allowed cases on RHS */
+           switch (e->terms[1].type) {
+               case YASM_EXPR_REG:
+               case YASM_EXPR_FLOAT:
+                   return 1;           /* not legal */
+               case YASM_EXPR_SYM:
+               case YASM_EXPR_SYMEXP:
+                   return 1;
+               case YASM_EXPR_EXPR:
+                   if (value_finalize_scan(value, e->terms[1].data.expn, 1))
+                       return 1;
+                   break;
+               default:
+                   break;
+           }
+
+           /* Check for single sym and allowed cases on LHS */
+           switch (e->terms[0].type) {
+               /*case YASM_EXPR_REG:   ????? should this be illegal ????? */
+               case YASM_EXPR_FLOAT:
+                   return 1;           /* not legal */
+               case YASM_EXPR_SYM:
+               case YASM_EXPR_SYMEXP:
+                   if (value->rel || ssym_not_ok)
+                       return 1;
+                   value->rel = e->terms[0].data.sym;
+                   /* and replace with 0 */
+                   e->terms[0].type = YASM_EXPR_INT;
+                   e->terms[0].data.intn = yasm_intnum_create_uint(0);
+                   break;
+               case YASM_EXPR_EXPR:
+                   /* recurse */
+                   if (value_finalize_scan(value, e->terms[0].data.expn,
+                                           ssym_not_ok))
+                       return 1;
+                   break;
+               default:
+                   break;      /* ignore */
+           }
+
+           /* Handle RHS */
+           if (!value->rel)
+               break;          /* no handling needed */
+           if (e->terms[1].type != YASM_EXPR_INT)
+               return 1;       /* can't shift sym by non-constant integer */
+           shamt = yasm_intnum_get_uint(e->terms[1].data.intn);
+           if ((shamt + value->rshift) > YASM_VALUE_RSHIFT_MAX)
+               return 1;       /* total shift would be too large */
+           value->rshift += shamt;
+
+           /* Just leave SHR in place */
+           break;
+       case YASM_EXPR_SEG:
+           /* Okay for single symrec (can only be done once).
+            * Not okay for anything BUT a single symrec as an immediate
+            * child.
+            */
+           if (e->terms[0].type != YASM_EXPR_SYM
+               && e->terms[0].type != YASM_EXPR_SYMEXP)
+               return 1;
+
+           if (value->seg_of)
+               return 1;       /* multiple SEG not legal */
+           value->seg_of = 1;
+
+           if (value->rel || ssym_not_ok)
+               return 1;       /* got a relative portion somewhere else? */
+           value->rel = e->terms[0].data.sym;
+
+           /* replace with ident'ed 0 */
+           e->op = YASM_EXPR_IDENT;
+           e->terms[0].type = YASM_EXPR_INT;
+           e->terms[0].data.intn = yasm_intnum_create_uint(0);
+           break;
+       case YASM_EXPR_WRT:
+           /* Okay for single symrec in LHS and either a register or single
+            * symrec (as an immediate child) on RHS.
+            * If a single symrec on RHS, can only be done once.
+            * WRT reg is left in expr for arch to look at.
+            */
+
+           /* Handle RHS */
+           switch (e->terms[1].type) {
+               case YASM_EXPR_SYM:
+               case YASM_EXPR_SYMEXP:
+                   if (value->wrt)
+                       return 1;
+                   value->wrt = e->terms[1].data.sym;
+                   /* and drop the WRT portion */
+                   e->op = YASM_EXPR_IDENT;
+                   e->numterms = 1;
+                   break;
+               case YASM_EXPR_REG:
+                   break;  /* ignore */
+               default:
+                   return 1;
+           }
+
+           /* Handle LHS */
+           switch (e->terms[0].type) {
+               case YASM_EXPR_SYM:
+               case YASM_EXPR_SYMEXP:
+                   if (value->rel || ssym_not_ok)
+                       return 1;
+                   value->rel = e->terms[0].data.sym;
+                   /* and replace with 0 */
+                   e->terms[0].type = YASM_EXPR_INT;
+                   e->terms[0].data.intn = yasm_intnum_create_uint(0);
+                   break;
+               case YASM_EXPR_EXPR:
+                   /* recurse */
+                   return value_finalize_scan(value, e->terms[0].data.expn,
+                                              ssym_not_ok);
+               default:
+                   break;  /* ignore */
+           }
+
+           break;
+       default:
+           /* Single symrec not allowed anywhere */
+           for (i=0; i<e->numterms; i++) {
+               switch (e->terms[i].type) {
+                   case YASM_EXPR_SYM:
+                   case YASM_EXPR_SYMEXP:
+                       return 1;
+                   case YASM_EXPR_EXPR:
+                       /* recurse */
+                       return value_finalize_scan(value,
+                                                  e->terms[i].data.expn, 1);
+                   default:
+                       break;
+               }
+           }
+           break;
+    }
+
+    return 0;
+}
+
+int
+yasm_value_finalize_expr(yasm_value *value, yasm_expr *e)
+{
+    int error = 0;
+
+    if (!e) {
+       yasm_value_initialize(value, NULL);
+       return 0;
+    }
+
+    yasm_value_initialize(value, yasm_expr__level_tree
+                         (e, 1, 1, 0, NULL, NULL, NULL, NULL, &error));
+
+    /* quit early if there was an issue in simplify() */
+    if (error)
+       return 1;
+
+    /* Handle trivial (IDENT) cases immediately */
+    if (value->abs->op == YASM_EXPR_IDENT) {
+       switch (value->abs->terms[0].type) {
+           case YASM_EXPR_INT:
+               if (yasm_intnum_is_zero(value->abs->terms[0].data.intn)) {
+                   yasm_expr_destroy(value->abs);
+                   value->abs = NULL;
+               }
+               return 0;
+           case YASM_EXPR_REG:
+           case YASM_EXPR_FLOAT:
+               return 0;
+           case YASM_EXPR_SYM:
+           case YASM_EXPR_SYMEXP:
+               value->rel = value->abs->terms[0].data.sym;
+               yasm_expr_destroy(value->abs);
+               value->abs = NULL;
+               return 0;
+           case YASM_EXPR_EXPR:
+               /* Bring up lower values. */
+               while (value->abs->op == YASM_EXPR_IDENT
+                      && value->abs->terms[0].type == YASM_EXPR_EXPR) {
+                   yasm_expr *sube = value->abs->terms[0].data.expn;
+                   yasm_xfree(value->abs);
+                   value->abs = sube;
+               }
+               break;
+           default:
+               yasm_internal_error(N_("unexpected expr term type"));
+       }
+    }
+
+    if (value_finalize_scan(value, value->abs, 0))
+       return 1;
+
+    value->abs = yasm_expr__level_tree(value->abs, 1, 1, 0, NULL, NULL, NULL,
+                                      NULL, NULL);
+
+    /* Simplify 0 in abs to NULL */
+    if (value->abs->op == YASM_EXPR_IDENT
+       && value->abs->terms[0].type == YASM_EXPR_INT
+       && yasm_intnum_is_zero(value->abs->terms[0].data.intn)) {
+       yasm_expr_destroy(value->abs);
+       value->abs = NULL;
+    }
+    return 0;
+}
+
+int
+yasm_value_output_basic(yasm_value *value, /*@out@*/ unsigned char *buf,
+                       size_t destsize, size_t valsize, int shift,
+                       yasm_bytecode *bc, int warn, yasm_arch *arch,
+                       yasm_calc_bc_dist_func calc_bc_dist)
+{
+    /*@dependent@*/ /*@null@*/ yasm_intnum *intn = NULL;
+    /*@only@*/ yasm_intnum *outval;
+    int sym_local;
+    int retval = 1;
+
+    if (value->abs) {
+       /* Handle floating point expressions */
+       if (!value->rel && value->abs->op == YASM_EXPR_IDENT
+           && value->abs->terms[0].type == YASM_EXPR_FLOAT) {
+           if (shift < 0)
+               yasm_internal_error(N_("attempting to negative shift a float"));
+           if (yasm_arch_floatnum_tobytes(arch, value->abs->terms[0].data.flt,
+                                          buf, destsize, valsize,
+                                          (unsigned int)shift, warn,
+                                          bc->line))
+               return -1;
+           else
+               return 1;
+       }
+
+       /* Check for complex float expressions */
+       if (yasm_expr__contains(value->abs, YASM_EXPR_FLOAT)) {
+           yasm__error(bc->line, N_("floating point expression too complex"));
+           return -1;
+       }
+
+       /* Handle integer expressions */
+       intn = yasm_expr_get_intnum(&value->abs, calc_bc_dist);
+       if (!intn) {
+           yasm__error(bc->line, N_("expression too complex"));
+           return -1;
+       }
+    }
+
+    if (value->rel) {
+       /* If relative portion is not in bc section, don't try to handle it
+        * here.  Otherwise get the relative portion's offset.
+        */
+       /*@dependent@*/ yasm_bytecode *rel_prevbc;
+       unsigned long dist;
+
+       sym_local = yasm_symrec_get_label(value->rel, &rel_prevbc);
+       if (value->wrt || value->seg_of || !sym_local)
+           return 0;       /* we can't handle SEG, WRT, or external symbols */
+       if (rel_prevbc->section != bc->section)
+           return 0;       /* not in this section */
+       if (!value->curpos_rel)
+           return 0;       /* not PC-relative */
+
+       /* Calculate value relative to current assembly position */
+       dist = rel_prevbc->offset + rel_prevbc->len;
+       if (dist < bc->offset) {
+           outval = yasm_intnum_create_uint(bc->offset - dist);
+           yasm_intnum_calc(outval, YASM_EXPR_NEG, NULL, bc->line);
+       } else {
+           dist -= bc->offset;
+           outval = yasm_intnum_create_uint(dist);
+       }
+
+       if (value->rshift > 0) {
+           /*@only@*/ yasm_intnum *shamt =
+               yasm_intnum_create_uint((unsigned long)value->rshift);
+           yasm_intnum_calc(outval, YASM_EXPR_SHR, shamt, bc->line);
+           yasm_intnum_destroy(shamt);
+       }
+       /* Add in absolute portion */
+       if (intn)
+           yasm_intnum_calc(outval, YASM_EXPR_ADD, intn, bc->line);
+       /* Output! */
+       if (yasm_arch_intnum_tobytes(arch, outval, buf, destsize, valsize,
+                                    shift, bc, warn, bc->line))
+           retval = -1;
+       yasm_intnum_destroy(outval);
+    } else if (intn) {
+       /* Output just absolute portion */
+       if (yasm_arch_intnum_tobytes(arch, intn, buf, destsize, valsize,
+                                    shift, bc, warn, bc->line))
+           retval = -1;
+    } else {
+       /* No absolute or relative portions: output 0 */
+       outval = yasm_intnum_create_uint(0);
+       if (yasm_arch_intnum_tobytes(arch, outval, buf, destsize, valsize,
+                                    shift, bc, warn, bc->line))
+           retval = -1;
+       yasm_intnum_destroy(outval);
+    }
+    return retval;
+}
+
+void
+yasm_value_print(const yasm_value *value, FILE *f, int indent_level)
+{
+    fprintf(f, "%*sAbsolute portion=", indent_level, "");
+    yasm_expr_print(value->abs, f);
+    fprintf(f, "\n");
+    if (value->rel) {
+       fprintf(f, "%*sRelative to=%s%s\n", indent_level, "",
+               value->seg_of ? "SEG " : "",
+               yasm_symrec_get_name(value->rel));
+       if (value->wrt)
+           fprintf(f, "%*s(With respect to=%s)\n", indent_level, "",
+                   yasm_symrec_get_name(value->wrt));
+       if (value->rshift > 0)
+           fprintf(f, "%*s(Right shifted by=%u)\n", indent_level, "",
+                   value->rshift);
+       if (value->curpos_rel)
+           fprintf(f, "%*s(Relative to current position)\n", indent_level,
+                   "");
+    }
+}
diff --git a/libyasm/value.h b/libyasm/value.h
new file mode 100644 (file)
index 0000000..955fda4
--- /dev/null
@@ -0,0 +1,160 @@
+/**
+ * \file libyasm/value.h
+ * \brief YASM value interface.
+ *
+ * \rcs
+ * $Id$
+ * \endrcs
+ *
+ * \license
+ *  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:
+ *  - Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *  - 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.
+ * \endlicense
+ */
+#ifndef YASM_VALUE_H
+#define YASM_VALUE_H
+
+/** Initialize a #yasm_value with just an expression.  No processing is
+ * performed, the expression is simply stuck into value.abs and the other
+ * fields are initialized.  Use yasm_expr_extract_value() to perform "smart"
+ * processing into a #yasm_value.  This function is intended for use during
+ * parsing simply to ensure all fields of the value are initialized; after
+ * the parse is complete, yasm_value_extract() should be called to finalize
+ * the value.
+ * \param value            value to be initialized
+ * \param e        expression (kept)
+ */
+void yasm_value_initialize(/*@out@*/ yasm_value *value,
+                          /*@null@*/ /*@kept@*/ yasm_expr *e);
+
+/** Initialize a #yasm_value with just a symrec.  No processing is performed,
+ * the symrec is simply stuck into value.rel and the other fields are
+ * initialized.
+ * \param value            value to be initialized
+ * \param sym      symrec
+ */
+void yasm_value_init_sym(/*@out@*/ yasm_value *value,
+                        /*@null@*/ yasm_symrec *sym);
+
+/** Frees any memory inside value; does not free value itself.
+ * \param value            value
+ */
+void yasm_value_delete(yasm_value *value);
+
+/** Perform yasm_value_finalize_expr() on a value that already exists from
+ * being initialized with yasm_value_initialize().
+ * \param value                value
+ * \return Nonzero if value could not be split.
+ */
+int yasm_value_finalize(yasm_value *value);
+
+/** Break a #yasm_expr into a #yasm_value constituent parts.  Extracts
+ * the relative portion of the value, SEG and WRT portions, and top-level
+ * right shift, if any.  Places the remaining expr into the absolute
+ * portion of the value.  Essentially a combination of yasm_value_initialize()
+ * and yasm_value_finalize().  First expands references to symrecs in
+ * absolute sections by expanding with the absolute section start plus the
+ * symrec offset within the absolute section.
+ * \param value                value to store split portions into
+ * \param e            expression input
+ * \return Nonzero if the expr could not be split into a value for some
+ *         reason (e.g. the relative portion was not added, but multiplied,
+ *         etc).
+ * \caution Do not use e after this call.  Even if an error is returned, e
+ *          is stored into value.
+ * \note This should only be called after the parse is complete.  Calling
+ *       before the parse is complete will usually result in an error return.
+ */
+int yasm_value_finalize_expr(/*@out@*/ yasm_value *value,
+                            /*@null@*/ /*@kept@*/ yasm_expr *e);
+
+/** Output value if constant or PC-relative section-local.  This should be
+ * used from objfmt yasm_output_value_func() functions.
+ * functions.
+ * \param value                value
+ * \param buf          buffer for byte representation
+ * \param destsize     destination size (in bytes)
+ * \param valsize      size (in bits)
+ * \param shift                left shift (in bits); may be negative to specify right
+ *                     shift (standard warnings include truncation to boundary)
+ * \param bc           current bytecode (usually passed into higher-level
+ *                     calling function)
+ * \param warn         enables standard warnings: zero for none;
+ *                     nonzero for overflow/underflow floating point warnings;
+ *                     negative for signed integer warnings,
+ *                     positive for unsigned integer warnings
+ * \param arch         architecture
+ * \param calc_bc_dist function used to determine bytecode distance
+ * \note Adds in value.rel (correctly) if PC-relative and in the same section
+ *       as bc (and there is no WRT or SEG); if this is not the desired
+ *       behavior, e.g. a reloc is needed in this case, don't use this
+ *       function!
+ * \return 0 if no value output due to value needing relocation;
+ *         1 if value output; -1 if error.
+ */
+int yasm_value_output_basic
+    (yasm_value *value, /*@out@*/ unsigned char *buf, size_t destsize,
+     size_t valsize, int shift, yasm_bytecode *bc, int warn, yasm_arch *arch,
+     yasm_calc_bc_dist_func calc_bc_dist);
+
+/** Print a value.  For debugging purposes.
+ * \param value                value
+ * \param indent_level indentation level
+ * \param f            file
+ */
+void yasm_value_print(const yasm_value *value, FILE *f, int indent_level);
+
+
+#ifndef YASM_DOXYGEN
+#define yasm_value_initialize(value, e) \
+    do { \
+       (value)->abs = e; \
+       (value)->rel = NULL; \
+       (value)->wrt = NULL; \
+       (value)->seg_of = 0; \
+       (value)->rshift = 0; \
+       (value)->curpos_rel = 0; \
+    } while(0)
+
+#define yasm_value_init_sym(value, sym) \
+    do { \
+       (value)->abs = NULL; \
+       (value)->rel = sym; \
+       (value)->wrt = NULL; \
+       (value)->seg_of = 0; \
+       (value)->rshift = 0; \
+       (value)->curpos_rel = 0; \
+    } while(0)
+
+#define yasm_value_delete(value) \
+    do { \
+       yasm_expr_destroy((value)->abs); \
+       (value)->abs = NULL; \
+       (value)->rel = NULL; \
+    } while(0)
+
+#define yasm_value_finalize(value) \
+    yasm_value_finalize_expr(value, (value)->abs)
+#endif
+
+#endif
index 2fb5b8ffd4ef55c928d8bfa75bf211e120dcc271..8d0aba58449c91d38c4249ad2abf5bf5d193647c 100644 (file)
@@ -182,7 +182,6 @@ yasm_arch_module yasm_lc3b_LTX_arch = {
     lc3b_get_fill,
     yasm_lc3b__finalize_insn,
     lc3b_floatnum_tobytes,
-    yasm_lc3b__intnum_fixup_rel,
     yasm_lc3b__intnum_tobytes,
     lc3b_get_reg_size,
     lc3b_reggroup_get_reg,
index fe5304d374e9cde3ba222a862b1073636f7c383a..52e918ae9a25b1ce046bb56af4c790a45c53dc53 100644 (file)
@@ -42,10 +42,11 @@ typedef enum lc3b_imm_type {
 /* Bytecode types */
 
 typedef struct lc3b_insn {
-    /*@null@*/ yasm_expr *imm; /* immediate or relative value */
+    yasm_value imm;            /* immediate or relative value */
     lc3b_imm_type imm_type;    /* size of the immediate */
 
-    /*@null@*/ /*@dependent@*/ yasm_symrec *origin; /* PC origin if needed */
+    /* PC origin if needed */
+    /*@null@*/ /*@dependent@*/ yasm_bytecode *origin_prevbc;
 
     unsigned int opcode;       /* opcode */
 } lc3b_insn;
@@ -68,10 +69,6 @@ void yasm_lc3b__finalize_insn
      /*@null@*/ yasm_insn_operands *operands, int num_prefixes,
      unsigned long **prefixes, int num_segregs, const unsigned long *segregs);
 
-int yasm_lc3b__intnum_fixup_rel
-    (yasm_arch *arch, yasm_intnum *intn, size_t valsize,
-     const yasm_bytecode *bc, unsigned long line);
-
 int yasm_lc3b__intnum_tobytes
     (yasm_arch *arch, const yasm_intnum *intn, unsigned char *buf,
      size_t destsize, size_t valsize, int shift, const yasm_bytecode *bc,
index 6f189d402164e3d748371bcb671f8f2424fd42e0..f3ce2f198b5443b1f37b654e52f0bde55d82330b 100644 (file)
@@ -42,7 +42,7 @@ static void lc3b_bc_insn_print(const void *contents, FILE *f,
 static yasm_bc_resolve_flags lc3b_bc_insn_resolve
     (yasm_bytecode *bc, int save, yasm_calc_bc_dist_func calc_bc_dist);
 static int lc3b_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);
 
 /* Bytecode callback structures */
@@ -66,8 +66,7 @@ static void
 lc3b_bc_insn_destroy(void *contents)
 {
     lc3b_insn *insn = (lc3b_insn *)contents;
-    if (insn->imm)
-       yasm_expr_destroy(insn->imm);
+    yasm_value_delete(&insn->imm);
     yasm_xfree(contents);
 }
 
@@ -78,13 +77,13 @@ lc3b_bc_insn_print(const void *contents, FILE *f, int indent_level)
 
     fprintf(f, "%*s_Instruction_\n", indent_level, "");
     fprintf(f, "%*sImmediate Value:", indent_level, "");
-    if (!insn->imm)
+    if (!insn->imm.abs)
        fprintf(f, " (nil)\n");
     else {
        indent_level++;
-       fprintf(f, "\n%*sVal=", indent_level, "");
-       yasm_expr_print(insn->imm, f);
-       fprintf(f, "\n%*sType=", indent_level, "");
+       fprintf(f, "\n");
+       yasm_value_print(&insn->imm, f, indent_level);
+       fprintf(f, "%*sType=", indent_level, "");
        switch (insn->imm_type) {
            case LC3B_IMM_NONE:
                fprintf(f, "NONE-SHOULDN'T HAPPEN");
@@ -113,12 +112,14 @@ lc3b_bc_insn_print(const void *contents, FILE *f, int indent_level)
        }
        indent_level--;
     }
+    /* FIXME
     fprintf(f, "\n%*sOrigin=", indent_level, "");
     if (insn->origin) {
        fprintf(f, "\n");
        yasm_symrec_print(insn->origin, f, indent_level+1);
     } else
        fprintf(f, "(nil)\n");
+    */
     fprintf(f, "%*sOpcode: %04x\n", indent_level, "",
            (unsigned int)insn->opcode);
 }
@@ -128,8 +129,8 @@ lc3b_bc_insn_resolve(yasm_bytecode *bc, int save,
                     yasm_calc_bc_dist_func calc_bc_dist)
 {
     lc3b_insn *insn = (lc3b_insn *)bc->contents;
-    /*@null@*/ yasm_expr *temp;
-    /*@dependent@*/ /*@null@*/ const yasm_intnum *num;
+    yasm_bytecode *target_prevbc;
+    /*@only@*/ yasm_intnum *num;
     long rel;
 
     /* Fixed size instruction length */
@@ -141,18 +142,31 @@ lc3b_bc_insn_resolve(yasm_bytecode *bc, int save,
     if (insn->imm_type != LC3B_IMM_9_PC || !save)
        return YASM_BC_RESOLVE_MIN_LEN;
 
-    temp = yasm_expr_copy(insn->imm);
-    temp = yasm_expr_create(YASM_EXPR_SUB, yasm_expr_expr(temp),
-                           yasm_expr_sym(insn->origin), bc->line);
-    num = yasm_expr_get_intnum(&temp, calc_bc_dist);
-    if (!num) {
-       yasm__error(bc->line, N_("target external or out of segment"));
+    if (!insn->imm.rel)
+       num = yasm_intnum_create_uint(0);
+    else if (!yasm_symrec_get_label(insn->imm.rel, &target_prevbc)
+            || target_prevbc->section != insn->origin_prevbc->section
+            || !(num = calc_bc_dist(insn->origin_prevbc, target_prevbc))) {
+       /* External or out of segment, so we can't check distance. */
+       return YASM_BC_RESOLVE_MIN_LEN;
+    }
+
+    if (insn->imm.abs) {
+       /*@only@*/ yasm_expr *temp = yasm_expr_copy(insn->imm.abs);
+       /*@dependent@*/ /*@null@*/ yasm_intnum *num2;
+       num2 = yasm_expr_get_intnum(&temp, calc_bc_dist);
+       if (!num2) {
+           yasm__error(bc->line, N_("jump target too complex"));
+           yasm_expr_destroy(temp);
+           return YASM_BC_RESOLVE_ERROR | YASM_BC_RESOLVE_UNKNOWN_LEN;
+       }
+       yasm_intnum_calc(num, YASM_EXPR_ADD, num2, bc->line);
        yasm_expr_destroy(temp);
-       return YASM_BC_RESOLVE_ERROR | YASM_BC_RESOLVE_UNKNOWN_LEN;
     }
+
     rel = yasm_intnum_get_int(num);
+    yasm_intnum_destroy(num);
     rel -= 2;
-    yasm_expr_destroy(temp);
     /* 9-bit signed, word-multiple displacement */
     if (rel < -512 || rel > 511) {
        yasm__error(bc->line, N_("target out of range"));
@@ -163,10 +177,11 @@ lc3b_bc_insn_resolve(yasm_bytecode *bc, int save,
 
 static int
 lc3b_bc_insn_tobytes(yasm_bytecode *bc, unsigned char **bufp, void *d,
-                    yasm_output_expr_func output_expr,
+                    yasm_output_value_func output_value,
                     /*@unused@*/ yasm_output_reloc_func output_reloc)
 {
     lc3b_insn *insn = (lc3b_insn *)bc->contents;
+    /*@only@*/ yasm_intnum *delta;
 
     /* Output opcode */
     YASM_SAVE_16_L(*bufp, insn->opcode);
@@ -176,34 +191,42 @@ lc3b_bc_insn_tobytes(yasm_bytecode *bc, unsigned char **bufp, void *d,
        case LC3B_IMM_NONE:
            break;
        case LC3B_IMM_4:
-           if (output_expr(&insn->imm, *bufp, 2, 4, 0, 0, bc, 0, 1, d))
+           if (output_value(&insn->imm, *bufp, 2, 4, 0, 0, bc, 1, d))
                return 1;
            break;
        case LC3B_IMM_5:
-           if (output_expr(&insn->imm, *bufp, 2, 5, 0, 0, bc, 0, 1, d))
+           if (output_value(&insn->imm, *bufp, 2, 5, 0, 0, bc, 1, d))
                return 1;
            break;
        case LC3B_IMM_6_WORD:
-           if (output_expr(&insn->imm, *bufp, 2, 6, -1, 0, bc, 0, 1, d))
+           if (output_value(&insn->imm, *bufp, 2, 6, -1, 0, bc, 1, d))
                return 1;
            break;
        case LC3B_IMM_6_BYTE:
-           if (output_expr(&insn->imm, *bufp, 2, 6, 0, 0, bc, 0, 1, d))
+           if (output_value(&insn->imm, *bufp, 2, 6, 0, 0, bc, 1, d))
                return 1;
            break;
        case LC3B_IMM_8:
-           if (output_expr(&insn->imm, *bufp, 2, 8, -1, 0, bc, 0, 1, d))
+           if (output_value(&insn->imm, *bufp, 2, 8, -1, 0, bc, 1, d))
                return 1;
            break;
        case LC3B_IMM_9_PC:
-           insn->imm = yasm_expr_create(YASM_EXPR_SUB,
-               yasm_expr_expr(insn->imm), yasm_expr_sym(insn->origin),
-               bc->line);
-           if (output_expr(&insn->imm, *bufp, 2, 9, -1, 0, bc, 1, 1, d))
+           /* Adjust relative displacement to end of bytecode */
+           delta = yasm_intnum_create_int(-(long)bc->len);
+           if (!insn->imm.abs)
+               insn->imm.abs = yasm_expr_create_ident(yasm_expr_int(delta),
+                                                      bc->line);
+           else
+               insn->imm.abs =
+                   yasm_expr_create(YASM_EXPR_ADD,
+                                    yasm_expr_expr(insn->imm.abs),
+                                    yasm_expr_int(delta), bc->line);
+
+           if (output_value(&insn->imm, *bufp, 2, 9, -1, 0, bc, 1, d))
                return 1;
            break;
        case LC3B_IMM_9:
-           if (output_expr(&insn->imm, *bufp, 2, 9, -1, 0, bc, 0, 1, d))
+           if (output_value(&insn->imm, *bufp, 2, 9, -1, 0, bc, 1, d))
                return 1;
            break;
        default:
@@ -214,21 +237,6 @@ lc3b_bc_insn_tobytes(yasm_bytecode *bc, unsigned char **bufp, void *d,
     return 0;
 }
 
-int
-yasm_lc3b__intnum_fixup_rel(yasm_arch *arch, yasm_intnum *intn,
-                           size_t valsize, const yasm_bytecode *bc,
-                           unsigned long line)
-{
-    yasm_intnum *delta;
-    if (valsize != 9)
-       yasm_internal_error(
-           N_("tried to do PC-relative offset from invalid sized value"));
-    delta = yasm_intnum_create_uint(bc->len);
-    yasm_intnum_calc(intn, YASM_EXPR_SUB, delta, line);
-    yasm_intnum_destroy(delta);
-    return 0;
-}
-
 int
 yasm_lc3b__intnum_tobytes(yasm_arch *arch, const yasm_intnum *intn,
                          unsigned char *buf, size_t destsize, size_t valsize,
index 5c81c460529be69299e830960afd7b590279056e..9b0dcee4ceb12260fcd804fb95e9457de04cd921 100644 (file)
@@ -239,9 +239,9 @@ yasm_lc3b__finalize_insn(yasm_arch *arch, yasm_bytecode *bc,
 
     /* Copy what we can from info */
     insn = yasm_xmalloc(sizeof(lc3b_insn));
-    insn->imm = NULL;
+    yasm_value_initialize(&insn->imm, NULL);
     insn->imm_type = LC3B_IMM_NONE;
-    insn->origin = NULL;
+    insn->origin_prevbc = NULL;
     insn->opcode = info->opcode;
 
     /* Apply modifiers */
@@ -277,12 +277,17 @@ yasm_lc3b__finalize_insn(yasm_arch *arch, yasm_bytecode *bc,
                case OPA_Imm:
                    switch (op->type) {
                        case YASM_INSN__OPERAND_IMM:
-                           insn->imm = op->data.val;
+                           if (yasm_value_finalize_expr(&insn->imm,
+                                                        op->data.val))
+                               yasm__error(bc->line,
+                                           N_("immediate expression too complex"));
                            break;
                        case YASM_INSN__OPERAND_REG:
-                           insn->imm = yasm_expr_create_ident(yasm_expr_int(
-                               yasm_intnum_create_uint(op->data.reg & 0x7)),
-                               bc->line);
+                           if (yasm_value_finalize_expr(&insn->imm,
+                                   yasm_expr_create_ident(yasm_expr_int(
+                                   yasm_intnum_create_uint(op->data.reg & 0x7)),
+                                   bc->line)))
+                               yasm_internal_error(N_("reg expr too complex?"));
                            break;
                        default:
                            yasm_internal_error(N_("invalid operand conversion"));
@@ -293,15 +298,16 @@ yasm_lc3b__finalize_insn(yasm_arch *arch, yasm_bytecode *bc,
            }
 
            insn->imm_type = (info->operands[i] & OPI_MASK)>>3;
-           if (insn->imm_type == LC3B_IMM_9_PC)
-               insn->origin = yasm_symtab_define_label2("$", prev_bc, 0,
-                                                        bc->line);
+           if (insn->imm_type == LC3B_IMM_9_PC) {
+               insn->origin_prevbc = prev_bc;
+               if (insn->imm.seg_of || insn->imm.rshift
+                   || insn->imm.curpos_rel)
+                   yasm__error(bc->line, N_("invalid jump target"));
+               insn->imm.curpos_rel = 1;
+           }
        }
     }
 
-    if (!insn->imm)
-       insn->imm_type = LC3B_IMM_NONE;
-
     /* Transform the bytecode */
     yasm_lc3b__bc_transform_insn(bc, insn);
 }
index eab4908937af2a1473e2d7d863a23e1297f357f8..82b9ca5378c1f971ea96de7d17647adb6d1ec7b3 100644 (file)
@@ -400,7 +400,6 @@ yasm_arch_module yasm_x86_LTX_arch = {
     x86_get_fill,
     yasm_x86__finalize_insn,
     yasm_x86__floatnum_tobytes,
-    yasm_x86__intnum_fixup_rel,
     yasm_x86__intnum_tobytes,
     yasm_x86__get_reg_size,
     x86_reggroup_get_reg,
index 1a3d7b64a158fc883c11dd8fb433eafc4b3e0cb4..6cb6fd41bde004609055bc73589b2e49e049928e 100644 (file)
@@ -135,17 +135,35 @@ int yasm_x86__set_rex_from_reg(unsigned char *rex, unsigned char *low3,
                               unsigned long reg, unsigned int bits,
                               x86_rex_bit_pos rexbit);
 
-void yasm_x86__ea_set_disponly(yasm_effaddr *ea);
-yasm_effaddr *yasm_x86__ea_create_reg(unsigned long reg, unsigned char *rex,
-                                     unsigned int bits);
-yasm_effaddr *yasm_x86__ea_create_imm
+/* Effective address type */
+typedef struct x86_effaddr {
+    yasm_effaddr ea;           /* base structure */
+
+    /* How the spare (register) bits in Mod/RM are handled:
+     * Even if valid_modrm=0, the spare bits are still valid (don't overwrite!)
+     * They're set in bytecode_create_insn().
+     */
+    unsigned char modrm;
+    unsigned char valid_modrm; /* 1 if Mod/RM byte currently valid, 0 if not */
+    unsigned char need_modrm;  /* 1 if Mod/RM byte needed, 0 if not */
+
+    unsigned char sib;
+    unsigned char valid_sib;   /* 1 if SIB byte currently valid, 0 if not */
+    unsigned char need_sib;    /* 1 if SIB byte needed, 0 if not,
+                                  0xff if unknown */
+} x86_effaddr;
+
+void yasm_x86__ea_init(x86_effaddr *x86_ea, unsigned int spare,
+                      unsigned long line);
+
+void yasm_x86__ea_set_disponly(x86_effaddr *x86_ea);
+x86_effaddr *yasm_x86__ea_create_reg(unsigned long reg, unsigned char *rex,
+                                    unsigned int bits);
+x86_effaddr *yasm_x86__ea_create_imm
     (/*@keep@*/ yasm_expr *imm, unsigned int im_len);
 yasm_effaddr *yasm_x86__ea_create_expr(yasm_arch *arch,
                                       /*@keep@*/ yasm_expr *e);
 
-/*@observer@*/ /*@null@*/ yasm_effaddr *yasm_x86__bc_insn_get_ea
-    (/*@null@*/ yasm_bytecode *bc);
-
 void yasm_x86__bc_insn_opersize_override(yasm_bytecode *bc,
                                         unsigned int opersize);
 void yasm_x86__bc_insn_addrsize_override(yasm_bytecode *bc,
@@ -172,7 +190,7 @@ typedef struct x86_insn {
     x86_common common;             /* common x86 information */
     x86_opcode opcode;
 
-    /*@null@*/ yasm_effaddr *ea;    /* effective address */
+    /*@null@*/ x86_effaddr *x86_ea; /* effective address */
 
     /*@null@*/ yasm_immval *imm;    /* immediate or relative value */
 
@@ -231,8 +249,8 @@ typedef struct x86_jmp {
     x86_common common;         /* common x86 information */
     x86_opcode shortop, nearop;
 
-    yasm_expr *target;         /* target location */
-    /*@dependent@*/ yasm_symrec *origin;    /* jump origin */
+    yasm_value target;         /* jump target */
+    /*@dependent@*/ yasm_bytecode *origin_prevbc;   /* jump origin */
 
     /* which opcode are we using? */
     /* The *FORCED forms are specified in the source as such */
@@ -247,8 +265,8 @@ typedef struct x86_jmpfar {
     x86_common common;         /* common x86 information */
     x86_opcode opcode;
 
-    yasm_expr *segment;                /* target segment */
-    yasm_expr *offset;         /* target offset */
+    yasm_value segment;                /* target segment */
+    yasm_value offset;         /* target offset */
 } x86_jmpfar;
 
 void yasm_x86__bc_transform_insn(yasm_bytecode *bc, x86_insn *insn);
@@ -259,19 +277,13 @@ void yasm_x86__bc_apply_prefixes
     (x86_common *common, unsigned char *rex, int num_prefixes,
      unsigned long **prefixes, unsigned long line);
 
-void yasm_x86__ea_init(yasm_effaddr *ea, unsigned int spare,
-                      /*@null@*/ yasm_symrec *origin);
-
 /* Check an effective address.  Returns 0 if EA was successfully determined,
  * 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,
-     yasm_calc_bc_dist_func calc_bc_dist);
+    (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 long line);
 
 void yasm_x86__parse_cpu(yasm_arch *arch, const char *cpuid, size_t cpuid_len,
                         unsigned long line);
@@ -293,9 +305,6 @@ int yasm_x86__floatnum_tobytes
     (yasm_arch *arch, const yasm_floatnum *flt, unsigned char *buf,
      size_t destsize, size_t valsize, size_t shift, int warn,
      unsigned long line);
-int yasm_x86__intnum_fixup_rel
-    (yasm_arch *arch, yasm_intnum *intn, size_t valsize,
-     const yasm_bytecode *bc, unsigned long line);
 int yasm_x86__intnum_tobytes
     (yasm_arch *arch, const yasm_intnum *intn, unsigned char *buf,
      size_t destsize, size_t valsize, int shift, const yasm_bytecode *bc,
index 5e55ae07b3ecd0071341b2b03964def78d91a8de..6938b0a8c76a042a2683f2b2509d4a3b36bdb92b 100644 (file)
 #include "x86arch.h"
 
 
-/* Effective address type */
-
-typedef struct x86_effaddr {
-    yasm_effaddr ea;           /* base structure */
-
-    /* PC-relative portions are for AMD64 only (RIP addressing) */
-    /*@null@*/ /*@dependent@*/ yasm_symrec *origin;    /* pcrel origin */
-
-    /* How the spare (register) bits in Mod/RM are handled:
-     * Even if valid_modrm=0, the spare bits are still valid (don't overwrite!)
-     * They're set in bytecode_create_insn().
-     */
-    unsigned char modrm;
-    unsigned char valid_modrm; /* 1 if Mod/RM byte currently valid, 0 if not */
-    unsigned char need_modrm;  /* 1 if Mod/RM byte needed, 0 if not */
-
-    unsigned char sib;
-    unsigned char valid_sib;   /* 1 if SIB byte currently valid, 0 if not */
-    unsigned char need_sib;    /* 1 if SIB byte needed, 0 if not,
-                                  0xff if unknown */
-
-    unsigned char pcrel;       /* 1 if PC-relative transformation needed */
-} x86_effaddr;
-
 /* Effective address callback function prototypes */
 
 static void x86_ea_destroy(yasm_effaddr *ea);
@@ -72,7 +48,7 @@ static void x86_bc_insn_print(const void *contents, FILE *f,
 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_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);
@@ -80,7 +56,7 @@ 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_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);
@@ -90,7 +66,7 @@ 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_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 */
@@ -170,27 +146,24 @@ yasm_x86__bc_transform_jmpfar(yasm_bytecode *bc, x86_jmpfar *jmpfar)
 }
 
 void
-yasm_x86__ea_init(yasm_effaddr *ea, unsigned int spare, yasm_symrec *origin)
+yasm_x86__ea_init(x86_effaddr *x86_ea, unsigned int spare, unsigned long line)
 {
-    x86_effaddr *x86_ea = (x86_effaddr *)ea;
-    x86_ea->origin = origin;
+    if (yasm_value_finalize(&x86_ea->ea.disp))
+       yasm__error(line, N_("effective address too complex"));
     x86_ea->modrm &= 0xC7;                 /* zero spare/reg bits */
     x86_ea->modrm |= (spare << 3) & 0x38;   /* plug in provided bits */
 }
 
 void
-yasm_x86__ea_set_disponly(yasm_effaddr *ea)
+yasm_x86__ea_set_disponly(x86_effaddr *x86_ea)
 {
-    x86_effaddr *x86_ea = (x86_effaddr *)ea;
-
     x86_ea->valid_modrm = 0;
     x86_ea->need_modrm = 0;
     x86_ea->valid_sib = 0;
     x86_ea->need_sib = 0;
-    x86_ea->pcrel = 0;
 }
 
-yasm_effaddr *
+x86_effaddr *
 yasm_x86__ea_create_reg(unsigned long reg, unsigned char *rex,
                        unsigned int bits)
 {
@@ -203,8 +176,9 @@ yasm_x86__ea_create_reg(unsigned long reg, unsigned char *rex,
     x86_ea = yasm_xmalloc(sizeof(x86_effaddr));
 
     x86_ea->ea.callback = &x86_ea_callback;
-    x86_ea->ea.disp = (yasm_expr *)NULL;
-    x86_ea->ea.len = 0;
+    yasm_value_initialize(&x86_ea->ea.disp, NULL);
+    x86_ea->ea.disp_len = 0;
+    x86_ea->ea.need_disp = 0;
     x86_ea->ea.nosplit = 0;
     x86_ea->ea.strong = 0;
     x86_ea->ea.segreg = 0;
@@ -214,9 +188,8 @@ yasm_x86__ea_create_reg(unsigned long reg, unsigned char *rex,
     x86_ea->sib = 0;
     x86_ea->valid_sib = 0;
     x86_ea->need_sib = 0;
-    x86_ea->pcrel = 0;
 
-    return (yasm_effaddr *)x86_ea;
+    return x86_ea;
 }
 
 yasm_effaddr *
@@ -243,8 +216,9 @@ yasm_x86__ea_create_expr(yasm_arch *arch, yasm_expr *e)
                                 yasm_expr_reg(X86_RIP), e->line);
        }
     }
-    x86_ea->ea.disp = e;
-    x86_ea->ea.len = 0;
+    yasm_value_initialize(&x86_ea->ea.disp, e);
+    x86_ea->ea.disp_len = 0;
+    x86_ea->ea.need_disp = 1;
     x86_ea->ea.nosplit = 0;
     x86_ea->ea.strong = 0;
     x86_ea->ea.segreg = 0;
@@ -257,13 +231,12 @@ yasm_x86__ea_create_expr(yasm_arch *arch, yasm_expr *e)
      * the BITS/address override setting.
      */
     x86_ea->need_sib = 0xff;
-    x86_ea->pcrel = 0;
 
     return (yasm_effaddr *)x86_ea;
 }
 
 /*@-compmempass@*/
-yasm_effaddr *
+x86_effaddr *
 yasm_x86__ea_create_imm(yasm_expr *imm, unsigned int im_len)
 {
     x86_effaddr *x86_ea;
@@ -271,8 +244,9 @@ yasm_x86__ea_create_imm(yasm_expr *imm, unsigned int im_len)
     x86_ea = yasm_xmalloc(sizeof(x86_effaddr));
 
     x86_ea->ea.callback = &x86_ea_callback;
-    x86_ea->ea.disp = imm;
-    x86_ea->ea.len = (unsigned char)im_len;
+    yasm_value_initialize(&x86_ea->ea.disp, imm);
+    x86_ea->ea.disp_len = (unsigned char)im_len;
+    x86_ea->ea.need_disp = 1;
     x86_ea->ea.nosplit = 0;
     x86_ea->ea.strong = 0;
     x86_ea->ea.segreg = 0;
@@ -282,9 +256,8 @@ yasm_x86__ea_create_imm(yasm_expr *imm, unsigned int im_len)
     x86_ea->sib = 0;
     x86_ea->valid_sib = 0;
     x86_ea->need_sib = 0;
-    x86_ea->pcrel = 0;
 
-    return (yasm_effaddr *)x86_ea;
+    return x86_ea;
 }
 /*@=compmempass@*/
 
@@ -348,10 +321,10 @@ static void
 x86_bc_insn_destroy(void *contents)
 {
     x86_insn *insn = (x86_insn *)contents;
-    if (insn->ea)
-       yasm_ea_destroy((yasm_effaddr *)insn->ea);
+    if (insn->x86_ea)
+       yasm_ea_destroy((yasm_effaddr *)insn->x86_ea);
     if (insn->imm) {
-       yasm_expr_destroy(insn->imm->val);
+       yasm_value_delete(&insn->imm->val);
        yasm_xfree(insn->imm);
     }
     yasm_xfree(contents);
@@ -361,7 +334,7 @@ static void
 x86_bc_jmp_destroy(void *contents)
 {
     x86_jmp *jmp = (x86_jmp *)contents;
-    yasm_expr_destroy(jmp->target);
+    yasm_value_delete(&jmp->target);
     yasm_xfree(contents);
 }
 
@@ -369,8 +342,8 @@ static void
 x86_bc_jmpfar_destroy(void *contents)
 {
     x86_jmpfar *jmpfar = (x86_jmpfar *)contents;
-    yasm_expr_destroy(jmpfar->segment);
-    yasm_expr_destroy(jmpfar->offset);
+    yasm_value_delete(&jmpfar->segment);
+    yasm_value_delete(&jmpfar->offset);
     yasm_xfree(contents);
 }
 
@@ -383,8 +356,8 @@ static void
 x86_ea_print(const yasm_effaddr *ea, FILE *f, int indent_level)
 {
     const x86_effaddr *x86_ea = (const x86_effaddr *)ea;
-    fprintf(f, "%*sSegmentOv=%02x PCRel=%u\n", indent_level, "",
-           (unsigned int)x86_ea->ea.segreg, (unsigned int)x86_ea->pcrel);
+    fprintf(f, "%*sSegmentOv=%02x\n", indent_level, "",
+           (unsigned int)x86_ea->ea.segreg);
     fprintf(f, "%*sModRM=%03o ValidRM=%u NeedRM=%u\n", indent_level, "",
            (unsigned int)x86_ea->modrm, (unsigned int)x86_ea->valid_modrm,
            (unsigned int)x86_ea->need_modrm);
@@ -421,9 +394,9 @@ x86_bc_insn_print(const void *contents, FILE *f, int indent_level)
 
     fprintf(f, "%*s_Instruction_\n", indent_level, "");
     fprintf(f, "%*sEffective Address:", indent_level, "");
-    if (insn->ea) {
+    if (insn->x86_ea) {
        fprintf(f, "\n");
-       yasm_ea_print((yasm_effaddr *)insn->ea, f, indent_level+1);
+       yasm_ea_print((yasm_effaddr *)insn->x86_ea, f, indent_level+1);
     } else
        fprintf(f, " (nil)\n");
     fprintf(f, "%*sImmediate Value:", indent_level, "");
@@ -431,12 +404,8 @@ x86_bc_insn_print(const void *contents, FILE *f, int indent_level)
        fprintf(f, " (nil)\n");
     else {
        indent_level++;
-       fprintf(f, "\n%*sVal=", indent_level, "");
-       if (insn->imm->val)
-           yasm_expr_print(insn->imm->val, f);
-       else
-           fprintf(f, "(nil-SHOULDN'T HAPPEN)");
        fprintf(f, "\n");
+       yasm_value_print(&insn->imm->val, f, indent_level);
        fprintf(f, "%*sLen=%u, Sign=%u\n", indent_level, "",
                (unsigned int)insn->imm->len,
                (unsigned int)insn->imm->sign);
@@ -456,10 +425,12 @@ x86_bc_jmp_print(const void *contents, FILE *f, int indent_level)
     const x86_jmp *jmp = (const x86_jmp *)contents;
 
     fprintf(f, "%*s_Jump_\n", indent_level, "");
-    fprintf(f, "%*sTarget=", indent_level, "");
-    yasm_expr_print(jmp->target, f);
+    fprintf(f, "%*sTarget:\n", indent_level, "");
+    yasm_value_print(&jmp->target, f, indent_level+1);
+    /* FIXME
     fprintf(f, "%*sOrigin=\n", indent_level, "");
     yasm_symrec_print(jmp->origin, f, indent_level+1);
+    */
     fprintf(f, "\n%*sShort Form:\n", indent_level, "");
     if (jmp->shortop.len == 0)
        fprintf(f, "%*sNone\n", indent_level+1, "");
@@ -500,10 +471,10 @@ x86_bc_jmpfar_print(const void *contents, FILE *f, int indent_level)
     const x86_jmpfar *jmpfar = (const x86_jmpfar *)contents;
 
     fprintf(f, "%*s_Far_Jump_\n", indent_level, "");
-    fprintf(f, "%*sSegment=", indent_level, "");
-    yasm_expr_print(jmpfar->segment, f);
-    fprintf(f, "\n%*sOffset=", indent_level, "");
-    yasm_expr_print(jmpfar->offset, f);
+    fprintf(f, "%*sSegment:\n", indent_level, "");
+    yasm_value_print(&jmpfar->segment, f, indent_level+1);
+    fprintf(f, "%*sOffset:\n", indent_level, "");
+    yasm_value_print(&jmpfar->offset, f, indent_level+1);
     x86_opcode_print(&jmpfar->opcode, f, indent_level);
     x86_common_print(&jmpfar->common, f, indent_level);
 }
@@ -530,184 +501,182 @@ x86_bc_insn_resolve(yasm_bytecode *bc, int save,
                    yasm_calc_bc_dist_func calc_bc_dist)
 {
     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 (x86_ea) {
        /* Create temp copy of disp, etc. */
-       x86_effaddr eat = *x86_ea;  /* structure copy */
-       unsigned char displen = ea->len;
+       x86_effaddr eat = *x86_ea;      /* structure copy */
 
-       if (ea->disp) {
-           temp = yasm_expr_copy(ea->disp);
-           assert(temp != NULL);
+       /* 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 &&
-               !yasm_expr__contains(temp, YASM_EXPR_REG)) {
-               yasm_x86__ea_set_disponly((yasm_effaddr *)&eat);
+       /* 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];
-               }
+           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(&temp, &insn->common.addrsize,
-                   insn->common.mode_bits, ea->nosplit,
-                   insn->postop == X86_POSTOP_ADDRESS16, &displen, &eat.modrm,
-                   &eat.valid_modrm, &eat.need_modrm, &eat.sib,
-                   &eat.valid_sib, &eat.need_sib, &eat.pcrel, &insn->rex,
-                   calc_bc_dist)) {
-               case 1:
-                   yasm_expr_destroy(temp);
-                   /* failed, don't bother checking rest of insn */
-                   return YASM_BC_RESOLVE_UNKNOWN_LEN|YASM_BC_RESOLVE_ERROR;
-               case 2:
-                   yasm_expr_destroy(temp);
-                   /* failed, don't bother checking rest of insn */
-                   return YASM_BC_RESOLVE_UNKNOWN_LEN;
-               default:
-                   yasm_expr_destroy(temp);
-                   /* okay */
-                   break;
-           }
+       /* 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,
+               insn->common.mode_bits, insn->postop == X86_POSTOP_ADDRESS16,
+               &insn->rex, calc_bc_dist, bc->line)) {
+           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 (displen != 1) {
-               /* Fits into a word/dword, or unknown. */
-               retval = YASM_BC_RESOLVE_NONE;  /* may not be smallest size */
+       if (eat.ea.disp_len != 1) {
+           /* Fits into a word/dword, or unknown. */
+           retval = YASM_BC_RESOLVE_NONE;  /* may not be smallest size */
 
-               /* Handle unknown case, make displen word-sized */
-               if (displen == 0xff)
-                   displen = (insn->common.addrsize == 16) ? 2U : 4U;
-           }
+           /* Handle unknown case, make displen word-sized */
+           if (eat.ea.disp_len == 0xff)
+               eat.ea.disp_len = (insn->common.addrsize == 16) ? 2U : 4U;
+       }
 
-           /* Handle address16 postop case */
-           if (insn->postop == X86_POSTOP_ADDRESS16)
-               insn->common.addrsize = 0;
+       /* 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 (ea->len != 0 && ea->len != displen)
-               ea->len = displen;
+       /* If we had forced ea->len but had to override, save it now */
+       if (x86_ea->ea.disp_len != 0 && x86_ea->ea.disp_len != eat.ea.disp_len)
+           x86_ea->ea.disp_len = eat.ea.disp_len;
 
-           if (save) {
-               *x86_ea = eat;  /* structure copy */
-               ea->len = displen;
-               if (displen == 0 && ea->disp) {
-                   yasm_expr_destroy(ea->disp);
-                   ea->disp = NULL;
-               }
+       if (save) {
+           eat.ea.disp.abs = x86_ea->ea.disp.abs; /* Copy back original */
+           *x86_ea = eat;      /* structure copy */
+           if (x86_ea->ea.disp_len == 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) + displen;
+       bc->len += eat.need_modrm + (eat.need_sib ? 1:0) + eat.ea.disp_len;
        bc->len += (eat.ea.segreg != 0) ? 1 : 0;
     }
 
     if (imm) {
-       const yasm_intnum *num;
+       /*@null@*/ yasm_expr *temp = NULL;
+       const yasm_intnum *num = NULL;
        unsigned int immlen = imm->len;
+       long val;
 
-       if (imm->val) {
-           temp = yasm_expr_copy(imm->val);
+       if (imm->val.abs) {
+           temp = yasm_expr_copy(imm->val.abs);
            assert(temp != NULL);
-
-           /* TODO: check imm->len vs. sized len from expr? */
-
            num = yasm_expr_get_intnum(&temp, calc_bc_dist);
+       }
 
-           switch (insn->postop) {
-               case X86_POSTOP_SIGNEXT_IMM8:
-                   /* Handle signext_imm8 postop special-casing */
-                   if (num) {
-                       long 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.
-                            */
-                           immlen = 1;
-                           if (save) {
-                               /* Make the byte form permanent. */
-                               insn->opcode.opcode[0] = insn->opcode.opcode[1];
-                               imm->len = 1;
-                               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++;
+       /* TODO: check imm->len vs. sized len from expr? */
+
+       switch (insn->postop) {
+           case X86_POSTOP_SIGNEXT_IMM8:
+               /* Handle signext_imm8 postop special-casing */
+               if (imm->val.rel)
+                   val = 1000;     /* has relative portion, don't collapse */
+               else if (num)
+                   val = yasm_intnum_get_int(num);
+               else
+                   val = 0;
+               if (val >= -128 && val <= 127) {
+                   /* We can use the sign-extended byte form: shorten
+                    * the immediate length to 1.
+                    */
+                   immlen = 1;
+                   if (save) {
+                       /* Make the byte form permanent. */
+                       insn->opcode.opcode[0] = insn->opcode.opcode[1];
+                       imm->len = 1;
+                       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;
+                   } 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 = 4;
-                       if (save) {
-                           /* Throwaway REX byte */
-                           unsigned char rex_temp = 0;
-
-                           /* Build ModRM EA - CAUTION: this depends on
-                            * opcode 0 being a mov instruction!
-                            */
-                           insn->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->len = 4;
-                       }
+           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 = 4;
+                   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->len = 4;
                    }
-                   /* Not really necessary, but saves confusion over it. */
-                   if (save)
-                       insn->postop = X86_POSTOP_NONE;
-                   break;
+               }
+               /* 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_expr_destroy(imm->val);
-                           yasm_xfree(imm);
-                           insn->imm = (yasm_immval *)NULL;
-                       }
-                   } else
-                       retval = YASM_BC_RESOLVE_NONE;  /* could still get ,1 */
+           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;
 
-                   /* Not really necessary, but saves confusion over it. */
-                   if (save)
-                       insn->postop = X86_POSTOP_NONE;
-                   break;
+                   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 */
 
-               default:
-                   break;
-           }
+               /* Not really necessary, but saves confusion over it. */
+               if (save)
+                   insn->postop = X86_POSTOP_NONE;
+               break;
 
-           yasm_expr_destroy(temp);
+           default:
+               break;
        }
 
+       yasm_expr_destroy(temp);
+
        bc->len += immlen;
     }
 
@@ -729,8 +698,10 @@ x86_bc_jmp_resolve(yasm_bytecode *bc, int save,
 {
     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;
-    /*@dependent@*/ /*@null@*/ const yasm_intnum *num;
+    /*@only@*/ yasm_intnum *num;
+    /*@dependent@*/ /*@null@*/ yasm_intnum *num2;
     long rel;
     unsigned char opersize;
     x86_jmp_opcode_sel jrtype = JMP_NONE;
@@ -747,31 +718,46 @@ x86_bc_jmp_resolve(yasm_bytecode *bc, int save,
            /* 1 byte relative displacement */
            jrtype = JMP_SHORT;
            if (save) {
-               temp = yasm_expr_copy(jmp->target);
-               temp = yasm_expr_create(YASM_EXPR_SUB, yasm_expr_expr(temp),
-                                       yasm_expr_sym(jmp->origin), bc->line);
-               num = yasm_expr_get_intnum(&temp, calc_bc_dist);
-               if (!num) {
-                   yasm__error(bc->line,
-                       N_("short jump target external or out of segment"));
-                   yasm_expr_destroy(temp);
+               /* does a short form exist? */
+               if (jmp->shortop.len == 0) {
+                   yasm__error(bc->line, N_("short jump does not exist"));
                    return YASM_BC_RESOLVE_ERROR | YASM_BC_RESOLVE_UNKNOWN_LEN;
-               } else {
-                   rel = yasm_intnum_get_int(num);
-                   rel -= jmp->shortop.len+1;
-                   yasm_expr_destroy(temp);
-                   /* does a short form exist? */
-                   if (jmp->shortop.len == 0) {
-                       yasm__error(bc->line, N_("short jump does not exist"));
-                       return YASM_BC_RESOLVE_ERROR |
-                           YASM_BC_RESOLVE_UNKNOWN_LEN;
-                   }
-                   /* short displacement must fit in -128 <= rel <= +127 */
-                   if (rel < -128 || rel > 127) {
-                       yasm__error(bc->line, N_("short jump out of range"));
+               }
+
+               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;
+               }
+
+               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(bc->line, N_("jump target too complex"));
                        return YASM_BC_RESOLVE_ERROR |
                            YASM_BC_RESOLVE_UNKNOWN_LEN;
                    }
+                   yasm_intnum_calc(num, YASM_EXPR_ADD, num2, bc->line);
+                   yasm_expr_destroy(temp);
+               }
+
+               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(bc->line, N_("short jump out of range"));
+                   return YASM_BC_RESOLVE_ERROR | YASM_BC_RESOLVE_UNKNOWN_LEN;
                }
            }
            break;
@@ -786,64 +772,51 @@ x86_bc_jmp_resolve(yasm_bytecode *bc, int save,
            }
            break;
        default:
-           temp = yasm_expr_copy(jmp->target);
+           /* 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;
+           }
 
            /* Try to find shortest displacement based on difference between
-            * target expr value and our (this bytecode's) offset.  Note this
-            * requires offset to be set BEFORE calling calc_len in order for
-            * this test to be valid.
+            * target expr value and origin offset.
             */
-           temp = yasm_expr_create(YASM_EXPR_SUB, yasm_expr_expr(temp),
-                                   yasm_expr_sym(jmp->origin), bc->line);
-           num = yasm_expr_get_intnum(&temp, calc_bc_dist);
-           if (num) {
-               rel = yasm_intnum_get_int(num);
-               rel -= jmp->shortop.len+1;
-               /* short displacement must fit within -128 <= rel <= +127 */
-               if (jmp->shortop.len != 0 && rel >= -128 && rel <= 127) {
-                   /* It fits into a short displacement. */
-                   jrtype = JMP_SHORT;
-               } else if (jmp->nearop.len != 0) {
-                   /* Near for now, but could get shorter in the future if
-                    * there's a short form available.
-                    */
-                   jrtype = JMP_NEAR;
-                   if (jmp->shortop.len != 0)
-                       retval = YASM_BC_RESOLVE_NONE;
-               } else {
-                   /* Doesn't fit into short, and there's no near opcode.
-                    * Error out if saving, otherwise just make it a short
-                    * (in the hopes that a short might make it possible for
-                    * it to actually be within short range).
-                    */
-                   if (save) {
-                       yasm__error(bc->line,
-                           N_("short jump out of range (near jump does not exist)"));
-                       return YASM_BC_RESOLVE_ERROR |
-                           YASM_BC_RESOLVE_UNKNOWN_LEN;
-                   }
-                   jrtype = JMP_SHORT;
+           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(bc->line, N_("jump target too complex"));
+                   return YASM_BC_RESOLVE_ERROR | YASM_BC_RESOLVE_UNKNOWN_LEN;
                }
+               yasm_intnum_calc(num, YASM_EXPR_ADD, num2, bc->line);
+               yasm_expr_destroy(temp);
+           }
+
+           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 {
-               /* It's unknown.  Thus, assume near displacement.  If a near
-                * opcode is not available, use a short opcode instead.
-                * If we're saving, error if a near opcode is not available.
+               /* Near for now, but could get shorter in the future as
+                * there's a short form available.
                 */
-               if (jmp->nearop.len != 0) {
-                   if (jmp->shortop.len != 0)
-                       retval = YASM_BC_RESOLVE_NONE;
-                   jrtype = JMP_NEAR;
-               } else {
-                   if (save) {
-                       yasm__error(bc->line,
-                           N_("short jump out of range (near jump does not exist)"));
-                       return YASM_BC_RESOLVE_ERROR |
-                           YASM_BC_RESOLVE_UNKNOWN_LEN;
-                   }
-                   jrtype = JMP_SHORT;
-               }
+               jrtype = JMP_NEAR;
+               retval = YASM_BC_RESOLVE_NONE;
            }
-           yasm_expr_destroy(temp);
            break;
     }
 
@@ -917,20 +890,19 @@ x86_opcode_tobytes(const x86_opcode *opcode, unsigned char **bufp)
 
 static int
 x86_bc_insn_tobytes(yasm_bytecode *bc, unsigned char **bufp, void *d,
-                   yasm_output_expr_func output_expr,
+                   yasm_output_value_func output_value,
                    /*@unused@*/ yasm_output_reloc_func output_reloc)
 {
     x86_insn *insn = (x86_insn *)bc->contents;
-    /*@null@*/ x86_effaddr *x86_ea = (x86_effaddr *)insn->ea;
-    /*@null@*/ yasm_effaddr *ea = &x86_ea->ea;
+    /*@null@*/ x86_effaddr *x86_ea = (x86_effaddr *)insn->x86_ea;
     yasm_immval *imm = insn->imm;
-    unsigned int i;
     unsigned char *bufp_orig = *bufp;
 
     /* Prefixes */
     if (insn->special_prefix != 0)
        YASM_WRITE_8(*bufp, insn->special_prefix);
-    x86_common_tobytes(&insn->common, bufp, ea ? (ea->segreg>>8) : 0);
+    x86_common_tobytes(&insn->common, bufp,
+                      x86_ea ? (x86_ea->ea.segreg>>8) : 0);
     if (insn->rex != 0xff) {
        if (insn->common.mode_bits == 64 && insn->common.opersize == 64 &&
            insn->def_opersize_64 != 64)
@@ -949,7 +921,7 @@ x86_bc_insn_tobytes(yasm_bytecode *bc, unsigned char **bufp, void *d,
     /* Effective address: ModR/M (if required), SIB (if required), and
      * displacement (if required).
      */
-    if (ea) {
+    if (x86_ea) {
        if (x86_ea->need_modrm) {
            if (!x86_ea->valid_modrm)
                yasm_internal_error(N_("invalid Mod/RM in x86 tobytes_insn"));
@@ -962,68 +934,51 @@ x86_bc_insn_tobytes(yasm_bytecode *bc, unsigned char **bufp, void *d,
            YASM_WRITE_8(*bufp, x86_ea->sib);
        }
 
-       if (ea->disp) {
+       if (x86_ea->ea.need_disp) {
            x86_effaddr eat = *x86_ea;  /* structure copy */
-           unsigned char displen = ea->len;
            unsigned char addrsize = insn->common.addrsize;
 
            eat.valid_modrm = 0;    /* force checkea to actually run */
 
-           /* 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(&ea->disp, &addrsize,
-                                      insn->common.mode_bits, ea->nosplit,
-                                      insn->postop == X86_POSTOP_ADDRESS16,
-                                      &displen, &eat.modrm, &eat.valid_modrm,
-                                      &eat.need_modrm, &eat.sib,
-                                      &eat.valid_sib, &eat.need_sib,
-                                      &eat.pcrel, &insn->rex,
-                                      yasm_common_calc_bc_dist))
-               yasm_internal_error(N_("checkea failed"));
-
-           if (ea->disp) {
-               if (eat.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(eat.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;
-               }
-               *bufp += ea->len;
-           } else {
-               /* 0 displacement, but we didn't know it before, so we have to
-                * write out 0 value.
+           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.
                 */
-               for (i=0; i<ea->len; i++)
-                   YASM_WRITE_8(*bufp, 0);
+               if (yasm_x86__expr_checkea
+                   (&eat, &addrsize, insn->common.mode_bits,
+                    insn->postop == X86_POSTOP_ADDRESS16, &insn->rex,
+                    yasm_common_calc_bc_dist, bc->line))
+                   yasm_internal_error(N_("checkea failed"));
+               x86_ea->ea.disp.abs = eat.ea.disp.abs;
            }
+
+           if (x86_ea->ea.disp.curpos_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, x86_ea->ea.disp_len,
+                            (size_t)(x86_ea->ea.disp_len*8), 0,
+                            (unsigned long)(*bufp-bufp_orig), bc, 1, d))
+               return 1;
+           *bufp += x86_ea->ea.disp_len;
        }
     }
 
     /* Immediate (if required) */
-    if (imm && imm->val) {
-       if (output_expr(&imm->val, *bufp, imm->len, (size_t)(imm->len*8), 0,
-                       (unsigned long)(*bufp-bufp_orig), bc, 0,
-                       imm->sign?-1:1, d))
+    if (imm) {
+       if (output_value(&imm->val, *bufp, imm->len, (size_t)(imm->len*8), 0,
+                        (unsigned long)(*bufp-bufp_orig), bc, imm->sign?-1:1,
+                        d))
            return 1;
        *bufp += imm->len;
     }
@@ -1033,14 +988,14 @@ x86_bc_insn_tobytes(yasm_bytecode *bc, unsigned char **bufp, void *d,
 
 static int
 x86_bc_jmp_tobytes(yasm_bytecode *bc, unsigned char **bufp, void *d,
-                  yasm_output_expr_func output_expr,
+                  yasm_output_value_func output_value,
                   /*@unused@*/ yasm_output_reloc_func output_reloc)
 {
     x86_jmp *jmp = (x86_jmp *)bc->contents;
     unsigned char opersize;
     unsigned int i;
     unsigned char *bufp_orig = *bufp;
-    /*@null@*/ yasm_expr *wrt;
+    /*@only@*/ yasm_intnum *delta;
 
     /* Prefixes */
     x86_common_tobytes(&jmp->common, bufp, 0);
@@ -1060,17 +1015,19 @@ x86_bc_jmp_tobytes(yasm_bytecode *bc, unsigned char **bufp, void *d,
            /* Opcode */
            x86_opcode_tobytes(&jmp->shortop, bufp);
 
-           /* Relative displacement */
-           wrt = yasm_expr_extract_wrt(&jmp->target);
-           jmp->target =
-               yasm_expr_create(YASM_EXPR_SUB, yasm_expr_expr(jmp->target),
-                                yasm_expr_sym(jmp->origin), bc->line);
-           if (wrt)
-               jmp->target = yasm_expr_create_tree(jmp->target,
-                                                   YASM_EXPR_WRT, wrt,
-                                                   bc->line);
-           if (output_expr(&jmp->target, *bufp, 1, 8, 0,
-                           (unsigned long)(*bufp-bufp_orig), bc, 1, -1, d))
+           /* Adjust relative displacement to end of bytecode */
+           delta = yasm_intnum_create_int(-(long)bc->len);
+           if (!jmp->target.abs)
+               jmp->target.abs = yasm_expr_create_ident(yasm_expr_int(delta),
+                                                        bc->line);
+           else
+               jmp->target.abs =
+                   yasm_expr_create(YASM_EXPR_ADD,
+                                    yasm_expr_expr(jmp->target.abs),
+                                    yasm_expr_int(delta), bc->line);
+
+           if (output_value(&jmp->target, *bufp, 1, 8, 0,
+                            (unsigned long)(*bufp-bufp_orig), bc, -1, d))
                return 1;
            *bufp += 1;
            break;
@@ -1085,18 +1042,21 @@ x86_bc_jmp_tobytes(yasm_bytecode *bc, unsigned char **bufp, void *d,
            /* Opcode */
            x86_opcode_tobytes(&jmp->nearop, bufp);
 
-           /* Relative displacement */
-           wrt = yasm_expr_extract_wrt(&jmp->target);
-           jmp->target =
-               yasm_expr_create(YASM_EXPR_SUB, yasm_expr_expr(jmp->target),
-                                yasm_expr_sym(jmp->origin), bc->line);
-           if (wrt)
-               jmp->target = yasm_expr_create_tree(jmp->target,
-                                                   YASM_EXPR_WRT, wrt,
-                                                   bc->line);
            i = (opersize == 16) ? 2 : 4;
-           if (output_expr(&jmp->target, *bufp, i, i*8, 0,
-                           (unsigned long)(*bufp-bufp_orig), bc, 1, -1, d))
+
+           /* Adjust relative displacement to end of bytecode */
+           delta = yasm_intnum_create_int(-(long)bc->len);
+           if (!jmp->target.abs)
+               jmp->target.abs = yasm_expr_create_ident(yasm_expr_int(delta),
+                                                        bc->line);
+           else
+               jmp->target.abs =
+                   yasm_expr_create(YASM_EXPR_ADD,
+                                    yasm_expr_expr(jmp->target.abs),
+                                    yasm_expr_int(delta), bc->line);
+
+           if (output_value(&jmp->target, *bufp, i, i*8, 0,
+                            (unsigned long)(*bufp-bufp_orig), bc, -1, d))
                return 1;
            *bufp += i;
            break;
@@ -1108,7 +1068,7 @@ x86_bc_jmp_tobytes(yasm_bytecode *bc, unsigned char **bufp, void *d,
 
 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,
                      /*@unused@*/ yasm_output_reloc_func output_reloc)
 {
     x86_jmpfar *jmpfar = (x86_jmpfar *)bc->contents;
@@ -1125,32 +1085,18 @@ x86_bc_jmpfar_tobytes(yasm_bytecode *bc, unsigned char **bufp, void *d,
 
     /* Absolute displacement: segment and offset */
     i = (opersize == 16) ? 2 : 4;
-    if (output_expr(&jmpfar->offset, *bufp, i, i*8, 0,
-                   (unsigned long)(*bufp-bufp_orig), bc, 0, 1, d))
+    if (output_value(&jmpfar->offset, *bufp, i, i*8, 0,
+                    (unsigned long)(*bufp-bufp_orig), bc, 1, d))
        return 1;
     *bufp += i;
-    if (output_expr(&jmpfar->segment, *bufp, 2, 2*8, 0,
-                   (unsigned long)(*bufp-bufp_orig), bc, 0, 1, d))
+    if (output_value(&jmpfar->segment, *bufp, 2, 2*8, 0,
+                    (unsigned long)(*bufp-bufp_orig), bc, 1, d))
        return 1;
     *bufp += 2;
 
     return 0;
 }
 
-int
-yasm_x86__intnum_fixup_rel(yasm_arch *arch, yasm_intnum *intn, size_t valsize,
-                          const yasm_bytecode *bc, unsigned long line)
-{
-    yasm_intnum *delta;
-    if (valsize != 8 && valsize != 16 && valsize != 32)
-       yasm_internal_error(
-           N_("tried to do PC-relative offset from invalid sized value"));
-    delta = yasm_intnum_create_uint(bc->len);
-    yasm_intnum_calc(intn, YASM_EXPR_SUB, delta, line);
-    yasm_intnum_destroy(delta);
-    return 0;
-}
-
 int
 yasm_x86__intnum_tobytes(yasm_arch *arch, const yasm_intnum *intn,
                         unsigned char *buf, size_t destsize, size_t valsize,
index 80810778f47b78f9cd1ab13cc7f0fd6225f232fd..f6c4673e2c6e610de7481856d9435cb0cecfc5af 100644 (file)
@@ -247,9 +247,9 @@ x86_expr_checkea_distcheck_reg(yasm_expr **ep, unsigned int bits)
  * 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 i;
@@ -257,14 +257,37 @@ x86_expr_checkea_getregusage(yasm_expr **ep, /*@null@*/ yasm_expr **wrt,
     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, calc_bc_dist, NULL,
-                               NULL, NULL);
-    if (*wrt)
-       *wrt = yasm_expr__level_tree(*wrt, 1, indexreg == 0, calc_bc_dist,
-                                    NULL, NULL, NULL);
+    *ep = yasm_expr__level_tree(*ep, 1, 1, indexreg == 0, calc_bc_dist, 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;
@@ -273,38 +296,14 @@ x86_expr_checkea_getregusage(yasm_expr **ep, /*@null@*/ yasm_expr **wrt,
            return 1;
        case 2:
            /* Need to simplify again */
-           *ep = yasm_expr__level_tree(*ep, 1, indexreg == 0, NULL, NULL,
-                                       NULL, NULL);
+           *ep = yasm_expr__level_tree(*ep, 1, 1, indexreg == 0, NULL, NULL,
+                                       NULL, NULL, NULL);
            e = *ep;
            break;
        default:
            break;
     }
 
-    if (*wrt && (*wrt)->op == YASM_EXPR_IDENT &&
-       (*wrt)->terms[0].type == YASM_EXPR_REG) {
-       /* Handle xx WRT rip. */
-       if (bits != 64)             /* only valid in 64-bit mode */
-           return 1;
-       reg = get_reg(&(*wrt)->terms[0], &regnum, data);
-       if (!reg || regnum != 16)   /* only accept rip */
-           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);
-
-       /* Drill down to next WRT and recurse if there was one. */
-       *wrt = yasm_expr_extract_wrt(ep);
-       if (*wrt)
-           return x86_expr_checkea_getregusage(ep, wrt, indexreg, pcrel,
-                                               bits, data, get_reg,
-                                               calc_bc_dist);
-    }
-
     switch (e->op) {
        case YASM_EXPR_ADD:
            /* Prescan for non-int multipliers against a reg.
@@ -409,17 +408,15 @@ x86_expr_checkea_getregusage(yasm_expr **ep, /*@null@*/ yasm_expr **wrt,
  */
 /*@-nullstate@*/
 static int
-x86_checkea_calc_displen(yasm_expr **ep, unsigned int wordsize, int noreg,
-                        int dispreq, unsigned char *displen,
-                        unsigned char *modrm, unsigned char *v_modrm)
+x86_checkea_calc_displen(x86_effaddr *x86_ea, unsigned int wordsize, int noreg,
+                        int dispreq, unsigned long line)
 {
-    yasm_expr *e = *ep;
-    const yasm_intnum *intn;
+    /*@null@*/ const yasm_intnum *intn = NULL;
     long dispval;
 
-    *v_modrm = 0;      /* default to not yet valid */
+    x86_ea->valid_modrm = 0;   /* default to not yet valid */
 
-    switch (*displen) {
+    switch (x86_ea->ea.disp_len) {
        case 0:
            break;
        /* If not 0, the displacement length was forced; set the Mod bits
@@ -428,36 +425,36 @@ x86_checkea_calc_displen(yasm_expr **ep, unsigned int wordsize, int noreg,
        case 1:
            /* Byte is not valid override in noreg case; fix it. */
            if (noreg) {
-               *displen = 0;
-               yasm__warning(YASM_WARN_GENERAL, e->line,
+               x86_ea->ea.disp_len = 0;
+               yasm__warning(YASM_WARN_GENERAL, line,
                              N_("invalid displacement size; fixed"));
            } else
-               *modrm |= 0100;
-           *v_modrm = 1;
+               x86_ea->modrm |= 0100;
+           x86_ea->valid_modrm = 1;
            break;
        case 2:
        case 4:
-           if (wordsize != *displen) {
-               yasm__error(e->line,
+           if (wordsize != x86_ea->ea.disp_len) {
+               yasm__error(line,
                    N_("invalid effective address (displacement size)"));
                return 1;
            }
            /* 2/4 is not valid override in noreg case; fix it. */
            if (noreg) {
-               if (wordsize != *displen)
-                   yasm__warning(YASM_WARN_GENERAL, e->line,
+               if (wordsize != x86_ea->ea.disp_len)
+                   yasm__warning(YASM_WARN_GENERAL, line,
                                  N_("invalid displacement size; fixed"));
-               *displen = 0;
+               x86_ea->ea.disp_len = 0;
            } else
-               *modrm |= 0200;
-           *v_modrm = 1;
+               x86_ea->modrm |= 0200;
+           x86_ea->valid_modrm = 1;
            break;
        default:
            /* we shouldn't ever get any other size! */
            yasm_internal_error(N_("strange EA displacement size"));
     }
 
-    if (*displen == 0) {
+    if (x86_ea->ea.disp_len == 0) {
        /* the displacement length hasn't been forced (or the forcing wasn't
         * valid), try to determine what it is.
         */
@@ -466,8 +463,8 @@ x86_checkea_calc_displen(yasm_expr **ep, unsigned int wordsize, int noreg,
             * and as the Mod bits are set to 0 by the caller, we're done
             * with the ModRM byte.
             */
-           *displen = wordsize;
-           *v_modrm = 1;
+           x86_ea->ea.disp_len = wordsize;
+           x86_ea->valid_modrm = 1;
            return 0;
        } else if (dispreq) {
            /* for BP/EBP, there *must* be a displacement value, but we
@@ -475,55 +472,62 @@ x86_checkea_calc_displen(yasm_expr **ep, unsigned int wordsize, int noreg,
             * We can't leave displen at 0, because that just means
             * unknown displacement, including none.
             */
-           *displen = 0xff;
+           x86_ea->ea.disp_len = 0xff;
        }
 
-       intn = yasm_expr_get_intnum(ep, NULL);
-       if (!intn) {
-           /* expr still has unknown values: assume 16/32-bit disp */
-           *displen = wordsize;
-           *modrm |= 0200;
-           *v_modrm = 1;
+       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
+            */
+           x86_ea->ea.disp_len = 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 (*displen != 0 && *displen != 0xff) {
-           if (*displen == 1)
-               *modrm |= 0100;
+       if (x86_ea->ea.disp_len != 0 && x86_ea->ea.disp_len != 0xff) {
+           if (x86_ea->ea.disp_len == 1)
+               x86_ea->modrm |= 0100;
            else
-               *modrm |= 0200;
-           *v_modrm = 1;
+               x86_ea->modrm |= 0200;
+           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 (*displen != 0xff && dispval == 0) {
+       if (x86_ea->ea.disp_len != 0xff && 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_len = 1;
+           x86_ea->modrm |= 0100;
        } else {
            /* It's a 16/32-bit displacement */
-           *displen = wordsize;
-           *modrm |= 0200;
+           x86_ea->ea.disp_len = 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;
@@ -556,29 +560,19 @@ x86_expr_checkea_getregsize_callback(yasm_expr__item *ei, void *d)
 }
 
 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_calc_bc_dist_func calc_bc_dist)
+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 long line)
 {
-    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
         * - what registers are used in the expression
         * - the bits setting
         */
-       switch (*displen) {
+       switch (x86_ea->ea.disp_len) {
            case 2:
                /* must be 16-bit */
                *addrsize = 16;
@@ -587,8 +581,8 @@ yasm_x86__expr_checkea(yasm_expr **ep, unsigned char *addrsize,
                /* We have to support this for the MemOffs case, but it's
                 * otherwise illegal.  It's also illegal in non-64-bit mode.
                 */
-               if (*n_modrm || *n_sib) {
-                   yasm__error(e->line,
+               if (x86_ea->need_modrm || x86_ea->need_sib) {
+                   yasm__error(line,
                        N_("invalid effective address (displacement size)"));
                    return 1;
                }
@@ -599,7 +593,7 @@ yasm_x86__expr_checkea(yasm_expr **ep, unsigned char *addrsize,
                 * we don't know unless we look at the registers, except in the
                 * MemOffs case (see the end of this function).
                 */
-               if (bits != 64 || (!*n_modrm && !*n_sib)) {
+               if (bits != 64 || (!x86_ea->need_modrm && !x86_ea->need_sib)) {
                    *addrsize = 32;
                    break;
                }
@@ -608,8 +602,9 @@ yasm_x86__expr_checkea(yasm_expr **ep, unsigned char *addrsize,
                /* check for use of 16 or 32-bit registers; if none are used
                 * default to bits setting.
                 */
-               if (!yasm_expr__traverse_leaves_in(e, addrsize,
-                       x86_expr_checkea_getregsize_callback))
+               if (!x86_ea->ea.disp.abs ||
+                   !yasm_expr__traverse_leaves_in(x86_ea->ea.disp.abs,
+                       addrsize, x86_expr_checkea_getregsize_callback))
                    *addrsize = bits;
                /* TODO: Add optional warning here if switched address size
                 * from bits setting just by register use.. eg [ax] in
@@ -619,7 +614,8 @@ yasm_x86__expr_checkea(yasm_expr **ep, unsigned char *addrsize,
     }
 
     if ((*addrsize == 32 || *addrsize == 64) &&
-       ((*n_modrm && !*v_modrm) || (*n_sib && !*v_sib))) {
+       ((x86_ea->need_modrm && !x86_ea->valid_modrm) ||
+        (x86_ea->need_sib && !x86_ea->valid_sib))) {
        int i;
        unsigned char low3;
        typedef enum {
@@ -650,7 +646,7 @@ yasm_x86__expr_checkea(yasm_expr **ep, unsigned char *addrsize,
 
        /* We can only do 64-bit addresses in 64-bit mode. */
        if (*addrsize == 64 && bits != 64) {
-           yasm__error(e->line,
+           yasm__error(line,
                N_("invalid effective address (64-bit in non-64-bit mode)"));
            return 1;
        }
@@ -658,22 +654,24 @@ yasm_x86__expr_checkea(yasm_expr **ep, unsigned char *addrsize,
        reg3264_data.regs = reg3264mult;
        reg3264_data.bits = bits;
        reg3264_data.addrsize = *addrsize;
-       switch (x86_expr_checkea_getregusage(ep, &wrt, &indexreg, pcrel, bits,
-                                            &reg3264_data,
-                                            x86_expr_checkea_get_reg3264,
-                                            calc_bc_dist)) {
-           case 1:
-               e = *ep;
-               yasm__error(e->line, N_("invalid effective address"));
-               return 1;
-           case 2:
-               if (wrt)
-                   *ep = yasm_expr_create_tree(*ep, YASM_EXPR_WRT, wrt,
-                                               (*ep)->line);
-               return 2;
-           default:
-               e = *ep;
-               break;
+       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)) {
+               case 1:
+                   yasm__error(line, N_("invalid effective address"));
+                   return 1;
+               case 2:
+                   if (pcrel)
+                       x86_ea->ea.disp.curpos_rel = 1;
+                   return 2;
+               default:
+                   if (pcrel)
+                       x86_ea->ea.disp.curpos_rel = 1;
+                   break;
+           }
        }
 
        /* If indexreg mult is 0, discard it.
@@ -689,7 +687,7 @@ yasm_x86__expr_checkea(yasm_expr **ep, unsigned char *addrsize,
         */
        for (i=0; i<17; i++) {
            if (reg3264mult[i] < 0) {
-               yasm__error(e->line, N_("invalid effective address"));
+               yasm__error(line, N_("invalid effective address"));
                return 1;
            }
            if (i != indexreg && reg3264mult[i] == 1 &&
@@ -706,14 +704,14 @@ yasm_x86__expr_checkea(yasm_expr **ep, unsigned char *addrsize,
            switch (reg3264mult[indexreg]) {
                case 1:
                    /* Only optimize this way if nosplit wasn't specified */
-                   if (!nosplit) {
+                   if (!x86_ea->ea.nosplit) {
                        basereg = indexreg;
                        indexreg = -1;
                    }
                    break;
                case 2:
                    /* Only split if nosplit wasn't specified */
-                   if (!nosplit) {
+                   if (!x86_ea->ea.nosplit) {
                        basereg = indexreg;
                        reg3264mult[indexreg] = 1;
                    }
@@ -731,7 +729,7 @@ yasm_x86__expr_checkea(yasm_expr **ep, unsigned char *addrsize,
         */
        for (i=0; i<17; i++)
            if (i != basereg && i != indexreg && reg3264mult[i] != 0) {
-               yasm__error(e->line, N_("invalid effective address"));
+               yasm__error(line, N_("invalid effective address"));
                return 1;
            }
 
@@ -739,7 +737,7 @@ yasm_x86__expr_checkea(yasm_expr **ep, unsigned char *addrsize,
        if (indexreg != REG3264_NONE && reg3264mult[indexreg] != 1 &&
            reg3264mult[indexreg] != 2 && reg3264mult[indexreg] != 4 &&
            reg3264mult[indexreg] != 8) {
-           yasm__error(e->line, N_("invalid effective address"));
+           yasm__error(line, N_("invalid effective address"));
            return 1;
        }
 
@@ -749,7 +747,7 @@ yasm_x86__expr_checkea(yasm_expr **ep, unsigned char *addrsize,
             * legal.
             */
            if (reg3264mult[REG3264_ESP] > 1 || basereg == REG3264_ESP) {
-               yasm__error(e->line, N_("invalid effective address"));
+               yasm__error(line, N_("invalid effective address"));
                return 1;
            }
            /* If mult==1 and basereg is not ESP, swap indexreg w/basereg. */
@@ -760,7 +758,7 @@ yasm_x86__expr_checkea(yasm_expr **ep, unsigned char *addrsize,
        /* RIP is only legal if it's the ONLY register used. */
        if (indexreg == REG64_RIP ||
            (basereg == REG64_RIP && indexreg != REG3264_NONE)) {
-           yasm__error(e->line, N_("invalid effective address"));
+           yasm__error(line, N_("invalid effective address"));
            return 1;
        }
 
@@ -770,31 +768,28 @@ yasm_x86__expr_checkea(yasm_expr **ep, unsigned char *addrsize,
         */
 
        /* First determine R/M (Mod is later determined from disp size) */
-       *n_modrm = 1;   /* we always need ModRM */
+       x86_ea->need_modrm = 1; /* we always need ModRM */
        if (basereg == REG3264_NONE && indexreg == REG3264_NONE) {
            /* Just a disp32: in 64-bit mode the RM encoding is used for RIP
             * offset addressing, so we need to use the SIB form instead.
             */
            if (bits == 64) {
-               *modrm |= 4;
-               *n_sib = 1;
+               x86_ea->modrm |= 4;
+               x86_ea->need_sib = 1;
            } else {
-               *modrm |= 5;
-               *sib = 0;
-               *v_sib = 0;
-               *n_sib = 0;
+               x86_ea->modrm |= 5;
+               x86_ea->sib = 0;
+               x86_ea->valid_sib = 0;
+               x86_ea->need_sib = 0;
            }
        } else if (basereg == REG64_RIP) {
-           *modrm |= 5;
-           *sib = 0;
-           *v_sib = 0;
-           *n_sib = 0;
+           x86_ea->modrm |= 5;
+           x86_ea->sib = 0;
+           x86_ea->valid_sib = 0;
+           x86_ea->need_sib = 0;
            /* RIP always requires a 32-bit displacement */
-           *v_modrm = 1;
-           *displen = 4;
-           if (wrt)
-               *ep = yasm_expr_create_tree(*ep, YASM_EXPR_WRT, wrt,
-                                           (*ep)->line);
+           x86_ea->valid_modrm = 1;
+           x86_ea->ea.disp_len = 4;
            return 0;
        } else if (indexreg == REG3264_NONE) {
            /* basereg only */
@@ -805,81 +800,79 @@ yasm_x86__expr_checkea(yasm_expr **ep, unsigned char *addrsize,
            if (yasm_x86__set_rex_from_reg(rex, &low3,
                                           (unsigned int)(X86_REG64 | basereg),
                                           bits, X86_REX_B)) {
-               yasm__error(e->line,
+               yasm__error(line,
                    N_("invalid combination of operands and effective address"));
                return 1;
            }
-           *modrm |= low3;
+           x86_ea->modrm |= low3;
            /* we don't need an SIB *unless* basereg is ESP or R12 */
            if (basereg == REG3264_ESP || basereg == REG64_R12)
-               *n_sib = 1;
+               x86_ea->need_sib = 1;
            else {
-               *sib = 0;
-               *v_sib = 0;
-               *n_sib = 0;
+               x86_ea->sib = 0;
+               x86_ea->valid_sib = 0;
+               x86_ea->need_sib = 0;
            }
        } else {
            /* index or both base and index */
-           *modrm |= 4;
-           *n_sib = 1;
+           x86_ea->modrm |= 4;
+           x86_ea->need_sib = 1;
        }
 
        /* Determine SIB if needed */
-       if (*n_sib == 1) {
-           *sib = 0;   /* start with 0 */
+       if (x86_ea->need_sib == 1) {
+           x86_ea->sib = 0;    /* start with 0 */
 
            /* Special case: no basereg */
            if (basereg == REG3264_NONE)
-               *sib |= 5;
+               x86_ea->sib |= 5;
            else {
                if (yasm_x86__set_rex_from_reg(rex, &low3, (unsigned int)
                                               (X86_REG64 | basereg), bits,
                                               X86_REX_B)) {
-                   yasm__error(e->line,
+                   yasm__error(line,
                        N_("invalid combination of operands and effective address"));
                    return 1;
                }
-               *sib |= low3;
+               x86_ea->sib |= low3;
            }
            
            /* Put in indexreg, checking for none case */
            if (indexreg == REG3264_NONE)
-               *sib |= 040;
+               x86_ea->sib |= 040;
                /* Any scale field is valid, just leave at 0. */
            else {
                if (yasm_x86__set_rex_from_reg(rex, &low3, (unsigned int)
                                               (X86_REG64 | indexreg), bits,
                                               X86_REX_X)) {
-                   yasm__error(e->line,
+                   yasm__error(line,
                        N_("invalid combination of operands and effective address"));
                    return 1;
                }
-               *sib |= low3 << 3;
+               x86_ea->sib |= low3 << 3;
                /* Set scale field, 1 case -> 0, so don't bother. */
                switch (reg3264mult[indexreg]) {
                    case 2:
-                       *sib |= 0100;
+                       x86_ea->sib |= 0100;
                        break;
                    case 4:
-                       *sib |= 0200;
+                       x86_ea->sib |= 0200;
                        break;
                    case 8:
-                       *sib |= 0300;
+                       x86_ea->sib |= 0300;
                        break;
                }
            }
 
-           *v_sib = 1; /* Done with SIB */
+           x86_ea->valid_sib = 1;      /* Done with SIB */
        }
 
        /* Calculate displacement length (if possible) */
-       retval = x86_checkea_calc_displen(ep, 4, basereg == REG3264_NONE,
-           basereg == REG3264_EBP || basereg == REG64_R13, displen, modrm,
-           v_modrm);
-       if (wrt)
-           *ep = yasm_expr_create_tree(*ep, YASM_EXPR_WRT, wrt, (*ep)->line);
+       retval = x86_checkea_calc_displen
+           (x86_ea, 4, basereg == REG3264_NONE,
+            basereg == REG3264_EBP || basereg == REG64_R13, line);
        return retval;
-    } else if (*addrsize == 16 && *n_modrm && !*v_modrm) {
+    } else if (*addrsize == 16 && x86_ea->need_modrm && !x86_ea->valid_modrm) {
        static const unsigned char modrm16[16] = {
            0006 /* disp16  */, 0007 /* [BX]    */, 0004 /* [SI]    */,
            0000 /* [BX+SI] */, 0005 /* [DI]    */, 0001 /* [BX+DI] */,
@@ -899,38 +892,39 @@ yasm_x86__expr_checkea(yasm_expr **ep, unsigned char *addrsize,
 
        /* 64-bit mode does not allow 16-bit addresses */
        if (bits == 64 && !address16_op) {
-           yasm__error(e->line,
+           yasm__error(line,
                N_("16-bit addresses not supported in 64-bit mode"));
            return 1;
        }
 
        /* 16-bit cannot have SIB */
-       *sib = 0;
-       *v_sib = 0;
-       *n_sib = 0;
-
-       switch (x86_expr_checkea_getregusage(ep, &wrt, (int *)NULL, pcrel,
-                                            bits, &reg16mult,
-                                            x86_expr_checkea_get_reg16,
-                                            calc_bc_dist)) {
-           case 1:
-               e = *ep;
-               yasm__error(e->line, N_("invalid effective address"));
-               return 1;
-           case 2:
-               if (wrt)
-                   *ep = yasm_expr_create_tree(*ep, YASM_EXPR_WRT, wrt,
-                                               (*ep)->line);
-               return 2;
-           default:
-               e = *ep;
-               break;
+       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)) {
+               case 1:
+                   yasm__error(line, N_("invalid effective address"));
+                   return 1;
+               case 2:
+                   if (pcrel)
+                       x86_ea->ea.disp.curpos_rel = 1;
+                   return 2;
+               default:
+                   if (pcrel)
+                       x86_ea->ea.disp.curpos_rel = 1;
+                   break;
+           }
        }
 
        /* reg multipliers not 0 or 1 are illegal. */
        if (reg16mult.bx & ~1 || reg16mult.si & ~1 || reg16mult.di & ~1 ||
            reg16mult.bp & ~1) {
-           yasm__error(e->line, N_("invalid effective address"));
+           yasm__error(line, N_("invalid effective address"));
            return 1;
        }
 
@@ -946,47 +940,42 @@ yasm_x86__expr_checkea(yasm_expr **ep, unsigned char *addrsize,
 
        /* Check the modrm value for invalid combinations. */
        if (modrm16[havereg] & 0070) {
-           yasm__error(e->line, N_("invalid effective address"));
+           yasm__error(line, N_("invalid effective address"));
            return 1;
        }
 
        /* Set ModRM byte for registers */
-       *modrm |= modrm16[havereg];
+       x86_ea->modrm |= modrm16[havereg];
 
        /* Calculate displacement length (if possible) */
-       retval = x86_checkea_calc_displen(ep, 2, havereg == HAVE_NONE,
-                                         havereg == HAVE_BP, displen, modrm,
-                                         v_modrm);
-       if (wrt)
-           *ep = yasm_expr_create_tree(*ep, YASM_EXPR_WRT, wrt, (*ep)->line);
+       retval = x86_checkea_calc_displen
+           (x86_ea, 2, havereg == HAVE_NONE, havereg == HAVE_BP, line);
        return retval;
-    } else if (!*n_modrm && !*n_sib) {
+    } else if (!x86_ea->need_modrm && !x86_ea->need_sib) {
        /* Special case for MOV MemOffs opcode: displacement but no modrm. */
        switch (*addrsize) {
            case 64:
                if (bits != 64) {
-                   yasm__error(e->line,
+                   yasm__error(line,
                        N_("invalid effective address (64-bit in non-64-bit mode)"));
                    return 1;
                }
-               *displen = 8;
+               x86_ea->ea.disp_len = 8;
                break;
            case 32:
-               *displen = 4;
+               x86_ea->ea.disp_len = 4;
                break;
            case 16:
                /* 64-bit mode does not allow 16-bit addresses */
                if (bits == 64 && !address16_op) {
-                   yasm__error(e->line,
+                   yasm__error(line,
                        N_("16-bit addresses not supported in 64-bit mode"));
                    return 1;
                }
-               *displen = 2;
+               x86_ea->ea.disp_len = 2;
                break;
        }
     }
-    if (wrt)
-       *ep = yasm_expr_create_tree(*ep, YASM_EXPR_WRT, wrt, (*ep)->line);
     return 0;
 }
 
index 1b374a4928ca124de34a2851e22d3020a3a5311a..c375e570cc400d3ebd42aaebb587c1c2bff69d73 100644 (file)
@@ -2050,6 +2050,7 @@ x86_finalize_jmpfar(yasm_arch *arch, yasm_bytecode *bc,
 {
     x86_jmpfar *jmpfar;
     yasm_insn_operand *op;
+    /*@only@*/ yasm_expr *segment;
 
     jmpfar = yasm_xmalloc(sizeof(x86_jmpfar));
     x86_finalize_common(&jmpfar->common, info, data[3]);
@@ -2060,16 +2061,21 @@ x86_finalize_jmpfar(yasm_arch *arch, yasm_bytecode *bc,
     switch (op->targetmod) {
        case X86_FAR:
            /* "FAR imm" target needs to become "seg imm:imm". */
-           jmpfar->offset = yasm_expr_copy(op->data.val);
-           jmpfar->segment = yasm_expr_create_branch(YASM_EXPR_SEG,
-                                                     op->data.val, bc->line);
+           if (yasm_value_finalize_expr(&jmpfar->offset,
+                                        yasm_expr_copy(op->data.val))
+               || yasm_value_finalize_expr(&jmpfar->segment, op->data.val))
+               yasm__error(bc->line, N_("jump target expression too complex"));
+           jmpfar->segment.seg_of = 1;
            break;
        case X86_FAR_SEGOFF:
            /* SEG:OFF expression; split it. */
-           jmpfar->offset = op->data.val;
-           jmpfar->segment = yasm_expr_extract_segoff(&jmpfar->offset);
-           if (!jmpfar->segment)
+           segment = yasm_expr_extract_segoff(&op->data.val);
+           if (!segment)
                yasm_internal_error(N_("didn't get SEG:OFF expression in jmpfar"));
+           if (yasm_value_finalize_expr(&jmpfar->segment, segment))
+               yasm__error(bc->line, N_("jump target segment too complex"));
+           if (yasm_value_finalize_expr(&jmpfar->offset, op->data.val))
+               yasm__error(bc->line, N_("jump target offset too complex"));
            break;
        default:
            yasm_internal_error(N_("didn't get FAR expression in jmpfar"));
@@ -2105,10 +2111,14 @@ x86_finalize_jmp(yasm_arch *arch, yasm_bytecode *bc, yasm_bytecode *prev_bc,
 
     jmp = yasm_xmalloc(sizeof(x86_jmp));
     x86_finalize_common(&jmp->common, jinfo, mode_bits);
-    jmp->target = op->data.val;
+    if (yasm_value_finalize_expr(&jmp->target, op->data.val))
+       yasm__error(bc->line, N_("jump target expression too complex"));
+    if (jmp->target.seg_of || jmp->target.rshift || jmp->target.curpos_rel)
+       yasm__error(bc->line, N_("invalid jump target"));
+    jmp->target.curpos_rel = 1;
 
     /* Need to save jump origin for relative jumps. */
-    jmp->origin = yasm_symtab_define_label2("$", prev_bc, 0, bc->line);
+    jmp->origin_prevbc = prev_bc;
 
     /* See if the user explicitly specified short/near/far. */
     switch ((int)(jinfo->operands[0] & OPTM_MASK)) {
@@ -2180,6 +2190,13 @@ x86_finalize_jmp(yasm_arch *arch, yasm_bytecode *bc, yasm_bytecode *prev_bc,
        yasm__error(bc->line,
                    N_("no NEAR form of that jump instruction exists"));
 
+    if (jmp->op_sel == JMP_NONE) {
+       if (jmp->nearop.len == 0)
+           jmp->op_sel = JMP_SHORT_FORCED;
+       if (jmp->shortop.len == 0)
+           jmp->op_sel = JMP_NEAR_FORCED;
+    }
+
     yasm_x86__bc_apply_prefixes((x86_common *)jmp, NULL, num_prefixes,
                                prefixes, bc->line);
 
@@ -2204,7 +2221,6 @@ yasm_x86__finalize_insn(yasm_arch *arch, yasm_bytecode *bc,
     unsigned long suffix = (data[3]>>8) & 0xFF;
     int found = 0;
     yasm_insn_operand *op, *ops[4], *rev_ops[4], **use_ops;
-    /*@null@*/ yasm_symrec *origin;
     /*@null@*/ yasm_expr *imm;
     unsigned char im_len;
     unsigned char im_sign;
@@ -2262,7 +2278,8 @@ yasm_x86__finalize_insn(yasm_arch *arch, yasm_bytecode *bc,
                if (op->data.ea->segreg != 0)
                    yasm__warning(YASM_WARN_GENERAL, bc->line,
                                  N_("skipping prefixes on this instruction"));
-               imm = yasm_expr_copy(op->data.ea->disp);
+               imm = op->data.ea->disp.abs;
+               op->data.ea->disp.abs = NULL;
                yasm_ea_destroy(op->data.ea);
                op->type = YASM_INSN__OPERAND_IMM;
                op->data.val = imm;
@@ -2529,9 +2546,9 @@ yasm_x86__finalize_insn(yasm_arch *arch, yasm_bytecode *bc,
            /* Check for 64-bit effective address size */
            if (op->type == YASM_INSN__OPERAND_MEMORY) {
                if ((info->operands[i] & OPEAS_MASK) == OPEAS_64) {
-                   if (op->data.ea->len != 8)
+                   if (op->data.ea->disp_len != 8)
                        mismatch = 1;
-               } else if (op->data.ea->len == 8)
+               } else if (op->data.ea->disp_len == 8)
                    mismatch = 1;
            }
 
@@ -2627,8 +2644,7 @@ yasm_x86__finalize_insn(yasm_arch *arch, yasm_bytecode *bc,
     insn = yasm_xmalloc(sizeof(x86_insn));
     x86_finalize_common(&insn->common, info, mode_bits);
     x86_finalize_opcode(&insn->opcode, info);
-    insn->ea = NULL;
-    origin = NULL;
+    insn->x86_ea = NULL;
     imm = NULL;
     insn->def_opersize_64 = info->def_opersize_64;
     insn->special_prefix = info->special_prefix;
@@ -2706,7 +2722,7 @@ yasm_x86__finalize_insn(yasm_arch *arch, yasm_bytecode *bc,
                case OPA_EA:
                    switch (op->type) {
                        case YASM_INSN__OPERAND_REG:
-                           insn->ea =
+                           insn->x86_ea =
                                yasm_x86__ea_create_reg(op->data.reg,
                                                        &insn->rex,
                                                        mode_bits);
@@ -2715,20 +2731,16 @@ yasm_x86__finalize_insn(yasm_arch *arch, yasm_bytecode *bc,
                            yasm_internal_error(
                                N_("invalid operand conversion"));
                        case YASM_INSN__OPERAND_MEMORY:
-                           insn->ea = op->data.ea;
+                           insn->x86_ea = (x86_effaddr *)op->data.ea;
                            if ((info->operands[i] & OPT_MASK) == OPT_MemOffs)
                                /* Special-case for MOV MemOffs instruction */
-                               yasm_x86__ea_set_disponly(insn->ea);
-                           else if (mode_bits == 64)
-                               /* Save origin for possible RIP-relative */
-                               origin =
-                                   yasm_symtab_define_label2("$", prev_bc, 0,
-                                                             bc->line);
+                               yasm_x86__ea_set_disponly(insn->x86_ea);
                            break;
                        case YASM_INSN__OPERAND_IMM:
-                           insn->ea = yasm_x86__ea_create_imm(op->data.val,
-                               size_lookup[(info->operands[i] &
-                                            OPS_MASK)>>OPS_SHIFT]);
+                           insn->x86_ea =
+                               yasm_x86__ea_create_imm(op->data.val,
+                                   size_lookup[(info->operands[i] &
+                                               OPS_MASK)>>OPS_SHIFT]);
                            break;
                    }
                    break;
@@ -2790,16 +2802,16 @@ yasm_x86__finalize_insn(yasm_arch *arch, yasm_bytecode *bc,
                    break;
                case OPA_SpareEA:
                    if (op->type == YASM_INSN__OPERAND_REG) {
-                       insn->ea = yasm_x86__ea_create_reg(op->data.reg,
-                                                          &insn->rex,
-                                                          mode_bits);
-                       if (!insn->ea ||
+                       insn->x86_ea = yasm_x86__ea_create_reg(op->data.reg,
+                                                              &insn->rex,
+                                                              mode_bits);
+                       if (!insn->x86_ea ||
                            yasm_x86__set_rex_from_reg(&insn->rex, &spare,
                                op->data.reg, mode_bits, X86_REX_R)) {
                            yasm__error(bc->line,
                                N_("invalid combination of opcode and operands"));
-                           if (insn->ea)
-                               yasm_xfree(insn->ea);
+                           if (insn->x86_ea)
+                               yasm_xfree(insn->x86_ea);
                            yasm_xfree(insn);
                            return;
                        }
@@ -2838,10 +2850,10 @@ yasm_x86__finalize_insn(yasm_arch *arch, yasm_bytecode *bc,
        }
     }
 
-    if (insn->ea) {
-       yasm_x86__ea_init(insn->ea, spare, origin);
+    if (insn->x86_ea) {
+       yasm_x86__ea_init(insn->x86_ea, spare, bc->line);
        for (i=0; i<num_segregs; i++)
-           yasm_ea_set_segreg(insn->ea, segregs[i], bc->line);
+           yasm_ea_set_segreg(&insn->x86_ea->ea, segregs[i], bc->line);
     } else if (num_segregs > 0 && insn->special_prefix == 0) {
        if (num_segregs > 1)
            yasm__warning(YASM_WARN_GENERAL, bc->line,
index af39fb606a63150ea679e6ebca96bc15460f47d9..ea21be62eb0c35fffaa53ebc39d66f5aad781790 100644 (file)
@@ -37,7 +37,7 @@ struct dwarf2_head {
     yasm_dbgfmt_dwarf2 *dbgfmt_dwarf2;
     yasm_bytecode *start_prevbc;
     yasm_bytecode *end_prevbc;
-    /*@null@*/ yasm_expr *debug_ptr;
+    /*@null@*/ yasm_symrec *debug_ptr;
     int with_address;
     int with_segment;
 };
@@ -50,7 +50,7 @@ static yasm_bc_resolve_flags dwarf2_head_bc_resolve
     (yasm_bytecode *bc, int save, yasm_calc_bc_dist_func calc_bc_dist);
 static int dwarf2_head_bc_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);
 
 /* Bytecode callback structures */
@@ -180,7 +180,7 @@ dwarf2_dbgfmt_generate(yasm_dbgfmt *dbgfmt)
     }
 }
 
-yasm_expr *
+yasm_symrec *
 yasm_dwarf2__bc_sym(yasm_symtab *symtab, yasm_bytecode *bc)
 {
     /*@dependent@*/ yasm_symrec *sym;
@@ -188,7 +188,7 @@ yasm_dwarf2__bc_sym(yasm_symtab *symtab, yasm_bytecode *bc)
        sym = bc->symrecs[0];
     else
        sym = yasm_symtab_define_label(symtab, ".bcsym", bc, 0, 0);
-    return yasm_expr_create_ident(yasm_expr_sym(sym), 0);
+    return sym;
 }
 
 dwarf2_head *
@@ -238,8 +238,6 @@ static void
 dwarf2_head_bc_destroy(void *contents)
 {
     dwarf2_head *head = (dwarf2_head *)contents;
-    if (head->debug_ptr)
-       yasm_expr_destroy(head->debug_ptr);
     yasm_xfree(contents);
 }
 
@@ -260,7 +258,7 @@ dwarf2_head_bc_resolve(yasm_bytecode *bc, int save,
 
 static int
 dwarf2_head_bc_tobytes(yasm_bytecode *bc, unsigned char **bufp, void *d,
-                      yasm_output_expr_func output_expr,
+                      yasm_output_value_func output_value,
                       yasm_output_reloc_func output_reloc)
 {
     dwarf2_head *head = (dwarf2_head *)bc->contents;
@@ -293,9 +291,11 @@ dwarf2_head_bc_tobytes(yasm_bytecode *bc, unsigned char **bufp, void *d,
 
     /* Pointer to another debug section */
     if (head->debug_ptr) {
-       output_expr(&head->debug_ptr, buf, dbgfmt_dwarf2->sizeof_offset,
-                   dbgfmt_dwarf2->sizeof_offset*8, 0,
-                   (unsigned long)(buf-*bufp), bc, 0, 0, d);
+       yasm_value value;
+       yasm_value_init_sym(&value, head->debug_ptr);
+       output_value(&value, buf, dbgfmt_dwarf2->sizeof_offset,
+                    dbgfmt_dwarf2->sizeof_offset*8, 0,
+                    (unsigned long)(buf-*bufp), bc, 0, d);
        buf += dbgfmt_dwarf2->sizeof_offset;
     }
 
index 1874298d77d8719eb18634c32545dc699272fce6..5de6cca64db005b6ca722d56b819d043c7671e69 100644 (file)
@@ -98,8 +98,8 @@ extern const yasm_assoc_data_callback yasm_dwarf2__section_data_cb;
 
 yasm_bytecode *yasm_dwarf2__append_bc(yasm_section *sect, yasm_bytecode *bc);
 
-/*@only@*/ yasm_expr *yasm_dwarf2__bc_sym(yasm_symtab *symtab,
-                                         yasm_bytecode *bc);
+/*@dependent@*/ yasm_symrec *yasm_dwarf2__bc_sym(yasm_symtab *symtab,
+                                                yasm_bytecode *bc);
 
 typedef struct dwarf2_head dwarf2_head;
 dwarf2_head *yasm_dwarf2__add_head
index 43e2faac30d2c1bcde95b67fadfacb6984ecf1c3..74cc4fb4586a9527df6c40e74acfb36a9b92d005 100644 (file)
@@ -212,7 +212,7 @@ static yasm_bc_resolve_flags dwarf2_abbrev_bc_resolve
     (yasm_bytecode *bc, int save, yasm_calc_bc_dist_func calc_bc_dist);
 static int dwarf2_abbrev_bc_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);
 
 /* Bytecode callback structures */
@@ -313,22 +313,25 @@ yasm_dwarf2__generate_info(yasm_dbgfmt_dwarf2 *dbgfmt_dwarf2,
     /* statement list (line numbers) */
     abc->len += dwarf2_add_abbrev_attr(abbrev, DW_AT_stmt_list, DW_FORM_data4);
     dwarf2_append_expr(debug_info,
-       yasm_dwarf2__bc_sym(dbgfmt_dwarf2->symtab,
-                           yasm_section_bcs_first(debug_line)),
+       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) {
        /* 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_dwarf2__bc_sym(dbgfmt_dwarf2->symtab,
-                               yasm_section_bcs_first(main_code)),
+           yasm_expr_create_ident(yasm_expr_sym(
+               yasm_dwarf2__bc_sym(dbgfmt_dwarf2->symtab,
+                                   yasm_section_bcs_first(main_code))), 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_dwarf2__bc_sym(dbgfmt_dwarf2->symtab,
-                               yasm_section_bcs_last(main_code)),
+           yasm_expr_create_ident(yasm_expr_sym(
+               yasm_dwarf2__bc_sym(dbgfmt_dwarf2->symtab,
+                                   yasm_section_bcs_last(main_code))), 0),
            dbgfmt_dwarf2->sizeof_address, 0);
     }
 
@@ -403,7 +406,7 @@ dwarf2_abbrev_bc_resolve(yasm_bytecode *bc, int save,
 
 static int
 dwarf2_abbrev_bc_tobytes(yasm_bytecode *bc, unsigned char **bufp, void *d,
-                        yasm_output_expr_func output_expr,
+                        yasm_output_value_func output_value,
                         yasm_output_reloc_func output_reloc)
 {
     dwarf2_abbrev *abbrev = (dwarf2_abbrev *)bc->contents;
index 6f0f801dd3b3a44cedca254925a78457eff184d0..6874476dc2f1252f4cf02aaa29c189f3e12a50f2 100644 (file)
@@ -122,7 +122,7 @@ typedef struct dwarf2_line_op {
 
     /* extended opcode */
     dwarf_line_number_ext_op ext_opcode;
-    /*@owned@*/ /*@null@*/ yasm_expr *ext_operand;  /* unsigned */
+    /*@null@*/ /*@dependent@*/ yasm_symrec *ext_operand;  /* unsigned */
     unsigned long ext_operandsize;
 } dwarf2_line_op;
 
@@ -134,7 +134,7 @@ static yasm_bc_resolve_flags dwarf2_spp_bc_resolve
     (yasm_bytecode *bc, int save, yasm_calc_bc_dist_func calc_bc_dist);
 static int dwarf2_spp_bc_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);
 
 static void dwarf2_line_op_bc_destroy(void *contents);
@@ -144,7 +144,7 @@ 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_line_op_bc_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);
 
 /* Bytecode callback structures */
@@ -270,7 +270,7 @@ static yasm_bytecode *
 dwarf2_dbgfmt_append_line_ext_op(yasm_section *sect,
                                 dwarf_line_number_ext_op ext_opcode,
                                 unsigned long ext_operandsize,
-                                /*@only@*/ /*@null@*/ yasm_expr *ext_operand)
+                                /*@null@*/ yasm_symrec *ext_operand)
 {
     dwarf2_line_op *line_op = yasm_xmalloc(sizeof(dwarf2_line_op));
     yasm_bytecode *bc;
@@ -380,8 +380,7 @@ dwarf2_dbgfmt_gen_line_op(yasm_section *debug_line, dwarf2_line_state *state,
            return 1;
        }
        dwarf2_dbgfmt_append_line_ext_op(debug_line, DW_LNE_set_address,
-           dbgfmt_dwarf2->sizeof_address,
-           yasm_expr_create_ident(yasm_expr_sym(loc->sym), loc->line));
+           dbgfmt_dwarf2->sizeof_address, loc->sym);
        addr_delta = 0;
     } else if (loc->bc) {
        if (state->precbc->offset > loc->bc->offset)
@@ -702,7 +701,7 @@ dwarf2_spp_bc_resolve(yasm_bytecode *bc, int save,
 
 static int
 dwarf2_spp_bc_tobytes(yasm_bytecode *bc, unsigned char **bufp, void *d,
-                     yasm_output_expr_func output_expr,
+                     yasm_output_value_func output_value,
                      yasm_output_reloc_func output_reloc)
 {
     dwarf2_spp *spp = (dwarf2_spp *)bc->contents;
@@ -764,8 +763,6 @@ 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);
-    if (line_op->ext_operand)
-       yasm_expr_destroy(line_op->ext_operand);
     yasm_xfree(contents);
 }
 
@@ -786,7 +783,7 @@ dwarf2_line_op_bc_resolve(yasm_bytecode *bc, int save,
 
 static int
 dwarf2_line_op_bc_tobytes(yasm_bytecode *bc, unsigned char **bufp, void *d,
-                         yasm_output_expr_func output_expr,
+                         yasm_output_value_func output_value,
                          yasm_output_reloc_func output_reloc)
 {
     dwarf2_line_op *line_op = (dwarf2_line_op *)bc->contents;
@@ -799,9 +796,11 @@ dwarf2_line_op_bc_tobytes(yasm_bytecode *bc, unsigned char **bufp, void *d,
     if (line_op->ext_opcode > 0) {
        YASM_WRITE_8(buf, line_op->ext_opcode);
        if (line_op->ext_operand) {
-           output_expr(&line_op->ext_operand, buf, line_op->ext_operandsize,
-                       line_op->ext_operandsize*8, 0,
-                       (unsigned long)(buf-*bufp), bc, 0, 0, d);
+           yasm_value value;
+           yasm_value_init_sym(&value, line_op->ext_operand);
+           output_value(&value, buf, line_op->ext_operandsize,
+                        line_op->ext_operandsize*8, 0,
+                        (unsigned long)(buf-*bufp), bc, 0, d);
            buf += line_op->ext_operandsize;
        }
     }
index c59b9df4d590af9aa8936eabaeb7770075c5c6a2..a0ec30ae97ae69be3e2c605547898a321a27a107 100644 (file)
@@ -125,7 +125,7 @@ static yasm_bc_resolve_flags stabs_bc_str_resolve
     (yasm_bytecode *bc, int save, yasm_calc_bc_dist_func calc_bc_dist);
 static int stabs_bc_str_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);
 
 static void stabs_bc_stab_destroy(void *contents);
@@ -135,7 +135,7 @@ static yasm_bc_resolve_flags stabs_bc_stab_resolve
     (yasm_bytecode *bc, int save, yasm_calc_bc_dist_func calc_bc_dist);
 static int stabs_bc_stab_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);
 
 /* Bytecode callback structures */
@@ -396,7 +396,7 @@ stabs_dbgfmt_generate(yasm_dbgfmt *dbgfmt)
 
 static int
 stabs_bc_stab_tobytes(yasm_bytecode *bc, unsigned char **bufp, void *d,
-                     yasm_output_expr_func output_expr,
+                     yasm_output_value_func output_value,
                      yasm_output_reloc_func output_reloc)
 {
     /* This entire function, essentially the core of rendering stabs to a file,
@@ -430,7 +430,7 @@ stabs_bc_stab_tobytes(yasm_bytecode *bc, unsigned char **bufp, void *d,
 
 static int
 stabs_bc_str_tobytes(yasm_bytecode *bc, unsigned char **bufp, void *d,
-                    yasm_output_expr_func output_expr,
+                    yasm_output_value_func output_value,
                     yasm_output_reloc_func output_reloc)
 {
     const char *str = (const char *)bc->contents;
index 0bde6a95330256fc5479c4fa15a112472c649677..04da1437bfccf54a65ecf50f16da94a5cb59765f 100644 (file)
@@ -81,23 +81,33 @@ nasm_listfmt_destroy(/*@only@*/ yasm_listfmt *listfmt)
 }
 
 static int
-nasm_listfmt_output_expr(yasm_expr **ep, unsigned char *buf, size_t destsize,
-                        size_t valsize, int shift, unsigned long offset,
-                        yasm_bytecode *bc, int rel, int warn,
-                        /*@null@*/ void *d)
+nasm_listfmt_output_value(yasm_value *value, unsigned char *buf,
+                         size_t destsize, size_t valsize, int shift,
+                         unsigned long offset, yasm_bytecode *bc, int warn,
+                         /*@null@*/ void *d)
 {
     /*@null@*/ nasm_listfmt_output_info *info = (nasm_listfmt_output_info *)d;
     /*@dependent@*/ /*@null@*/ yasm_intnum *intn;
-    /*@dependent@*/ /*@null@*/ const yasm_floatnum *flt;
 
     assert(info != NULL);
 
+    /* Output */
+    switch (yasm_value_output_basic(value, buf, destsize, valsize, shift, bc,
+                                   warn, info->arch, NULL)) {
+       case -1:
+           return 1;
+       case 0:
+           break;
+       default:
+           return 0;
+    }
+
     /* Generate reloc if needed */
     if (info->next_reloc && info->next_reloc_addr == bc->offset+offset) {
        bcreloc *reloc = yasm_xmalloc(sizeof(bcreloc));
        reloc->offset = offset;
        reloc->size = destsize;
-       reloc->rel = rel;
+       reloc->rel = value->curpos_rel;
        STAILQ_INSERT_TAIL(&info->bcrelocs, reloc, link);
 
        /* Get next reloc's info */
@@ -110,20 +120,16 @@ nasm_listfmt_output_expr(yasm_expr **ep, unsigned char *buf, size_t destsize,
        }
     }
 
-    flt = yasm_expr_get_floatnum(ep);
-    if (flt) {
-       if (shift < 0)
-           yasm_internal_error(N_("attempting to negative shift a float"));
-       return yasm_arch_floatnum_tobytes(info->arch, flt, buf, destsize,
-                                         valsize, (unsigned int)shift, 0,
-                                         bc->line);
-    }
-
-    intn = yasm_expr_get_intnum(ep, NULL);
-    if (intn)
-       return yasm_arch_intnum_tobytes(info->arch, intn, buf, destsize,
-                                       valsize, shift, bc, 0, bc->line);
-    else {
+    if (value->abs) {
+       intn = yasm_expr_get_intnum(&value->abs, NULL);
+       if (intn)
+           return yasm_arch_intnum_tobytes(info->arch, intn, buf, destsize,
+                                           valsize, shift, bc, 0, bc->line);
+       else {
+           yasm__error(bc->line, N_("relocation too complex"));
+           return 1;
+       }
+    } else {
        int retval;
        intn = yasm_intnum_create_uint(0);
        retval = yasm_arch_intnum_tobytes(info->arch, intn, buf, destsize,
@@ -208,7 +214,7 @@ nasm_listfmt_output(yasm_listfmt *listfmt, FILE *f, yasm_linemap *linemap,
                 * way
                 */
                bigbuf = yasm_bc_tobytes(bc, buf, &size, &multiple, &gap,
-                                        &info, nasm_listfmt_output_expr,
+                                        &info, nasm_listfmt_output_value,
                                         NULL);
 
                /* output bytes with reloc information */
index 0932ebb767890ce19ec6249e8af4aeb88b80b254..d84fd90762b27e6dfc03fdbb81b13f3486a3a929 100644 (file)
@@ -135,54 +135,46 @@ bin_objfmt_expr_xform(/*@returned@*/ /*@only@*/ yasm_expr *e,
 }
 
 static int
-bin_objfmt_output_expr(yasm_expr **ep, unsigned char *buf, size_t destsize,
-                      size_t valsize, int shift,
-                      /*@unused@*/ unsigned long offset, yasm_bytecode *bc,
-                      int rel, int warn, /*@null@*/ void *d)
+bin_objfmt_output_value(yasm_value *value, unsigned char *buf, size_t destsize,
+                       size_t valsize, int shift,
+                       /*@unused@*/ unsigned long offset, yasm_bytecode *bc,
+                       int warn, /*@null@*/ void *d)
 {
     /*@null@*/ bin_objfmt_output_info *info = (bin_objfmt_output_info *)d;
-    /*@dependent@*/ /*@null@*/ yasm_intnum *intn;
-    /*@dependent@*/ /*@null@*/ const yasm_floatnum *flt;
+    /*@dependent@*/ /*@null@*/ yasm_bytecode *precbc;
+    /*@dependent@*/ yasm_section *sect;
 
     assert(info != NULL);
 
-    /* For binary output, this is trivial: any expression that doesn't simplify
-     * to an integer is an error (references something external).
-     * Other object formats need to generate their relocation list from here!
-     */
-
-    *ep = yasm_expr__level_tree(*ep, 1, 1, NULL, bin_objfmt_expr_xform, NULL,
-                               NULL);
-
-    /* Handle floating point expressions */
-    flt = yasm_expr_get_floatnum(ep);
-    if (flt) {
-       if (shift < 0)
-           yasm_internal_error(N_("attempting to negative shift a float"));
-       return yasm_arch_floatnum_tobytes(info->objfmt_bin->arch, flt, buf,
-                                         destsize, valsize,
-                                         (unsigned int)shift, warn, bc->line);
+    /* Binary objects we need to resolve against object, not against section. */
+    if (value->rel && !value->curpos_rel
+       && yasm_symrec_get_label(value->rel, &precbc)
+       && (sect = yasm_bc_get_section(precbc))) {
+       if (!value->abs)
+           value->abs = yasm_expr_create_ident(yasm_expr_sym(value->rel),
+                                               bc->line);
+       else
+           value->abs =
+               yasm_expr_create(YASM_EXPR_ADD, yasm_expr_expr(value->abs),
+                                yasm_expr_sym(value->rel), bc->line);
+       value->rel = NULL;
     }
 
-    /* Handle integer expressions */
-    intn = yasm_expr_get_intnum(ep, NULL);
-    if (intn) {
-       if (rel) {
-           int retval = yasm_arch_intnum_fixup_rel(info->objfmt_bin->arch,
-                                                   intn, valsize, bc,
-                                                   bc->line);
-           if (retval)
-               return retval;
-       }
-       return yasm_arch_intnum_tobytes(info->objfmt_bin->arch, intn, buf,
-                                       destsize, valsize, shift, bc, warn,
-                                       bc->line);
-    }
-
-    /* Check for complex float expressions */
-    if (yasm_expr__contains(*ep, YASM_EXPR_FLOAT)) {
-       yasm__error(bc->line, N_("floating point expression too complex"));
-       return 1;
+    /* Simplify absolute portion of value, transforming symrecs */
+    if (value->abs)
+       value->abs = yasm_expr__level_tree
+           (value->abs, 1, 1, 1, NULL, bin_objfmt_expr_xform, NULL, NULL,
+            NULL);
+
+    /* Output */
+    switch (yasm_value_output_basic(value, buf, destsize, valsize, shift,
+                                   bc, warn, info->objfmt_bin->arch, NULL)) {
+       case -1:
+           return 1;
+       case 0:
+           break;
+       default:
+           return 0;
     }
 
     /* Couldn't output, assume it contains an external reference. */
@@ -204,7 +196,7 @@ bin_objfmt_output_bytecode(yasm_bytecode *bc, /*@null@*/ void *d)
     assert(info != NULL);
 
     bigbuf = yasm_bc_tobytes(bc, info->buf, &size, &multiple, &gap, info,
-                            bin_objfmt_output_expr, NULL);
+                            bin_objfmt_output_value, NULL);
 
     /* Don't bother doing anything else if size ended up being 0. */
     if (size == 0) {
index 25fb790a64fa890987615f4eebd22a906f34046e..814b3a3e9a99493d7fd644e5998d9f58f7047929 100644 (file)
@@ -1,6 +1,6 @@
 -:4: expression must not contain floating point value
 -:5: expression must not contain floating point value
--:7: attempt to reserve non-constant quantity of space
+-:7: reserve expression not absolute
 -:11: expression must not contain floating point value
 -:12: expression must not contain floating point value
--:14: attempt to reserve non-constant quantity of space
+-:14: reserve expression not absolute
index 54db62e9500274e28eb47f6bb493190c9ca6c167..6c5c69080c671e457e34a75ed7b174ee20ad2186 100644 (file)
@@ -414,83 +414,131 @@ coff_objfmt_set_section_addr(yasm_section *sect, /*@null@*/ void *d)
 }
 
 static int
-coff_objfmt_output_expr(yasm_expr **ep, unsigned char *buf, size_t destsize,
-                       size_t valsize, int shift, unsigned long offset,
-                       yasm_bytecode *bc, int rel, int warn,
-                       /*@null@*/ void *d)
+coff_objfmt_output_value(yasm_value *value, unsigned char *buf, size_t destsize,
+                        size_t valsize, int shift, unsigned long offset,
+                        yasm_bytecode *bc, int warn, /*@null@*/ void *d)
 {
     /*@null@*/ coff_objfmt_output_info *info = (coff_objfmt_output_info *)d;
     yasm_objfmt_coff *objfmt_coff;
+    /*@only@*/ /*@null@*/ yasm_intnum *dist = NULL;
     /*@dependent@*/ /*@null@*/ yasm_intnum *intn;
-    /*@dependent@*/ /*@null@*/ const yasm_floatnum *flt;
-    /*@dependent@*/ /*@null@*/ yasm_symrec *sym;
-    /*@dependent@*/ yasm_section *label_sect;
-    /*@dependent@*/ /*@null@*/ yasm_bytecode *label_precbc;
+    unsigned long intn_val, intn_minus;
+    int retval;
 
     assert(info != NULL);
     objfmt_coff = info->objfmt_coff;
 
-    *ep = yasm_expr_simplify(*ep, yasm_common_calc_bc_dist);
+    if (value->abs)
+       value->abs = yasm_expr_simplify(value->abs, yasm_common_calc_bc_dist);
 
-    /* Handle floating point expressions */
-    flt = yasm_expr_get_floatnum(ep);
-    if (flt) {
-       if (shift < 0)
-           yasm_internal_error(N_("attempting to negative shift a float"));
-       return yasm_arch_floatnum_tobytes(objfmt_coff->arch, flt, buf,
-                                         destsize, valsize,
-                                         (unsigned int)shift, warn, bc->line);
+    /* Try to output constant and PC-relative section-local first.
+     * Note this does NOT output any value with a SEG, WRT, external,
+     * cross-section, or non-PC-relative reference (those are handled below).
+     */
+    switch (yasm_value_output_basic(value, buf, destsize, valsize, shift, bc,
+                                   warn, info->objfmt_coff->arch,
+                                   yasm_common_calc_bc_dist)) {
+       case -1:
+           return 1;
+       case 0:
+           break;
+       default:
+           return 0;
     }
 
-    /* Handle integer expressions, with relocation if necessary */
-    if (objfmt_coff->win64)
-       sym = yasm_expr_extract_symrec(ep, YASM_SYMREC_REPLACE_ZERO,
-                                      yasm_common_calc_bc_dist);
-    else
-       sym = yasm_expr_extract_symrec(ep, YASM_SYMREC_REPLACE_VALUE,
-                                      yasm_common_calc_bc_dist);
+    /* Handle other expressions, with relocation if necessary */
+    if (value->seg_of || value->rshift > 0) {
+       yasm__error(bc->line, N_("coff: relocation too complex"));
+       return 1;
+    }
 
-    if (sym) {
+    intn_val = 0;
+    intn_minus = 0;
+    if (value->rel) {
+       yasm_sym_vis vis = yasm_symrec_get_visibility(value->rel);
+       /*@dependent@*/ /*@null@*/ yasm_symrec *sym = value->rel;
        unsigned long addr;
        coff_reloc *reloc;
-       yasm_sym_vis vis;
 
-       reloc = yasm_xmalloc(sizeof(coff_reloc));
-       addr = bc->offset + offset;
-       if (COFF_SET_VMA)
-           addr += info->addr;
-       reloc->reloc.addr = yasm_intnum_create_uint(addr);
-       reloc->reloc.sym = sym;
-       vis = yasm_symrec_get_visibility(sym);
+       /* Sometimes we want the relocation to be generated against one
+        * symbol but the value generated correspond to a different symbol.
+        * This is done through (sym being referenced) WRT (sym used for reloc).
+        * Note both syms need to be in the same section!
+        */
+       if (value->wrt) {
+           /*@dependent@*/ /*@null@*/ yasm_bytecode *rel_precbc, *wrt_precbc;
+           if (!yasm_symrec_get_label(sym, &rel_precbc)
+               || !yasm_symrec_get_label(value->wrt, &wrt_precbc)) {
+               yasm__error(bc->line, N_("coff: wrt expression too complex"));
+               return 1;
+           }
+           dist = yasm_common_calc_bc_dist(wrt_precbc, rel_precbc);
+           if (!dist) {
+               yasm__error(bc->line, N_("coff: cannot wrt across sections"));
+               return 1;
+           }
+           sym = value->wrt;
+       }
+
        if (vis & YASM_SYM_COMMON) {
            /* In standard COFF, COMMON symbols have their length added in */
            if (!objfmt_coff->win32) {
                /*@dependent@*/ /*@null@*/ coff_symrec_data *csymd;
+               /*@dependent@*/ /*@null@*/ yasm_intnum *common_size;
 
                csymd = yasm_symrec_get_data(sym, &coff_symrec_data_cb);
                assert(csymd != NULL);
-               *ep = yasm_expr_create(YASM_EXPR_ADD, yasm_expr_expr(*ep),
-                   yasm_expr_expr(yasm_expr_copy(csymd->size)),
-                   csymd->size->line);
-               *ep = yasm_expr_simplify(*ep, yasm_common_calc_bc_dist);
+               common_size = yasm_expr_get_intnum(&csymd->size,
+                                                  yasm_common_calc_bc_dist);
+               if (!common_size) {
+                   yasm__error(bc->line, N_("coff: common size too complex"));
+                   return 1;
+               }
+
+               if (yasm_intnum_sign(common_size) < 0) {
+                   yasm__error(bc->line, N_("coff: common size is negative"));
+                   return 1;
+               }
+
+               intn_val += yasm_intnum_get_uint(common_size);
            }
        } else if (!(vis & YASM_SYM_EXTERN) && !objfmt_coff->win64) {
+           /*@dependent@*/ /*@null@*/ yasm_bytecode *sym_precbc;
+
            /* Local symbols need relocation to their section's start */
-           if (yasm_symrec_get_label(sym, &label_precbc)) {
-               /*@null@*/ coff_section_data *label_csd;
-               label_sect = yasm_bc_get_section(label_precbc);
-               label_csd = yasm_section_get_data(label_sect,
-                                                 &coff_section_data_cb);
-               assert(label_csd != NULL);
-               reloc->reloc.sym = label_csd->sym;
+           if (yasm_symrec_get_label(sym, &sym_precbc)) {
+               yasm_section *sym_sect = yasm_bc_get_section(sym_precbc);
+               /*@null@*/ coff_section_data *sym_csd;
+               sym_csd = yasm_section_get_data(sym_sect,
+                                               &coff_section_data_cb);
+               assert(sym_csd != NULL);
+               sym = sym_csd->sym;
+               intn_val = sym_precbc->offset + sym_precbc->len;
                if (COFF_SET_VMA)
-                   *ep = yasm_expr_create(YASM_EXPR_ADD, yasm_expr_expr(*ep),
-                       yasm_expr_int(yasm_intnum_create_uint(label_csd->addr)),
-                       (*ep)->line);
+                   intn_val += sym_csd->addr;
            }
        }
 
-       if (rel) {
+       if (value->curpos_rel) {
+           /* For standard COFF, need to adjust to start of section, e.g.
+            * subtract out the bytecode offset.
+            * For Win32 COFF, need to reference to next bytecode.
+            */
+           if (objfmt_coff->win32)
+               intn_val += bc->len;
+           else
+               intn_minus = bc->offset;
+       }
+
+       /* Generate reloc */
+       reloc = yasm_xmalloc(sizeof(coff_reloc));
+       addr = bc->offset + offset;
+       if (COFF_SET_VMA)
+           addr += info->addr;
+       reloc->reloc.addr = yasm_intnum_create_uint(addr);
+       reloc->reloc.sym = sym;
+
+       if (value->curpos_rel) {
            if (objfmt_coff->machine == COFF_MACHINE_I386) {
                if (valsize == 32)
                    reloc->type = COFF_RELOC_I386_REL32;
@@ -507,22 +555,6 @@ coff_objfmt_output_expr(yasm_expr **ep, unsigned char *buf, size_t destsize,
                }
            } else
                yasm_internal_error(N_("coff objfmt: unrecognized machine"));
-           /* For standard COFF, need to reference to start of section, so add
-            * $$ in.
-            * For Win32 COFF, need to reference to next bytecode, so add '$'
-            * (really $+$.len) in.
-            */
-           if (objfmt_coff->win32)
-               *ep = yasm_expr_create(YASM_EXPR_ADD, yasm_expr_expr(*ep),
-                   yasm_expr_sym(yasm_symtab_define_label2("$", bc,
-                                                           0, (*ep)->line)),
-                   (*ep)->line);
-           else
-               *ep = yasm_expr_create(YASM_EXPR_ADD, yasm_expr_expr(*ep),
-                   yasm_expr_sym(yasm_symtab_define_label2("$$",
-                       yasm_section_bcs_first(info->sect), 0, (*ep)->line)),
-                   (*ep)->line);
-           *ep = yasm_expr_simplify(*ep, yasm_common_calc_bc_dist);
        } else {
            if (objfmt_coff->machine == COFF_MACHINE_I386) {
                if (info->csd->flags2 & COFF_FLAG_NOBASE)
@@ -547,26 +579,39 @@ coff_objfmt_output_expr(yasm_expr **ep, unsigned char *buf, size_t destsize,
        info->csd->nreloc++;
        yasm_section_add_reloc(info->sect, (yasm_reloc *)reloc, yasm_xfree);
     }
-    intn = yasm_expr_get_intnum(ep, NULL);
-    if (intn) {
-       if (rel) {
-           int retval = yasm_arch_intnum_fixup_rel(objfmt_coff->arch, intn,
-                                                   valsize, bc, bc->line);
-           if (retval)
-               return retval;
+
+    /* Build up final integer output from intn_val, intn_minus, value->abs,
+     * and dist.  We do all this at the end to avoid creating temporary
+     * intnums above (except for dist).
+     */
+    if (intn_minus <= intn_val)
+       intn = yasm_intnum_create_uint(intn_val-intn_minus);
+    else {
+       intn = yasm_intnum_create_uint(intn_minus-intn_val);
+       yasm_intnum_calc(intn, YASM_EXPR_NEG, NULL, bc->line);
+    }
+
+    if (value->abs) {
+       yasm_intnum *intn2 = yasm_expr_get_intnum(&value->abs, NULL);
+       if (!intn2) {
+           yasm__error(bc->line, N_("coff: relocation too complex"));
+           yasm_intnum_destroy(intn);
+           if (dist)
+               yasm_intnum_destroy(dist);
+           return 1;
        }
-       return yasm_arch_intnum_tobytes(objfmt_coff->arch, intn, buf, destsize,
-                                       valsize, shift, bc, warn, bc->line);
+       yasm_intnum_calc(intn, YASM_EXPR_ADD, intn2, bc->line);
     }
 
-    /* Check for complex float expressions */
-    if (yasm_expr__contains(*ep, YASM_EXPR_FLOAT)) {
-       yasm__error(bc->line, N_("floating point expression too complex"));
-       return 1;
+    if (dist) {
+       yasm_intnum_calc(intn, YASM_EXPR_ADD, dist, bc->line);
+       yasm_intnum_destroy(dist);
     }
 
-    yasm__error(bc->line, N_("coff: relocation too complex"));
-    return 1;
+    retval = yasm_arch_intnum_tobytes(objfmt_coff->arch, intn, buf, destsize,
+                                     valsize, shift, bc, warn, bc->line);
+    yasm_intnum_destroy(intn);
+    return retval;
 }
 
 static int
@@ -582,7 +627,7 @@ coff_objfmt_output_bytecode(yasm_bytecode *bc, /*@null@*/ void *d)
     assert(info != NULL);
 
     bigbuf = yasm_bc_tobytes(bc, info->buf, &size, &multiple, &gap, info,
-                            coff_objfmt_output_expr, NULL);
+                            coff_objfmt_output_value, NULL);
 
     /* Don't bother doing anything else if size ended up being 0. */
     if (size == 0) {
index c895fc46fbe452299a3d0447472344399ff71888..a8b3ce888531d596a3704d6cd8afb02ba8b2194c 100644 (file)
@@ -290,91 +290,81 @@ elf_objfmt_output_reloc(yasm_symrec *sym, yasm_bytecode *bc,
 }
 
 static int
-elf_objfmt_output_expr(yasm_expr **ep, unsigned char *buf, size_t destsize,
+elf_objfmt_output_value(yasm_value *value, unsigned char *buf, size_t destsize,
                        size_t valsize, int shift, unsigned long offset,
-                       yasm_bytecode *bc, int rel, int warn,
-                       /*@null@*/ void *d)
+                       yasm_bytecode *bc, int warn, /*@null@*/ void *d)
 {
     /*@null@*/ elf_objfmt_output_info *info = (elf_objfmt_output_info *)d;
     /*@dependent@*/ /*@null@*/ yasm_intnum *intn;
-    /*@dependent@*/ /*@null@*/ const yasm_floatnum *flt;
-    /*@dependent@*/ /*@null@*/ yasm_symrec *sym;
+    unsigned long intn_val;
     /*@null@*/ elf_reloc_entry *reloc = NULL;
-    /*@null@*/ yasm_expr *wrt_expr;
-    /*@dependent@*/ /*@null@*/ yasm_symrec *wrt = NULL;
+    int retval;
 
     if (info == NULL)
        yasm_internal_error("null info struct");
 
-    *ep = yasm_expr_simplify(*ep, yasm_common_calc_bc_dist);
-
-    /* Handle floating point expressions */
-    flt = yasm_expr_get_floatnum(ep);
-    if (flt) {
-       if (shift < 0)
-           yasm_internal_error(N_("attempting to negative shift a float"));
-       return yasm_arch_floatnum_tobytes(info->objfmt_elf->arch, flt, buf,
-                                         destsize, valsize,
-                                         (unsigned int)shift, warn, bc->line);
-    }
-
-    /* Check for a WRT relocation */
-    wrt_expr = yasm_expr_extract_wrt(ep);
-    if (wrt_expr) {
-       wrt = yasm_expr_extract_symrec(&wrt_expr, YASM_SYMREC_REPLACE_ZERO,
-                                      yasm_common_calc_bc_dist);
-       yasm_expr_destroy(wrt_expr);
-       if (!wrt) {
-           yasm__error(bc->line, N_("WRT expression too complex"));
+    if (value->abs)
+       value->abs = yasm_expr_simplify(value->abs, yasm_common_calc_bc_dist);
+
+    /* Try to output constant and PC-relative section-local first.
+     * Note this does NOT output any value with a SEG, WRT, external,
+     * cross-section, or non-PC-relative reference (those are handled below).
+     */
+    switch (yasm_value_output_basic(value, buf, destsize, valsize, shift, bc,
+                                   warn, info->objfmt_elf->arch,
+                                   yasm_common_calc_bc_dist)) {
+       case -1:
            return 1;
-       }
+       case 0:
+           break;
+       default:
+           return 0;
     }
 
-    /* Handle integer expressions, with relocation if necessary */
-    if (wrt == info->objfmt_elf->dotdotsym
-       || (wrt && elf_is_wrt_sym_relative(wrt)))
-       sym = yasm_expr_extract_symrec(ep, YASM_SYMREC_REPLACE_ZERO,
-                                      yasm_common_calc_bc_dist);
-    else
-       sym = yasm_expr_extract_symrec(ep, YASM_SYMREC_REPLACE_VALUE_IF_LOCAL,
-                                      yasm_common_calc_bc_dist);
+    /* Handle other expressions, with relocation if necessary */
+    if (value->seg_of || value->rshift > 0) {
+       yasm__error(bc->line, N_("elf: relocation too complex"));
+       return 1;
+    }
 
-    if (sym) {
-       yasm_sym_vis vis;
+    intn_val = 0;
+    if (value->rel) {
+       yasm_sym_vis vis = yasm_symrec_get_visibility(value->rel);
+       /*@dependent@*/ /*@null@*/ yasm_symrec *sym = value->rel;
+       /*@dependent@*/ /*@null@*/ yasm_symrec *wrt = value->wrt;
 
-       vis = yasm_symrec_get_visibility(sym);
        if (wrt == info->objfmt_elf->dotdotsym)
            wrt = NULL;
        else if (wrt && elf_is_wrt_sym_relative(wrt))
            ;
        else if (vis == YASM_SYM_LOCAL) {
-           yasm_bytecode *label_precbc;
-           /* Local symbols need relocation to their section's start */
-           if (yasm_symrec_get_label(sym, &label_precbc)) {
-               yasm_section *label_sect = yasm_bc_get_section(label_precbc);
+           yasm_bytecode *sym_precbc;
+           /* Local symbols need relocation to their section's start, and
+            * add in the offset of the bytecode (within the target section)
+            * into the abs portion.
+            *
+            * This is only done if the symbol is relocated against the
+            * section instead of the symbol itself.
+            */
+           if (yasm_symrec_get_label(sym, &sym_precbc)) {
+               /* Relocate to section start */
+               yasm_section *sym_sect = yasm_bc_get_section(sym_precbc);
                /*@null@*/ elf_secthead *sym_shead;
-               sym_shead =
-                   yasm_section_get_data(label_sect, &elf_section_data);
+               sym_shead = yasm_section_get_data(sym_sect, &elf_section_data);
                assert(sym_shead != NULL);
                sym = elf_secthead_get_sym(sym_shead);
-           }
-       }
 
-       if (rel) {
-           /* Need to reference to start of section, so add $$ in. */
-           *ep = yasm_expr_create(YASM_EXPR_ADD, yasm_expr_expr(*ep),
-               yasm_expr_sym(yasm_symtab_define_label2("$$",
-                   yasm_section_bcs_first(info->sect), 0, (*ep)->line)),
-               (*ep)->line);
-           /* HELP: and this seems to have the desired effect. */
-           *ep = yasm_expr_create(YASM_EXPR_ADD, yasm_expr_expr(*ep),
-               yasm_expr_int(yasm_intnum_create_uint(bc->offset + offset)),
-               (*ep)->line);
-           *ep = yasm_expr_simplify(*ep, yasm_common_calc_bc_dist);
+               intn_val = sym_precbc->offset + sym_precbc->len;
+           }
        }
+       
+       /* For PC-relative, need to add offset of expression within bc. */
+       if (value->curpos_rel)
+           intn_val += offset;
 
        reloc = elf_reloc_entry_create(sym, wrt,
-           yasm_intnum_create_uint(bc->offset + offset), rel, valsize);
+           yasm_intnum_create_uint(bc->offset + offset), value->curpos_rel,
+           valsize);
        if (reloc == NULL) {
            yasm__error(bc->line, N_("elf: invalid relocation (WRT or size)"));
            return 1;
@@ -383,30 +373,25 @@ elf_objfmt_output_expr(yasm_expr **ep, unsigned char *buf, size_t destsize,
        elf_secthead_append_reloc(info->sect, info->shead, reloc);
     }
 
-    intn = yasm_expr_get_intnum(ep, NULL);
-    if (intn) {
-       if (rel) {
-           int retval = yasm_arch_intnum_fixup_rel(info->objfmt_elf->arch,
-                                                   intn, valsize, bc,
-                                                   bc->line);
-           if (retval)
-               return retval;
-       }
-       if (reloc)
-           elf_handle_reloc_addend(intn, reloc);
-       return yasm_arch_intnum_tobytes(info->objfmt_elf->arch, intn, buf,
-                                       destsize, valsize, shift, bc, warn,
-                                       bc->line);
-    }
+    intn = yasm_intnum_create_uint(intn_val);
 
-    /* Check for complex float expressions */
-    if (yasm_expr__contains(*ep, YASM_EXPR_FLOAT)) {
-       yasm__error(bc->line, N_("floating point expression too complex"));
-       return 1;
+    if (value->abs) {
+       yasm_intnum *intn2 = yasm_expr_get_intnum(&value->abs, NULL);
+       if (!intn2) {
+           yasm__error(bc->line, N_("elf: relocation too complex"));
+           yasm_intnum_destroy(intn);
+           return 1;
+       }
+       yasm_intnum_calc(intn, YASM_EXPR_ADD, intn2, bc->line);
     }
 
-    yasm__error(bc->line, N_("elf: relocation too complex"));
-    return 1;
+    if (reloc)
+       elf_handle_reloc_addend(intn, reloc);
+    retval = yasm_arch_intnum_tobytes(info->objfmt_elf->arch, intn, buf,
+                                     destsize, valsize, shift, bc, warn,
+                                     bc->line);
+    yasm_intnum_destroy(intn);
+    return retval;
 }
 
 static int
@@ -424,7 +409,7 @@ elf_objfmt_output_bytecode(yasm_bytecode *bc, /*@null@*/ void *d)
        yasm_internal_error("null info struct");
 
     bigbuf = yasm_bc_tobytes(bc, buf, &size, &multiple, &gap, info,
-                            elf_objfmt_output_expr, elf_objfmt_output_reloc);
+                            elf_objfmt_output_value, elf_objfmt_output_reloc);
 
     /* Don't bother doing anything else if size ended up being 0. */
     if (size == 0) {
index 975176467f404be5d8f56d01d8e1d7e3403564db..a0a6d8e80347bd6ba58adc502416a86a2da210d8 100644 (file)
@@ -130,7 +130,7 @@ trap:               sub     rsp, 256
 
 [SECTION .pdata]
 dd     trap
-dd     trap+(trap.end-trap)
+dd     trap.end wrt trap
 dd     $xdatasym
 
 [SECTION .xdata]
index 24b7a0a11d5173e5da053b036ee53fdef4a91a46..1c11d232d695d17f19ccc798fdeb491dca0f6f8f 100644 (file)
@@ -157,112 +157,85 @@ xdf_objfmt_create(yasm_object *object, yasm_arch *a)
 }
 
 static int
-xdf_objfmt_output_expr(yasm_expr **ep, unsigned char *buf, size_t destsize,
+xdf_objfmt_output_value(yasm_value *value, unsigned char *buf, size_t destsize,
                        size_t valsize, int shift, unsigned long offset,
-                       yasm_bytecode *bc, int rel, int warn,
-                       /*@null@*/ void *d)
+                       yasm_bytecode *bc, int warn, /*@null@*/ void *d)
 {
     /*@null@*/ xdf_objfmt_output_info *info = (xdf_objfmt_output_info *)d;
     yasm_objfmt_xdf *objfmt_xdf;
     /*@dependent@*/ /*@null@*/ yasm_intnum *intn;
-    /*@dependent@*/ /*@null@*/ const yasm_floatnum *flt;
-    /*@dependent@*/ /*@null@*/ yasm_symrec *sym;
-    yasm_expr *shr_expr;
-    yasm_expr *wrt_expr;
-    unsigned int shr = 0;
-    unsigned int seg = 0;
+    unsigned long intn_minus;
+    int retval;
 
     assert(info != NULL);
     objfmt_xdf = info->objfmt_xdf;
 
-    *ep = yasm_expr_simplify(*ep, yasm_common_calc_bc_dist);
-
-    /* Handle floating point expressions */
-    flt = yasm_expr_get_floatnum(ep);
-    if (flt) {
-       if (shift < 0)
-           yasm_internal_error(N_("attempting to negative shift a float"));
-       return yasm_arch_floatnum_tobytes(objfmt_xdf->arch, flt, buf,
-                                         destsize, valsize,
-                                         (unsigned int)shift, warn, bc->line);
-    }
-
-    /* Check for a right shift value */
-    shr_expr = yasm_expr_extract_shr(ep);
-    if (shr_expr) {
-       /*@dependent@*/ /*@null@*/ const yasm_intnum *shr_intn;
-       shr_intn = yasm_expr_get_intnum(&shr_expr, NULL);
-       if (!shr_intn) {
-           yasm__error(bc->line, N_("shift expression too complex"));
+    if (value->abs)
+       value->abs = yasm_expr_simplify(value->abs, yasm_common_calc_bc_dist);
+
+    /* Try to output constant and PC-relative section-local first.
+     * Note this does NOT output any value with a SEG, WRT, external,
+     * cross-section, or non-PC-relative reference (those are handled below).
+     */
+    switch (yasm_value_output_basic(value, buf, destsize, valsize, shift, bc,
+                                   warn, info->objfmt_xdf->arch,
+                                   yasm_common_calc_bc_dist)) {
+       case -1:
            return 1;
-       }
-       shr = yasm_intnum_get_uint(shr_intn);
+       case 0:
+           break;
+       default:
+           return 0;
     }
 
-    /* Check for a segment relocation */
-    if (yasm_expr_extract_seg(ep))
-       seg = 1;
-
-    /* Check for a WRT relocation */
-    wrt_expr = yasm_expr_extract_wrt(ep);
-
-    /* Handle integer expressions, with relocation if necessary */
-    sym = yasm_expr_extract_symrec(ep, YASM_SYMREC_REPLACE_ZERO,
-                                  yasm_common_calc_bc_dist);
-    if (sym) {
+    intn_minus = 0;
+    if (value->rel) {
        xdf_reloc *reloc;
 
        reloc = yasm_xmalloc(sizeof(xdf_reloc));
        reloc->reloc.addr = yasm_intnum_create_uint(bc->offset + offset);
-       reloc->reloc.sym = sym;
+       reloc->reloc.sym = value->rel;
        reloc->base = NULL;
        reloc->size = valsize/8;
-       reloc->shift = shr;
+       reloc->shift = value->rshift;
 
-       if (seg)
+       if (value->seg_of)
            reloc->type = XDF_RELOC_SEG;
-       else if (wrt_expr) {
-           reloc->base = yasm_expr_extract_symrec(&wrt_expr,
-                                                  YASM_SYMREC_REPLACE_ZERO, 
-                                                  yasm_common_calc_bc_dist);
-           if (!reloc->base) {
-               yasm__error(bc->line, N_("WRT expression too complex"));
-               return 1;
-           }
+       else if (value->wrt) {
+           reloc->base = value->wrt;
            reloc->type = XDF_RELOC_WRT;
-       } else if (rel) {
+       } else if (value->curpos_rel) {
            reloc->type = XDF_RELOC_RIP;
-           /* Need to reference to start of section, so add $$ in. */
-           *ep = yasm_expr_create(YASM_EXPR_ADD, yasm_expr_expr(*ep),
-               yasm_expr_sym(yasm_symtab_define_label2("$$",
-                   yasm_section_bcs_first(info->sect), 0, (*ep)->line)),
-               (*ep)->line);
-           *ep = yasm_expr_simplify(*ep, yasm_common_calc_bc_dist);
+           /* Adjust to start of section, so subtract out the bytecode
+            * offset.
+            */
+           intn_minus = bc->offset;
        } else
            reloc->type = XDF_RELOC_REL;
        info->xsd->nreloc++;
        yasm_section_add_reloc(info->sect, (yasm_reloc *)reloc, yasm_xfree);
     }
-    intn = yasm_expr_get_intnum(ep, NULL);
-    if (intn) {
-       if (rel) {
-           int retval = yasm_arch_intnum_fixup_rel(objfmt_xdf->arch, intn,
-                                                   valsize, bc, bc->line);
-           if (retval)
-               return retval;
-       }
-       return yasm_arch_intnum_tobytes(objfmt_xdf->arch, intn, buf, destsize,
-                                       valsize, shift, bc, warn, bc->line);
-    }
 
-    /* Check for complex float expressions */
-    if (yasm_expr__contains(*ep, YASM_EXPR_FLOAT)) {
-       yasm__error(bc->line, N_("floating point expression too complex"));
-       return 1;
+    if (intn_minus > 0) {
+       intn = yasm_intnum_create_uint(intn_minus);
+       yasm_intnum_calc(intn, YASM_EXPR_NEG, NULL, bc->line);
+    } else
+       intn = yasm_intnum_create_uint(0);
+
+    if (value->abs) {
+       yasm_intnum *intn2 = yasm_expr_get_intnum(&value->abs, NULL);
+       if (!intn2) {
+           yasm__error(bc->line, N_("xdf: relocation too complex"));
+           yasm_intnum_destroy(intn);
+           return 1;
+       }
+       yasm_intnum_calc(intn, YASM_EXPR_ADD, intn2, bc->line);
     }
 
-    yasm__error(bc->line, N_("xdf: relocation too complex"));
-    return 1;
+    retval = yasm_arch_intnum_tobytes(objfmt_xdf->arch, intn, buf, destsize,
+                                     valsize, shift, bc, warn, bc->line);
+    yasm_intnum_destroy(intn);
+    return retval;
 }
 
 static int
@@ -278,7 +251,7 @@ xdf_objfmt_output_bytecode(yasm_bytecode *bc, /*@null@*/ void *d)
     assert(info != NULL);
 
     bigbuf = yasm_bc_tobytes(bc, info->buf, &size, &multiple, &gap, info,
-                            xdf_objfmt_output_expr, NULL);
+                            xdf_objfmt_output_value, NULL);
 
     /* Don't bother doing anything else if size ended up being 0. */
     if (size == 0) {