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) {