diff options
author | Peter Johnson <peter@tortall.net> | 2001-11-15 23:44:41 +0000 |
---|---|---|
committer | Peter Johnson <peter@tortall.net> | 2001-11-15 23:44:41 +0000 |
commit | d7fe402fb96cf79d1e93910633b678bb95d2a5e7 (patch) | |
tree | 7d2d794daf199c89b2d71b8fda3fa33187dd7cac /libyasm | |
parent | a2bc46cb54b0963bbb4a5f78d541202e422cb857 (diff) | |
download | yasm-d7fe402fb96cf79d1e93910633b678bb95d2a5e7.tar.gz |
Split away x86-specific parts of expression handling (eg, effective address ->
ModRM+SIB).
svn path=/trunk/yasm/; revision=328
Diffstat (limited to 'libyasm')
-rw-r--r-- | libyasm/expr-int.h | 89 | ||||
-rw-r--r-- | libyasm/expr.c | 750 | ||||
-rw-r--r-- | libyasm/expr.h | 6 | ||||
-rw-r--r-- | libyasm/tests/memexpr_test.c | 22 |
4 files changed, 110 insertions, 757 deletions
diff --git a/libyasm/expr-int.h b/libyasm/expr-int.h new file mode 100644 index 00000000..03d8c13a --- /dev/null +++ b/libyasm/expr-int.h @@ -0,0 +1,89 @@ +/* $IdPath$ + * Expressions internal structures header file + * + * Copyright (C) 2001 Peter Johnson + * + * This file is part of YASM. + * + * YASM is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * YASM is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ +#ifndef YASM_EXPR_INT_H +#define YASM_EXPR_INT_H + +/* Types listed in canonical sorting order. See expr_order_terms(). */ +typedef enum { + EXPR_NONE = 0, + EXPR_REG = 1<<0, + EXPR_INT = 1<<1, + EXPR_FLOAT = 1<<2, + EXPR_SYM = 1<<3, + EXPR_EXPR = 1<<4 +} ExprType; + +struct ExprItem { + ExprType type; + union { + symrec *sym; + expr *expn; + intnum *intn; + floatnum *flt; + /* FIXME: reg structure is moderately x86-specific (namely size) */ + struct reg { + unsigned char num; + unsigned char size; /* in bits, eg AX=16, EAX=32 */ + } reg; + } data; +}; + +/* Some operations may allow more than two operand terms: + * ADD, MUL, OR, AND, XOR + */ +struct expr { + ExprOp op; + const char *filename; + unsigned long line; + int numterms; + ExprItem terms[2]; /* structure may be extended to include more */ +}; + +/* Traverse over expression tree in order, calling func for each leaf + * (non-operation). The data pointer d is passed to each func call. + * + * Stops early (and returns 1) if func returns 1. Otherwise returns 0. + */ +int expr_traverse_leaves_in(expr *e, void *d, + int (*func) (ExprItem *ei, void *d)); + +/* Transform negatives throughout an entire expn tree */ +expr *expr_xform_neg_tree(expr *e); + +/* Level an entire expn tree */ +expr *expr_level_tree(expr *e, int fold_const, int simplify_ident); + +/* Reorder terms of e into canonical order. Only reorders if reordering + * doesn't change meaning of expression. (eg, doesn't reorder SUB). + * Canonical order: REG, INT, FLOAT, SYM, EXPR. + * Multiple terms of a single type are kept in the same order as in + * the original expression. + * NOTE: Only performs reordering on *one* level (no recursion). + */ +void expr_order_terms(expr *e); + +/* Copy entire expression EXCEPT for index "except" at *top level only*. */ +expr *expr_copy_except(const expr *e, int except); + +int expr_contains(expr *e, ExprType t); + +#endif diff --git a/libyasm/expr.c b/libyasm/expr.c index c49d1846..bf2d7021 100644 --- a/libyasm/expr.c +++ b/libyasm/expr.c @@ -31,46 +31,11 @@ RCSID("$IdPath$"); #include "expr.h" #include "symrec.h" +#include "expr-int.h" -/* Types listed in canonical sorting order. See expr_order_terms(). */ -typedef enum { - EXPR_NONE = 0, - EXPR_REG = 1<<0, - EXPR_INT = 1<<1, - EXPR_FLOAT = 1<<2, - EXPR_SYM = 1<<3, - EXPR_EXPR = 1<<4 -} ExprType; - -struct ExprItem { - ExprType type; - union { - symrec *sym; - expr *expn; - intnum *intn; - floatnum *flt; - struct reg { - unsigned char num; - unsigned char size; /* in bits, eg AX=16, EAX=32 */ - } reg; - } data; -}; - -/* Some operations may allow more than two operand terms: - * ADD, MUL, OR, AND, XOR - */ -struct expr { - ExprOp op; - const char *filename; - unsigned long line; - int numterms; - ExprItem terms[2]; /* structure may be extended to include more */ -}; static int expr_traverse_nodes_post(expr *e, void *d, int (*func) (expr *e, void *d)); -static int expr_traverse_leaves_in(expr *e, void *d, - int (*func) (ExprItem *ei, void *d)); /* allocate a new expression node, with children as defined. * If it's a unary operator, put the element in left and set right=NULL. */ @@ -286,8 +251,8 @@ expr_xform_neg(expr *e) return e; } -/* Level an entire expn tree */ -static expr * +/* Transform negatives throughout an entire expn tree */ +expr * expr_xform_neg_tree(expr *e) { int i; @@ -583,7 +548,7 @@ expr_level_op(expr *e, int fold_const, int simplify_ident) } /* Level an entire expn tree */ -static expr * +expr * expr_level_tree(expr *e, int fold_const, int simplify_ident) { int i; @@ -620,7 +585,7 @@ expr_order_terms_compare(const void *va, const void *vb) * the original expression. * NOTE: Only performs reordering on *one* level (no recursion). */ -static void +void expr_order_terms(expr *e) { /* don't bother reordering if only one element */ @@ -647,7 +612,7 @@ expr_order_terms(expr *e) } /* Copy entire expression EXCEPT for index "except" at *top level only*. */ -static expr * +expr * expr_copy_except(const expr *e, int except) { expr *n; @@ -733,711 +698,12 @@ expr_contains_callback(ExprItem *ei, void *d) return (ei->type & *t); } -static int +int expr_contains(expr *e, ExprType t) { return expr_traverse_leaves_in(e, &t, expr_contains_callback); } -/* Only works if ei->type == EXPR_REG (doesn't check). - * Overwrites ei with intnum of 0 (to eliminate regs from the final expr). - */ -static int * -expr_checkea_get_reg32(ExprItem *ei, void *d) -{ - int *data = d; - int *ret; - - /* don't allow 16-bit registers */ - if (ei->data.reg.size != 32) - return 0; - - ret = &data[ei->data.reg.num & 7]; /* & 7 for sanity check */ - - /* overwrite with 0 to eliminate register from displacement expr */ - ei->type = EXPR_INT; - ei->data.intn = intnum_new_int(0); - - /* we're okay */ - return ret; -} - -typedef struct checkea_reg16_data { - int bx, si, di, bp; /* total multiplier for each reg */ -} checkea_reg16_data; - -/* Only works if ei->type == EXPR_REG (doesn't check). - * Overwrites ei with intnum of 0 (to eliminate regs from the final expr). - */ -static int * -expr_checkea_get_reg16(ExprItem *ei, void *d) -{ - checkea_reg16_data *data = d; - /* in order: ax,cx,dx,bx,sp,bp,si,di */ - static int *reg16[8] = {0,0,0,0,0,0,0,0}; - int *ret; - - reg16[3] = &data->bx; - reg16[5] = &data->bp; - reg16[6] = &data->si; - reg16[7] = &data->di; - - /* don't allow 32-bit registers */ - if (ei->data.reg.size != 16) - return 0; - - ret = reg16[ei->data.reg.num & 7]; /* & 7 for sanity check */ - - /* only allow BX, SI, DI, BP */ - if (!ret) - return 0; - - /* overwrite with 0 to eliminate register from displacement expr */ - ei->type = EXPR_INT; - ei->data.intn = intnum_new_int(0); - - /* we're okay */ - return ret; -} - -/* Distribute over registers to help bring them to the topmost level of e. - * Also check for illegal operations against registers. - * Returns 0 if something was illegal, 1 if legal and nothing in e changed, - * and 2 if legal and e needs to be simplified. - * - * Only half joking: Someday make this/checkea able to accept crazy things - * like: (bx+di)*(bx+di)-bx*bx-2*bx*di-di*di+di? Probably not: NASM never - * accepted such things, and it's doubtful such an expn is valid anyway - * (even though the above one is). But even macros would be hard-pressed - * to generate something like this. - * - * e must already have been simplified for this function to work properly - * (as it doesn't think things like SUB are valid). - * - * IMPLEMENTATION NOTE: About the only thing this function really needs to - * "distribute" is: (non-float-expn or intnum) * (sum expn of registers). - * - * TODO: Clean up this code, make it easier to understand. - */ -static int -expr_checkea_distcheck_reg(expr **ep) -{ - expr *e = *ep; - int i; - int havereg = -1, havereg_expr = -1; - int retval = 1; /* default to legal, no changes */ - - for (i=0; i<e->numterms; i++) { - switch (e->terms[i].type) { - case EXPR_REG: - /* Check op to make sure it's valid to use w/register. */ - if (e->op != EXPR_ADD && e->op != EXPR_MUL && - e->op != EXPR_IDENT) - return 0; - /* Check for reg*reg */ - if (e->op == EXPR_MUL && havereg != -1) - return 0; - havereg = i; - break; - case EXPR_FLOAT: - /* Floats not allowed. */ - return 0; - case EXPR_EXPR: - if (expr_contains(e->terms[i].data.expn, EXPR_REG)) { - int ret2; - - /* Check op to make sure it's valid to use w/register. */ - if (e->op != EXPR_ADD && e->op != EXPR_MUL) - return 0; - /* Check for reg*reg */ - if (e->op == EXPR_MUL && havereg != -1) - return 0; - havereg = i; - havereg_expr = i; - /* Recurse to check lower levels */ - ret2 = expr_checkea_distcheck_reg(&e->terms[i].data.expn); - if (ret2 == 0) - return 0; - if (ret2 == 2) - retval = 2; - } else if (expr_contains(e->terms[i].data.expn, EXPR_FLOAT)) - return 0; /* Disallow floats */ - break; - default: - break; - } - } - - /* just exit if no registers were used */ - if (havereg == -1) - return retval; - - /* Distribute */ - if (e->op == EXPR_MUL && havereg_expr != -1) { - expr *ne; - - retval = 2; /* we're going to change it */ - - /* The reg expn *must* be EXPR_ADD at this point. Sanity check. */ - if (e->terms[havereg_expr].type != EXPR_EXPR || - e->terms[havereg_expr].data.expn->op != EXPR_ADD) - InternalError(_("Register expression not ADD or EXPN")); - - /* Iterate over each term in reg expn */ - for (i=0; i<e->terms[havereg_expr].data.expn->numterms; i++) { - /* Copy everything EXCEPT havereg_expr term into new expression */ - ne = expr_copy_except(e, havereg_expr); - /* Copy reg expr term into uncopied (empty) term in new expn */ - ne->terms[havereg_expr] = - e->terms[havereg_expr].data.expn->terms[i]; /* struct copy */ - /* Overwrite old reg expr term with new expn */ - e->terms[havereg_expr].data.expn->terms[i].type = EXPR_EXPR; - e->terms[havereg_expr].data.expn->terms[i].data.expn = ne; - } - - /* Replace e with expanded reg expn */ - ne = e->terms[havereg_expr].data.expn; - e->terms[havereg_expr].type = EXPR_NONE; /* don't delete it! */ - expr_delete(e); /* but everything else */ - e = ne; - *ep = ne; - } - - return retval; -} - -/* Simplify and determine if expression is superficially valid: - * Valid expr should be [(int-equiv expn)]+[reg*(int-equiv expn)+...] - * where the [...] parts are optional. - * - * Don't simplify out constant identities if we're looking for an indexreg: we - * may need the multiplier for determining what the indexreg is! - * - * Returns 0 if invalid register usage, 1 if unable to determine all values, - * and 2 if all values successfully determined and saved in data. - */ -static int -expr_checkea_getregusage(expr **ep, int *indexreg, void *data, - int *(*get_reg)(ExprItem *ei, void *d)) -{ - int i; - int *reg; - expr *e; - - *ep = expr_xform_neg_tree(*ep); - *ep = expr_level_tree(*ep, 1, indexreg == 0); - e = *ep; - switch (expr_checkea_distcheck_reg(ep)) { - case 0: - return 0; - case 2: - /* Need to simplify again */ - *ep = expr_xform_neg_tree(*ep); - *ep = expr_level_tree(*ep, 1, indexreg == 0); - e = *ep; - break; - default: - break; - } - - switch (e->op) { - case EXPR_ADD: - /* Prescan for non-int multipliers. - * This is because if any of the terms is a more complex - * expr (eg, undetermined value), we don't want to try to - * figure out *any* of the expression, because each register - * lookup overwrites the register with a 0 value! And storing - * the state of this routine from one excution to the next - * would be a major chore. - */ - for (i=0; i<e->numterms; i++) - if (e->terms[i].type == EXPR_EXPR) { - if (e->terms[i].data.expn->numterms > 2) - return 1; - expr_order_terms(e->terms[i].data.expn); - if (e->terms[i].data.expn->terms[1].type != EXPR_INT) - return 1; - } - - /* FALLTHROUGH */ - case EXPR_IDENT: - /* Check each term for register (and possible multiplier). */ - for (i=0; i<e->numterms; i++) { - if (e->terms[i].type == EXPR_REG) { - reg = get_reg(&e->terms[i], data); - if (!reg) - return 0; - (*reg)++; - if (indexreg) - *indexreg = reg-(int *)data; - } else if (e->terms[i].type == EXPR_EXPR) { - /* Already ordered from ADD above, just grab the value. - * Sanity check for EXPR_INT. - */ - if (e->terms[i].data.expn->terms[0].type != EXPR_REG) - InternalError(_("Register not found in reg expn")); - if (e->terms[i].data.expn->terms[1].type != EXPR_INT) - InternalError(_("Non-integer value in reg expn")); - reg = get_reg(&e->terms[i].data.expn->terms[0], data); - if (!reg) - return 0; - (*reg) += - intnum_get_int(e->terms[i].data.expn->terms[1].data.intn); - if (indexreg) - *indexreg = reg-(int *)data; - } - } - break; - case EXPR_MUL: - /* Here, too, check for non-int multipliers. */ - if (e->numterms > 2) - return 1; - expr_order_terms(e); - if (e->terms[1].type != EXPR_INT) - return 1; - reg = get_reg(&e->terms[0], data); - if (!reg) - return 0; - (*reg) += intnum_get_int(e->terms[1].data.intn); - if (indexreg) - *indexreg = reg-(int *)data; - break; - default: - /* Should never get here! */ - break; - } - - /* Simplify expr, which is now really just the displacement. This - * should get rid of the 0's we put in for registers in the callback. - */ - *ep = expr_simplify(*ep); - /* e = *ep; */ - - return 2; -} - -/* Calculate the displacement length, if possible. - * Takes several extra inputs so it can be used by both 32-bit and 16-bit - * expressions: - * wordsize=2 for 16-bit, =4 for 32-bit. - * noreg=1 if the *ModRM byte* has no registers used. - * isbpreg=1 if BP/EBP is the *only* register used within the *ModRM byte*. - */ -static int -checkea_calc_displen(expr **ep, int wordsize, int noreg, int isbpreg, - unsigned char *displen, unsigned char *modrm, - unsigned char *v_modrm) -{ - expr *e = *ep; - const intnum *intn; - long dispval; - - *v_modrm = 0; /* default to not yet valid */ - - switch (*displen) { - case 0: - /* the displacement length hasn't been forced, try to - * determine what it is. - */ - if (noreg) { - /* no register in ModRM expression, so it must be disp16/32, - * and as the Mod bits are set to 0 by the caller, we're done - * with the ModRM byte. - */ - *displen = wordsize; - *v_modrm = 1; - } else if (isbpreg) { - /* for BP/EBP, there *must* be a displacement value, but we - * may not know the size (8 or 16/32) for sure right now. - * We can't leave displen at 0, because that just means - * unknown displacement, including none. - */ - *displen = 0xff; - } - - intn = expr_get_intnum(ep); - if (!intn) - break; /* expr still has unknown values */ - - /* make sure the displacement will fit in 16/32 bits if unsigned, - * and 8 bits if signed. - */ - if (!intnum_check_size(intn, wordsize, 0) && - !intnum_check_size(intn, 1, 1)) { - ErrorAt(e->filename, e->line, _("invalid effective address")); - return 0; - } - - /* don't try to find out what size displacement we have if - * displen is known. - */ - if (*displen != 0 && *displen != 0xff) - break; - - /* Don't worry about overflows here (it's already guaranteed - * to be 16/32 or 8 bits). - */ - dispval = intnum_get_int(intn); - - /* Figure out what size displacement we will have. */ - if (*displen != 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). - * 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 isbpreg check above, so - * check *displen. - */ - expr_delete(e); - *ep = (expr *)NULL; - } else if (dispval >= -128 && dispval <= 127) { - /* It fits into a signed byte */ - *displen = 1; - *modrm |= 0100; - } else { - /* It's a 16/32-bit displacement */ - *displen = wordsize; - *modrm |= 0200; - } - *v_modrm = 1; /* We're done with ModRM */ - - break; - - /* If not 0, the displacement length was forced; set the Mod bits - * appropriately and we're done with the ModRM byte. We assume - * that the user knows what they're doing if they do an explicit - * override, so we don't check for overflow (we'll just truncate - * when we output). - */ - case 1: - /* TODO: Add optional warning here about byte not being valid - * override in noreg case. - */ - if (!noreg) - *modrm |= 0100; - *v_modrm = 1; - break; - case 2: - case 4: - if (wordsize != *displen) { - ErrorAt(e->filename, e->line, - _("invalid effective address (displacement size)")); - return 0; - } - /* TODO: Add optional warning here about 2/4 not being valid - * override in noreg case. - */ - if (!noreg) - *modrm |= 0200; - *v_modrm = 1; - break; - default: - /* we shouldn't ever get any other size! */ - InternalError(_("strange EA displacement size")); - } - - return 1; -} - -static int -expr_checkea_getregsize_callback(ExprItem *ei, void *d) -{ - unsigned char *addrsize = (unsigned char *)d; - - if (ei->type == EXPR_REG) { - *addrsize = ei->data.reg.size; - return 1; - } else - return 0; -} - -int -expr_checkea(expr **ep, unsigned char *addrsize, unsigned char bits, - unsigned char nosplit, 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) -{ - expr *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) { - case 4: - /* must be 32-bit */ - *addrsize = 32; - break; - case 2: - /* must be 16-bit */ - *addrsize = 16; - break; - default: - /* check for use of 16 or 32-bit registers; if none are used - * default to bits setting. - */ - if (!expr_traverse_leaves_in(e, addrsize, - 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 - * 32-bit mode would generate a warning. - */ - } - } - - if (*addrsize == 32 && ((*n_modrm && !*v_modrm) || (*n_sib && !*v_sib))) { - int i; - typedef enum { - REG32_NONE = -1, - REG32_EAX = 0, - REG32_ECX = 1, - REG32_EDX = 2, - REG32_EBX = 3, - REG32_ESP = 4, - REG32_EBP = 5, - REG32_ESI = 6, - REG32_EDI = 7 - } reg32type; - int reg32mult[8] = {0, 0, 0, 0, 0, 0, 0, 0}; - int basereg = REG32_NONE; /* "base" register (for SIB) */ - int indexreg = REG32_NONE; /* "index" register (for SIB) */ - - switch (expr_checkea_getregusage(ep, &indexreg, reg32mult, - expr_checkea_get_reg32)) { - case 0: - e = *ep; - ErrorAt(e->filename, e->line, _("invalid effective address")); - return 0; - case 1: - return 1; - default: - e = *ep; - break; - } - - /* If indexreg mult is 0, discard it. - * This is possible because of the way indexreg is found in - * expr_checkea_getregusage(). - */ - if (indexreg != REG32_NONE && reg32mult[indexreg] == 0) - indexreg = REG32_NONE; - - /* Find a basereg (*1, but not indexreg), if there is one. - * Also, if an indexreg hasn't been assigned, try to find one. - * Meanwhile, check to make sure there's no negative register mults. - */ - for (i=0; i<8; i++) { - if (reg32mult[i] < 0) { - ErrorAt(e->filename, e->line, _("invalid effective address")); - return 0; - } - if (i != indexreg && reg32mult[i] == 1) - basereg = i; - else if (indexreg == REG32_NONE && reg32mult[i] > 0) - indexreg = i; - } - - /* Handle certain special cases of indexreg mults when basereg is - * empty. - */ - if (indexreg != REG32_NONE && basereg == REG32_NONE) - switch (reg32mult[indexreg]) { - case 1: - /* Only optimize this way if nosplit wasn't specified */ - if (!nosplit) { - basereg = indexreg; - indexreg = -1; - } - break; - case 2: - /* Only split if nosplit wasn't specified */ - if (!nosplit) { - basereg = indexreg; - reg32mult[indexreg] = 1; - } - break; - case 3: - case 5: - case 9: - basereg = indexreg; - reg32mult[indexreg]--; - break; - } - - /* Make sure there's no other registers than the basereg and indexreg - * we just found. - */ - for (i=0; i<8; i++) - if (i != basereg && i != indexreg && reg32mult[i] != 0) { - ErrorAt(e->filename, e->line, _("invalid effective address")); - return 0; - } - - /* Check the index multiplier value for validity if present. */ - if (indexreg != REG32_NONE && reg32mult[indexreg] != 1 && - reg32mult[indexreg] != 2 && reg32mult[indexreg] != 4 && - reg32mult[indexreg] != 8) { - ErrorAt(e->filename, e->line, _("invalid effective address")); - return 0; - } - - /* ESP is not a legal indexreg. */ - if (indexreg == REG32_ESP) { - /* If mult>1 or basereg is ESP also, there's no way to make it - * legal. - */ - if (reg32mult[REG32_ESP] > 1 || basereg == REG32_ESP) { - ErrorAt(e->filename, e->line, _("invalid effective address")); - return 0; - } - /* If mult==1 and basereg is not ESP, swap indexreg w/basereg. */ - indexreg = basereg; - basereg = REG32_ESP; - } - - /* At this point, we know the base and index registers and that the - * memory expression is (essentially) valid. Now build the ModRM and - * (optional) SIB bytes. - */ - - /* First determine R/M (Mod is later determined from disp size) */ - *n_modrm = 1; /* we always need ModRM */ - if (basereg == REG32_NONE) { - /* disp32[index] */ - *modrm |= 5; - /* we must have a SIB */ - *n_sib = 1; - } else if (indexreg == REG32_NONE) { - /* basereg only */ - *modrm |= basereg; - /* we don't need an SIB *unless* basereg is ESP */ - if (basereg == REG32_ESP) - *n_sib = 1; - else { - *sib = 0; - *v_sib = 0; - *n_sib = 0; - } - } else { - /* both base AND index */ - *modrm |= 4; - *n_sib = 1; - } - - /* Determine SIB if needed */ - if (*n_sib == 1) { - *sib = 0; /* start with 0 */ - - /* Special case: no basereg (only happens in disp32[index] case) */ - if (basereg == REG32_NONE) - *sib |= 5; - else - *sib |= basereg & 7; /* &7 to sanity check */ - - /* Put in indexreg, checking for none case */ - if (indexreg == REG32_NONE) - *sib |= 040; - /* Any scale field is valid, just leave at 0. */ - else { - *sib |= (indexreg & 7) << 3; /* &7 to sanity check */ - /* Set scale field, 1 case -> 0, so don't bother. */ - switch (reg32mult[indexreg]) { - case 2: - *sib |= 0100; - break; - case 4: - *sib |= 0200; - break; - case 8: - *sib |= 0300; - break; - } - } - - *v_sib = 1; /* Done with SIB */ - } - - /* Calculate displacement length (if possible) */ - return checkea_calc_displen(ep, 4, basereg == REG32_NONE, - basereg == REG32_EBP && - indexreg == REG32_NONE, displen, modrm, - v_modrm); - } else if (*addrsize == 16 && *n_modrm && !*v_modrm) { - static const unsigned char modrm16[16] = { - 0006 /* disp16 */, 0007 /* [BX] */, 0004 /* [SI] */, - 0000 /* [BX+SI] */, 0005 /* [DI] */, 0001 /* [BX+DI] */, - 0377 /* invalid */, 0377 /* invalid */, 0006 /* [BP]+d */, - 0377 /* invalid */, 0002 /* [BP+SI] */, 0377 /* invalid */, - 0003 /* [BP+DI] */, 0377 /* invalid */, 0377 /* invalid */, - 0377 /* invalid */ - }; - checkea_reg16_data reg16mult = {0, 0, 0, 0}; - enum { - HAVE_NONE = 0, - HAVE_BX = 1<<0, - HAVE_SI = 1<<1, - HAVE_DI = 1<<2, - HAVE_BP = 1<<3 - } havereg = HAVE_NONE; - - /* 16-bit cannot have SIB */ - *sib = 0; - *v_sib = 0; - *n_sib = 0; - - switch (expr_checkea_getregusage(ep, (int *)NULL, ®16mult, - expr_checkea_get_reg16)) { - case 0: - e = *ep; - ErrorAt(e->filename, e->line, _("invalid effective address")); - return 0; - case 1: - return 1; - default: - e = *ep; - break; - } - - /* reg multipliers not 0 or 1 are illegal. */ - if (reg16mult.bx & ~1 || reg16mult.si & ~1 || reg16mult.di & ~1 || - reg16mult.bp & ~1) { - ErrorAt(e->filename, e->line, _("invalid effective address")); - return 0; - } - - /* Set havereg appropriately */ - if (reg16mult.bx > 0) - havereg |= HAVE_BX; - if (reg16mult.si > 0) - havereg |= HAVE_SI; - if (reg16mult.di > 0) - havereg |= HAVE_DI; - if (reg16mult.bp > 0) - havereg |= HAVE_BP; - - /* Check the modrm value for invalid combinations. */ - if (modrm16[havereg] & 0070) { - ErrorAt(e->filename, e->line, _("invalid effective address")); - return 0; - } - - /* Set ModRM byte for registers */ - *modrm |= modrm16[havereg]; - - /* Calculate displacement length (if possible) */ - return checkea_calc_displen(ep, 2, havereg == HAVE_NONE, - havereg == HAVE_BP, displen, modrm, - v_modrm); - } - return 1; -} - static int expr_expand_equ_callback(ExprItem *ei, void *d) { @@ -1488,7 +754,7 @@ expr_traverse_nodes_post(expr *e, void *d, int (*func) (expr *e, void *d)) * * Stops early (and returns 1) if func returns 1. Otherwise returns 0. */ -static int +int expr_traverse_leaves_in(expr *e, void *d, int (*func) (ExprItem *ei, void *d)) { diff --git a/libyasm/expr.h b/libyasm/expr.h index 3f526e90..a6487338 100644 --- a/libyasm/expr.h +++ b/libyasm/expr.h @@ -44,12 +44,6 @@ expr *expr_copy(const expr *e); void expr_delete(expr *e); -int expr_checkea(expr **ep, unsigned char *addrsize, unsigned char bits, - unsigned char nosplit, 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); - /* Expands all (symrec) equ's in the expression into full expression * instances. */ diff --git a/libyasm/tests/memexpr_test.c b/libyasm/tests/memexpr_test.c index 09e017fa..ec9c001d 100644 --- a/libyasm/tests/memexpr_test.c +++ b/libyasm/tests/memexpr_test.c @@ -30,6 +30,10 @@ #include "intnum.h" #include "floatnum.h" +#include "bytecode.h" +#include "arch.h" +#include "x86-int.h" + typedef enum { REG_AX = 0, REG_CX = 1, @@ -294,7 +298,7 @@ WarningAt(const char *filename, unsigned long line, const char *fmt, ...) } static int -checkea_check(CheckEA_Entry *val) +x86_checkea_check(CheckEA_Entry *val) { CheckEA_InOut chk = val->in; /* local structure copy of inputs */ int retval; @@ -302,9 +306,9 @@ checkea_check(CheckEA_Entry *val) error_triggered = 0; /* execute function and check return value */ - retval = expr_checkea(&expn, &chk.addrsize, chk.bits, chk.nosplit, - &chk.displen, &chk.modrm, &chk.v_modrm, &chk.n_modrm, - &chk.sib, &chk.v_sib, &chk.n_sib); + retval = x86_expr_checkea(&expn, &chk.addrsize, chk.bits, chk.nosplit, + &chk.displen, &chk.modrm, &chk.v_modrm, + &chk.n_modrm, &chk.sib, &chk.v_sib, &chk.n_sib); if (retval != val->retval) { sprintf(result_msg, "%s: incorrect %s (expected %d, got %d)", val->ascii, "return value", val->retval, retval); @@ -373,14 +377,14 @@ checkea_check(CheckEA_Entry *val) return 0; } -START_TEST(test_checkea_bits16) +START_TEST(test_x86_checkea_bits16) { CheckEA_Entry *vals = bits16_vals; int i, num = sizeof(bits16_vals)/sizeof(CheckEA_Entry); for (i=0; i<num; i++) { expn = vals[i].in.expr_gen(); - fail_unless(checkea_check(&vals[i]) == 0, result_msg); + fail_unless(x86_checkea_check(&vals[i]) == 0, result_msg); expr_delete(expn); } } @@ -390,10 +394,10 @@ static Suite * memexpr_suite(void) { Suite *s = suite_create("memexpr"); - TCase *tc_checkea = tcase_create("checkea"); + TCase *tc_x86_checkea = tcase_create("x86_checkea"); - suite_add_tcase(s, tc_checkea); - tcase_add_test(tc_checkea, test_checkea_bits16); + suite_add_tcase(s, tc_x86_checkea); + tcase_add_test(tc_x86_checkea, test_x86_checkea_bits16); return s; } |