diff --git a/Mkfiles/Makefile.dj b/Mkfiles/Makefile.dj
index dc64559b..ced5700a 100644
--- a/Mkfiles/Makefile.dj
+++ b/Mkfiles/Makefile.dj
@@ -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 \
diff --git a/Mkfiles/Makefile.flat b/Mkfiles/Makefile.flat
index c17d00f1..284f68a3 100644
--- a/Mkfiles/Makefile.flat
+++ b/Mkfiles/Makefile.flat
@@ -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 \
diff --git a/Mkfiles/vc/libyasm/libyasm.vcproj b/Mkfiles/vc/libyasm/libyasm.vcproj
index d4f8a1a4..09f9da06 100644
--- a/Mkfiles/vc/libyasm/libyasm.vcproj
+++ b/Mkfiles/vc/libyasm/libyasm.vcproj
@@ -452,6 +452,9 @@
BasicRuntimeChecks="3"/>
+
+
+
+
diff --git a/Mkfiles/vc8/libyasm/libyasm.vcproj b/Mkfiles/vc8/libyasm/libyasm.vcproj
index 15b221be..36e64503 100644
--- a/Mkfiles/vc8/libyasm/libyasm.vcproj
+++ b/Mkfiles/vc8/libyasm/libyasm.vcproj
@@ -1077,6 +1077,10 @@
/>
+
+
@@ -1274,6 +1278,10 @@
RelativePath="..\..\..\libyasm\valparam.h"
>
+
+
diff --git a/libyasm.h b/libyasm.h
index e3c8cc32..b35d5e52 100644
--- a/libyasm.h
+++ b/libyasm.h
@@ -60,6 +60,7 @@
#include
#include
#include
+#include
#include
#include
diff --git a/libyasm/Makefile.inc b/libyasm/Makefile.inc
index 3dba3592..23147a10 100644
--- a/libyasm/Makefile.inc
+++ b/libyasm/Makefile.inc
@@ -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
diff --git a/libyasm/arch.h b/libyasm/arch.h
index 1afce594..e7846f58 100644
--- a/libyasm/arch.h
+++ b/libyasm/arch.h
@@ -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 \
diff --git a/libyasm/bc-int.h b/libyasm/bc-int.h
index fbf8fced..ff0636b1 100644
--- a/libyasm/bc-int.h
+++ b/libyasm/bc-int.h
@@ -27,34 +27,6 @@
#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;
diff --git a/libyasm/bytecode.c b/libyasm/bytecode.c
index dae30af8..69893e2d 100644
--- a/libyasm/bytecode.c
+++ b/libyasm/bytecode.c
@@ -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"
@@ -47,10 +49,10 @@
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, "",
diff --git a/libyasm/bytecode.h b/libyasm/bytecode.h
index 7408d9bb..dd44ac0e 100644
--- a/libyasm/bytecode.h
+++ b/libyasm/bytecode.h
@@ -34,10 +34,55 @@
#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@*/;
diff --git a/libyasm/coretype.h b/libyasm/coretype.h
index 47c508f4..bb06ca90 100644
--- a/libyasm/coretype.h
+++ b/libyasm/coretype.h
@@ -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
diff --git a/libyasm/expr.c b/libyasm/expr.c
index f207b1fe..2037c565 100644
--- a/libyasm/expr.c
+++ b/libyasm/expr.c
@@ -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);
+ 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));
+ /* 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--;
+ /* 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)
diff --git a/libyasm/expr.h b/libyasm/expr.h
index 87268d51..f21907a3 100644
--- a/libyasm/expr.h
+++ b/libyasm/expr.h
@@ -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
diff --git a/libyasm/tests/Makefile.inc b/libyasm/tests/Makefile.inc
index f14ec4d7..4011fc9e 100644
--- a/libyasm/tests/Makefile.inc
+++ b/libyasm/tests/Makefile.inc
@@ -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
diff --git a/libyasm/tests/absloop-err.errwarn b/libyasm/tests/absloop-err.errwarn
index df8172d3..6cda28a7 100644
--- a/libyasm/tests/absloop-err.errwarn
+++ b/libyasm/tests/absloop-err.errwarn
@@ -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
index 00000000..883fa6fa
--- /dev/null
+++ b/libyasm/tests/value-err.asm
@@ -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
index 00000000..ae659a98
--- /dev/null
+++ b/libyasm/tests/value-err.errwarn
@@ -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
index 00000000..8b398197
--- /dev/null
+++ b/libyasm/value.c
@@ -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; inumterms; 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; jnumterms; 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<numterms; i++) {
+ if ((e->terms[i].type == YASM_EXPR_SYM
+ || e->terms[i].type == YASM_EXPR_SYMEXP)
+ && (used & (1<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; inumterms; 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
index 00000000..955fda49
--- /dev/null
+++ b/libyasm/value.h
@@ -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
diff --git a/modules/arch/lc3b/lc3barch.c b/modules/arch/lc3b/lc3barch.c
index 2fb5b8ff..8d0aba58 100644
--- a/modules/arch/lc3b/lc3barch.c
+++ b/modules/arch/lc3b/lc3barch.c
@@ -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,
diff --git a/modules/arch/lc3b/lc3barch.h b/modules/arch/lc3b/lc3barch.h
index fe5304d3..52e918ae 100644
--- a/modules/arch/lc3b/lc3barch.h
+++ b/modules/arch/lc3b/lc3barch.h
@@ -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,
diff --git a/modules/arch/lc3b/lc3bbc.c b/modules/arch/lc3b/lc3bbc.c
index 6f189d40..f3ce2f19 100644
--- a/modules/arch/lc3b/lc3bbc.c
+++ b/modules/arch/lc3b/lc3bbc.c
@@ -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"));
- yasm_expr_destroy(temp);
- return YASM_BC_RESOLVE_ERROR | YASM_BC_RESOLVE_UNKNOWN_LEN;
+ 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);
+ }
+
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,
diff --git a/modules/arch/lc3b/lc3bid.re b/modules/arch/lc3b/lc3bid.re
index 5c81c460..9b0dcee4 100644
--- a/modules/arch/lc3b/lc3bid.re
+++ b/modules/arch/lc3b/lc3bid.re
@@ -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);
}
diff --git a/modules/arch/x86/x86arch.c b/modules/arch/x86/x86arch.c
index eab49089..82b9ca53 100644
--- a/modules/arch/x86/x86arch.c
+++ b/modules/arch/x86/x86arch.c
@@ -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,
diff --git a/modules/arch/x86/x86arch.h b/modules/arch/x86/x86arch.h
index 1a3d7b64..6cb6fd41 100644
--- a/modules/arch/x86/x86arch.h
+++ b/modules/arch/x86/x86arch.h
@@ -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,
diff --git a/modules/arch/x86/x86bc.c b/modules/arch/x86/x86bc.c
index 5e55ae07..6938b0a8 100644
--- a/modules/arch/x86/x86bc.c
+++ b/modules/arch/x86/x86bc.c
@@ -35,30 +35,6 @@
#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);
-
- 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;
- }
-
- if (displen != 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 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;
+ /* 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) {
- *x86_ea = eat; /* structure copy */
- ea->len = displen;
- if (displen == 0 && ea->disp) {
- yasm_expr_destroy(ea->disp);
- ea->disp = NULL;
- }
+ /* Make the short form permanent. */
+ insn->opcode.opcode[0] = insn->opcode.opcode[1];
+ }
+ }
+
+ /* Check validity of effective address and calc R/M bits of
+ * Mod/RM byte and SIB byte. We won't know the Mod field
+ * of the Mod/RM byte until we know more about the
+ * displacement.
+ */
+ switch (yasm_x86__expr_checkea(&eat, &insn->common.addrsize,
+ 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 (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 (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;
+
+ /* 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) {
+ 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++;
- }
- }
- /* 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;
- }
- }
- /* 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 */
-
- /* Not really necessary, but saves confusion over it. */
- if (save)
- insn->postop = X86_POSTOP_NONE;
- break;
-
- default:
- break;
- }
-
- yasm_expr_destroy(temp);
}
+ /* 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++;
+ }
+ } 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->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;
+
+ case X86_POSTOP_SHIFT:
+ /* Handle shift postop special-casing */
+ if (num && yasm_intnum_get_uint(num) == 1) {
+ /* We can use the ,1 form: no imm (set to 0 len) */
+ immlen = 0;
+
+ if (save) {
+ /* Make the ,1 form permanent. */
+ insn->opcode.opcode[0] = insn->opcode.opcode[1];
+ /* Delete imm, as it's not needed. */
+ yasm_value_delete(&imm->val);
+ yasm_xfree(imm);
+ insn->imm = (yasm_immval *)NULL;
+ }
+ } else
+ retval = YASM_BC_RESOLVE_NONE; /* could still get ,1 */
+
+ /* Not really necessary, but saves confusion over it. */
+ if (save)
+ insn->postop = X86_POSTOP_NONE;
+ break;
+
+ default:
+ break;
+ }
+
+ 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;
+ }
+
+ 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);
- /* 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"));
- return YASM_BC_RESOLVE_ERROR |
- YASM_BC_RESOLVE_UNKNOWN_LEN;
- }
+ }
+
+ 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;
- }
- } 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.
- */
- 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;
+ 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 {
+ /* Near for now, but could get shorter in the future as
+ * there's a short form available.
+ */
+ jrtype = JMP_NEAR;
+ retval = YASM_BC_RESOLVE_NONE;
}
- 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; ilen; 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,
diff --git a/modules/arch/x86/x86expr.c b/modules/arch/x86/x86expr.c
index 80810778..f6c4673e 100644
--- a/modules/arch/x86/x86expr.c
+++ b/modules/arch/x86/x86expr.c
@@ -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], ®num, 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], ®num, 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,
- ®3264_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,
+ ®3264_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;
+ x86_ea->sib = 0;
+ x86_ea->valid_sib = 0;
+ x86_ea->need_sib = 0;
- switch (x86_expr_checkea_getregusage(ep, &wrt, (int *)NULL, pcrel,
- bits, ®16mult,
- 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;
+ if (x86_ea->ea.disp.abs) {
+ int pcrel = 0;
+ switch (x86_expr_checkea_getregusage
+ (&x86_ea->ea.disp.abs, (int *)NULL, &pcrel, bits,
+ ®16mult, 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;
}
diff --git a/modules/arch/x86/x86id.c b/modules/arch/x86/x86id.c
index 1b374a49..c375e570 100644
--- a/modules/arch/x86/x86id.c
+++ b/modules/arch/x86/x86id.c
@@ -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; iea, 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,
diff --git a/modules/dbgfmts/dwarf2/dwarf2-dbgfmt.c b/modules/dbgfmts/dwarf2/dwarf2-dbgfmt.c
index af39fb60..ea21be62 100644
--- a/modules/dbgfmts/dwarf2/dwarf2-dbgfmt.c
+++ b/modules/dbgfmts/dwarf2/dwarf2-dbgfmt.c
@@ -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;
}
diff --git a/modules/dbgfmts/dwarf2/dwarf2-dbgfmt.h b/modules/dbgfmts/dwarf2/dwarf2-dbgfmt.h
index 1874298d..5de6cca6 100644
--- a/modules/dbgfmts/dwarf2/dwarf2-dbgfmt.h
+++ b/modules/dbgfmts/dwarf2/dwarf2-dbgfmt.h
@@ -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
diff --git a/modules/dbgfmts/dwarf2/dwarf2-info.c b/modules/dbgfmts/dwarf2/dwarf2-info.c
index 43e2faac..74cc4fb4 100644
--- a/modules/dbgfmts/dwarf2/dwarf2-info.c
+++ b/modules/dbgfmts/dwarf2/dwarf2-info.c
@@ -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;
diff --git a/modules/dbgfmts/dwarf2/dwarf2-line.c b/modules/dbgfmts/dwarf2/dwarf2-line.c
index 6f0f801d..6874476d 100644
--- a/modules/dbgfmts/dwarf2/dwarf2-line.c
+++ b/modules/dbgfmts/dwarf2/dwarf2-line.c
@@ -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;
}
}
diff --git a/modules/dbgfmts/stabs/stabs-dbgfmt.c b/modules/dbgfmts/stabs/stabs-dbgfmt.c
index c59b9df4..a0ec30ae 100644
--- a/modules/dbgfmts/stabs/stabs-dbgfmt.c
+++ b/modules/dbgfmts/stabs/stabs-dbgfmt.c
@@ -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;
diff --git a/modules/listfmts/nasm/nasm-listfmt.c b/modules/listfmts/nasm/nasm-listfmt.c
index 0bde6a95..04da1437 100644
--- a/modules/listfmts/nasm/nasm-listfmt.c
+++ b/modules/listfmts/nasm/nasm-listfmt.c
@@ -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 */
diff --git a/modules/objfmts/bin/bin-objfmt.c b/modules/objfmts/bin/bin-objfmt.c
index 0932ebb7..d84fd907 100644
--- a/modules/objfmts/bin/bin-objfmt.c
+++ b/modules/objfmts/bin/bin-objfmt.c
@@ -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);
- }
+ /* 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);
- /* 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;
+ /* 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) {
diff --git a/modules/objfmts/bin/tests/reserve-err.errwarn b/modules/objfmts/bin/tests/reserve-err.errwarn
index 25fb790a..814b3a3e 100644
--- a/modules/objfmts/bin/tests/reserve-err.errwarn
+++ b/modules/objfmts/bin/tests/reserve-err.errwarn
@@ -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
diff --git a/modules/objfmts/coff/coff-objfmt.c b/modules/objfmts/coff/coff-objfmt.c
index 54db62e9..6c5c6908 100644
--- a/modules/objfmts/coff/coff-objfmt.c
+++ b/modules/objfmts/coff/coff-objfmt.c
@@ -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;
+ /* 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);
+ 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, &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)
+ intn_val += sym_csd->addr;
+ }
+ }
+
+ if (value->curpos_rel) {
+ /* For standard COFF, need to adjust to start of section, e.g.
+ * subtract out the bytecode offset.
+ * For Win32 COFF, need to 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;
- vis = yasm_symrec_get_visibility(sym);
- 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;
- 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);
- }
- } else if (!(vis & YASM_SYM_EXTERN) && !objfmt_coff->win64) {
- /* 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 (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);
- }
- }
-
- if (rel) {
+ 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) {
diff --git a/modules/objfmts/elf/elf-objfmt.c b/modules/objfmts/elf/elf-objfmt.c
index c895fc46..a8b3ce88 100644
--- a/modules/objfmts/elf/elf-objfmt.c
+++ b/modules/objfmts/elf/elf-objfmt.c
@@ -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);
+ 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(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"));
+ /* 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);
+
+ intn_val = sym_precbc->offset + sym_precbc->len;
}
}
-
- 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);
- }
+
+ /* 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;
+ intn = yasm_intnum_create_uint(intn_val);
+
+ 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;
}
- 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);
+ 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;
- }
-
- 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) {
diff --git a/modules/objfmts/win64/tests/win64-dataref.asm b/modules/objfmts/win64/tests/win64-dataref.asm
index 97517646..a0a6d8e8 100644
--- a/modules/objfmts/win64/tests/win64-dataref.asm
+++ b/modules/objfmts/win64/tests/win64-dataref.asm
@@ -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]
diff --git a/modules/objfmts/xdf/xdf-objfmt.c b/modules/objfmts/xdf/xdf-objfmt.c
index 24b7a0a1..1c11d232 100644
--- a/modules/objfmts/xdf/xdf-objfmt.c
+++ b/modules/objfmts/xdf/xdf-objfmt.c
@@ -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);
+ 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_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"));
+ /* 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;
+
+ 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;
}
- return yasm_arch_intnum_tobytes(objfmt_xdf->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;
- }
-
- 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) {