summaryrefslogtreecommitdiff
path: root/libyasm
diff options
context:
space:
mode:
authorPeter Johnson <peter@tortall.net>2001-11-15 23:44:41 +0000
committerPeter Johnson <peter@tortall.net>2001-11-15 23:44:41 +0000
commitd7fe402fb96cf79d1e93910633b678bb95d2a5e7 (patch)
tree7d2d794daf199c89b2d71b8fda3fa33187dd7cac /libyasm
parenta2bc46cb54b0963bbb4a5f78d541202e422cb857 (diff)
downloadyasm-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.h89
-rw-r--r--libyasm/expr.c750
-rw-r--r--libyasm/expr.h6
-rw-r--r--libyasm/tests/memexpr_test.c22
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, &reg16mult,
- 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;
}