Correctly process 32-bit memory expressions in expr_checkea().

svn path=/trunk/yasm/; revision=303
0.3
Peter Johnson 24 years ago
parent 305b471f51
commit 10fa8fadc1
  1. 404
      libyasm/expr.c
  2. 404
      modules/arch/x86/expr.c
  3. 404
      modules/arch/x86/x86expr.c
  4. 404
      src/arch/x86/expr.c
  5. 404
      src/arch/x86/x86expr.c
  6. 404
      src/expr.c

@ -761,9 +761,9 @@ expr_checkea_get_reg32(ExprItem *ei, void *d)
return ret;
}
typedef struct checkea_invalid16_data {
typedef struct checkea_reg16_data {
int bx, si, di, bp; /* total multiplier for each reg */
} checkea_invalid16_data;
} 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).
@ -771,7 +771,7 @@ typedef struct checkea_invalid16_data {
static int *
expr_checkea_get_reg16(ExprItem *ei, void *d)
{
checkea_invalid16_data *data = 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;
@ -910,7 +910,7 @@ expr_checkea_distcheck_reg(expr **ep)
* where the [...] parts are optional.
*
* Don't simplify out constant identities if we're looking for an indexreg: we
* need the multiplier for determining what the indexreg is!
* 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.
@ -928,7 +928,6 @@ expr_checkea_getregusage(expr **ep, int *indexreg, void *data,
e = *ep;
switch (expr_checkea_distcheck_reg(ep)) {
case 0:
ErrorAt(e->filename, e->line, _("invalid effective address"));
return 0;
case 2:
/* Need to simplify again */
@ -968,6 +967,8 @@ expr_checkea_getregusage(expr **ep, int *indexreg, void *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.
@ -982,8 +983,7 @@ expr_checkea_getregusage(expr **ep, int *indexreg, void *data,
(*reg) +=
intnum_get_int(e->terms[i].data.expn->terms[1].data.intn);
if (indexreg)
*indexreg =
e->terms[i].data.expn->terms[0].data.reg.num;
*indexreg = reg-(int *)data;
}
}
break;
@ -998,6 +998,8 @@ expr_checkea_getregusage(expr **ep, int *indexreg, void *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! */
@ -1013,6 +1015,123 @@ expr_checkea_getregusage(expr **ep, int *indexreg, void *data,
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:
*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;
}
*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)
{
@ -1033,8 +1152,6 @@ expr_checkea(expr **ep, unsigned char *addrsize, unsigned char bits,
unsigned char *n_sib)
{
expr *e = *ep;
const intnum *intn;
long dispval;
if (*addrsize == 0) {
/* we need to figure out the address size from what we know about:
@ -1066,9 +1183,21 @@ expr_checkea(expr **ep, unsigned char *addrsize, unsigned char bits,
}
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 = 0;*/ /* "base" register (for SIB) */
int indexreg = 0; /* "index" register (for SIB) */
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)) {
@ -1083,6 +1212,153 @@ expr_checkea(expr **ep, unsigned char *addrsize, unsigned char bits,
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] */,
@ -1092,7 +1368,7 @@ expr_checkea(expr **ep, unsigned char *addrsize, unsigned char bits,
0003 /* [BP+DI] */, 0377 /* invalid */, 0377 /* invalid */,
0377 /* invalid */
};
checkea_invalid16_data reg16mult = {0, 0, 0, 0};
checkea_reg16_data reg16mult = {0, 0, 0, 0};
enum {
HAVE_NONE = 0,
HAVE_BX = 1<<0,
@ -1142,107 +1418,13 @@ expr_checkea(expr **ep, unsigned char *addrsize, unsigned char bits,
return 0;
}
/* Set ModRM byte for registers */
*modrm |= modrm16[havereg];
*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.
*/
switch (havereg) {
case HAVE_NONE:
/* no register in expression, so it must be disp16, and
* as the Mod bits are set to 0 above, we're done with
* the ModRM byte.
*/
*displen = 2;
*v_modrm = 1;
break;
case HAVE_BP:
/* for BP, there *must* be a displacement value, but we
* may not know the size (8 or 16) for sure right now.
* We can't leave displen at 0, because that just means
* unknown displacement, including none.
*/
*displen = 0xff;
break;
default:
break;
}
intn = expr_get_intnum(ep);
if (!intn)
break; /* expr still has unknown values */
/* make sure the displacement will fit in 16 bits if unsigned,
* and 8 bits if signed.
*/
if (!intnum_check_size(intn, 2, 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 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 HAVE_BP 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-bit displacement */
*displen = 2;
*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:
*modrm |= 0100;
*v_modrm = 1;
break;
case 2:
*modrm |= 0200;
*v_modrm = 1;
break;
default:
/* any other size is an error */
ErrorAt(e->filename, e->line,
_("invalid effective address (displacement size)"));
return 0;
}
/* Calculate displacement length (if possible) */
return checkea_calc_displen(ep, 2, havereg == HAVE_NONE,
havereg == HAVE_BP, displen, modrm,
v_modrm);
}
return 1;
}

@ -761,9 +761,9 @@ expr_checkea_get_reg32(ExprItem *ei, void *d)
return ret;
}
typedef struct checkea_invalid16_data {
typedef struct checkea_reg16_data {
int bx, si, di, bp; /* total multiplier for each reg */
} checkea_invalid16_data;
} 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).
@ -771,7 +771,7 @@ typedef struct checkea_invalid16_data {
static int *
expr_checkea_get_reg16(ExprItem *ei, void *d)
{
checkea_invalid16_data *data = 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;
@ -910,7 +910,7 @@ expr_checkea_distcheck_reg(expr **ep)
* where the [...] parts are optional.
*
* Don't simplify out constant identities if we're looking for an indexreg: we
* need the multiplier for determining what the indexreg is!
* 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.
@ -928,7 +928,6 @@ expr_checkea_getregusage(expr **ep, int *indexreg, void *data,
e = *ep;
switch (expr_checkea_distcheck_reg(ep)) {
case 0:
ErrorAt(e->filename, e->line, _("invalid effective address"));
return 0;
case 2:
/* Need to simplify again */
@ -968,6 +967,8 @@ expr_checkea_getregusage(expr **ep, int *indexreg, void *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.
@ -982,8 +983,7 @@ expr_checkea_getregusage(expr **ep, int *indexreg, void *data,
(*reg) +=
intnum_get_int(e->terms[i].data.expn->terms[1].data.intn);
if (indexreg)
*indexreg =
e->terms[i].data.expn->terms[0].data.reg.num;
*indexreg = reg-(int *)data;
}
}
break;
@ -998,6 +998,8 @@ expr_checkea_getregusage(expr **ep, int *indexreg, void *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! */
@ -1013,6 +1015,123 @@ expr_checkea_getregusage(expr **ep, int *indexreg, void *data,
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:
*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;
}
*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)
{
@ -1033,8 +1152,6 @@ expr_checkea(expr **ep, unsigned char *addrsize, unsigned char bits,
unsigned char *n_sib)
{
expr *e = *ep;
const intnum *intn;
long dispval;
if (*addrsize == 0) {
/* we need to figure out the address size from what we know about:
@ -1066,9 +1183,21 @@ expr_checkea(expr **ep, unsigned char *addrsize, unsigned char bits,
}
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 = 0;*/ /* "base" register (for SIB) */
int indexreg = 0; /* "index" register (for SIB) */
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)) {
@ -1083,6 +1212,153 @@ expr_checkea(expr **ep, unsigned char *addrsize, unsigned char bits,
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] */,
@ -1092,7 +1368,7 @@ expr_checkea(expr **ep, unsigned char *addrsize, unsigned char bits,
0003 /* [BP+DI] */, 0377 /* invalid */, 0377 /* invalid */,
0377 /* invalid */
};
checkea_invalid16_data reg16mult = {0, 0, 0, 0};
checkea_reg16_data reg16mult = {0, 0, 0, 0};
enum {
HAVE_NONE = 0,
HAVE_BX = 1<<0,
@ -1142,107 +1418,13 @@ expr_checkea(expr **ep, unsigned char *addrsize, unsigned char bits,
return 0;
}
/* Set ModRM byte for registers */
*modrm |= modrm16[havereg];
*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.
*/
switch (havereg) {
case HAVE_NONE:
/* no register in expression, so it must be disp16, and
* as the Mod bits are set to 0 above, we're done with
* the ModRM byte.
*/
*displen = 2;
*v_modrm = 1;
break;
case HAVE_BP:
/* for BP, there *must* be a displacement value, but we
* may not know the size (8 or 16) for sure right now.
* We can't leave displen at 0, because that just means
* unknown displacement, including none.
*/
*displen = 0xff;
break;
default:
break;
}
intn = expr_get_intnum(ep);
if (!intn)
break; /* expr still has unknown values */
/* make sure the displacement will fit in 16 bits if unsigned,
* and 8 bits if signed.
*/
if (!intnum_check_size(intn, 2, 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 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 HAVE_BP 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-bit displacement */
*displen = 2;
*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:
*modrm |= 0100;
*v_modrm = 1;
break;
case 2:
*modrm |= 0200;
*v_modrm = 1;
break;
default:
/* any other size is an error */
ErrorAt(e->filename, e->line,
_("invalid effective address (displacement size)"));
return 0;
}
/* Calculate displacement length (if possible) */
return checkea_calc_displen(ep, 2, havereg == HAVE_NONE,
havereg == HAVE_BP, displen, modrm,
v_modrm);
}
return 1;
}

@ -761,9 +761,9 @@ expr_checkea_get_reg32(ExprItem *ei, void *d)
return ret;
}
typedef struct checkea_invalid16_data {
typedef struct checkea_reg16_data {
int bx, si, di, bp; /* total multiplier for each reg */
} checkea_invalid16_data;
} 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).
@ -771,7 +771,7 @@ typedef struct checkea_invalid16_data {
static int *
expr_checkea_get_reg16(ExprItem *ei, void *d)
{
checkea_invalid16_data *data = 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;
@ -910,7 +910,7 @@ expr_checkea_distcheck_reg(expr **ep)
* where the [...] parts are optional.
*
* Don't simplify out constant identities if we're looking for an indexreg: we
* need the multiplier for determining what the indexreg is!
* 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.
@ -928,7 +928,6 @@ expr_checkea_getregusage(expr **ep, int *indexreg, void *data,
e = *ep;
switch (expr_checkea_distcheck_reg(ep)) {
case 0:
ErrorAt(e->filename, e->line, _("invalid effective address"));
return 0;
case 2:
/* Need to simplify again */
@ -968,6 +967,8 @@ expr_checkea_getregusage(expr **ep, int *indexreg, void *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.
@ -982,8 +983,7 @@ expr_checkea_getregusage(expr **ep, int *indexreg, void *data,
(*reg) +=
intnum_get_int(e->terms[i].data.expn->terms[1].data.intn);
if (indexreg)
*indexreg =
e->terms[i].data.expn->terms[0].data.reg.num;
*indexreg = reg-(int *)data;
}
}
break;
@ -998,6 +998,8 @@ expr_checkea_getregusage(expr **ep, int *indexreg, void *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! */
@ -1013,6 +1015,123 @@ expr_checkea_getregusage(expr **ep, int *indexreg, void *data,
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:
*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;
}
*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)
{
@ -1033,8 +1152,6 @@ expr_checkea(expr **ep, unsigned char *addrsize, unsigned char bits,
unsigned char *n_sib)
{
expr *e = *ep;
const intnum *intn;
long dispval;
if (*addrsize == 0) {
/* we need to figure out the address size from what we know about:
@ -1066,9 +1183,21 @@ expr_checkea(expr **ep, unsigned char *addrsize, unsigned char bits,
}
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 = 0;*/ /* "base" register (for SIB) */
int indexreg = 0; /* "index" register (for SIB) */
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)) {
@ -1083,6 +1212,153 @@ expr_checkea(expr **ep, unsigned char *addrsize, unsigned char bits,
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] */,
@ -1092,7 +1368,7 @@ expr_checkea(expr **ep, unsigned char *addrsize, unsigned char bits,
0003 /* [BP+DI] */, 0377 /* invalid */, 0377 /* invalid */,
0377 /* invalid */
};
checkea_invalid16_data reg16mult = {0, 0, 0, 0};
checkea_reg16_data reg16mult = {0, 0, 0, 0};
enum {
HAVE_NONE = 0,
HAVE_BX = 1<<0,
@ -1142,107 +1418,13 @@ expr_checkea(expr **ep, unsigned char *addrsize, unsigned char bits,
return 0;
}
/* Set ModRM byte for registers */
*modrm |= modrm16[havereg];
*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.
*/
switch (havereg) {
case HAVE_NONE:
/* no register in expression, so it must be disp16, and
* as the Mod bits are set to 0 above, we're done with
* the ModRM byte.
*/
*displen = 2;
*v_modrm = 1;
break;
case HAVE_BP:
/* for BP, there *must* be a displacement value, but we
* may not know the size (8 or 16) for sure right now.
* We can't leave displen at 0, because that just means
* unknown displacement, including none.
*/
*displen = 0xff;
break;
default:
break;
}
intn = expr_get_intnum(ep);
if (!intn)
break; /* expr still has unknown values */
/* make sure the displacement will fit in 16 bits if unsigned,
* and 8 bits if signed.
*/
if (!intnum_check_size(intn, 2, 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 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 HAVE_BP 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-bit displacement */
*displen = 2;
*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:
*modrm |= 0100;
*v_modrm = 1;
break;
case 2:
*modrm |= 0200;
*v_modrm = 1;
break;
default:
/* any other size is an error */
ErrorAt(e->filename, e->line,
_("invalid effective address (displacement size)"));
return 0;
}
/* Calculate displacement length (if possible) */
return checkea_calc_displen(ep, 2, havereg == HAVE_NONE,
havereg == HAVE_BP, displen, modrm,
v_modrm);
}
return 1;
}

@ -761,9 +761,9 @@ expr_checkea_get_reg32(ExprItem *ei, void *d)
return ret;
}
typedef struct checkea_invalid16_data {
typedef struct checkea_reg16_data {
int bx, si, di, bp; /* total multiplier for each reg */
} checkea_invalid16_data;
} 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).
@ -771,7 +771,7 @@ typedef struct checkea_invalid16_data {
static int *
expr_checkea_get_reg16(ExprItem *ei, void *d)
{
checkea_invalid16_data *data = 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;
@ -910,7 +910,7 @@ expr_checkea_distcheck_reg(expr **ep)
* where the [...] parts are optional.
*
* Don't simplify out constant identities if we're looking for an indexreg: we
* need the multiplier for determining what the indexreg is!
* 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.
@ -928,7 +928,6 @@ expr_checkea_getregusage(expr **ep, int *indexreg, void *data,
e = *ep;
switch (expr_checkea_distcheck_reg(ep)) {
case 0:
ErrorAt(e->filename, e->line, _("invalid effective address"));
return 0;
case 2:
/* Need to simplify again */
@ -968,6 +967,8 @@ expr_checkea_getregusage(expr **ep, int *indexreg, void *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.
@ -982,8 +983,7 @@ expr_checkea_getregusage(expr **ep, int *indexreg, void *data,
(*reg) +=
intnum_get_int(e->terms[i].data.expn->terms[1].data.intn);
if (indexreg)
*indexreg =
e->terms[i].data.expn->terms[0].data.reg.num;
*indexreg = reg-(int *)data;
}
}
break;
@ -998,6 +998,8 @@ expr_checkea_getregusage(expr **ep, int *indexreg, void *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! */
@ -1013,6 +1015,123 @@ expr_checkea_getregusage(expr **ep, int *indexreg, void *data,
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:
*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;
}
*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)
{
@ -1033,8 +1152,6 @@ expr_checkea(expr **ep, unsigned char *addrsize, unsigned char bits,
unsigned char *n_sib)
{
expr *e = *ep;
const intnum *intn;
long dispval;
if (*addrsize == 0) {
/* we need to figure out the address size from what we know about:
@ -1066,9 +1183,21 @@ expr_checkea(expr **ep, unsigned char *addrsize, unsigned char bits,
}
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 = 0;*/ /* "base" register (for SIB) */
int indexreg = 0; /* "index" register (for SIB) */
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)) {
@ -1083,6 +1212,153 @@ expr_checkea(expr **ep, unsigned char *addrsize, unsigned char bits,
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] */,
@ -1092,7 +1368,7 @@ expr_checkea(expr **ep, unsigned char *addrsize, unsigned char bits,
0003 /* [BP+DI] */, 0377 /* invalid */, 0377 /* invalid */,
0377 /* invalid */
};
checkea_invalid16_data reg16mult = {0, 0, 0, 0};
checkea_reg16_data reg16mult = {0, 0, 0, 0};
enum {
HAVE_NONE = 0,
HAVE_BX = 1<<0,
@ -1142,107 +1418,13 @@ expr_checkea(expr **ep, unsigned char *addrsize, unsigned char bits,
return 0;
}
/* Set ModRM byte for registers */
*modrm |= modrm16[havereg];
*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.
*/
switch (havereg) {
case HAVE_NONE:
/* no register in expression, so it must be disp16, and
* as the Mod bits are set to 0 above, we're done with
* the ModRM byte.
*/
*displen = 2;
*v_modrm = 1;
break;
case HAVE_BP:
/* for BP, there *must* be a displacement value, but we
* may not know the size (8 or 16) for sure right now.
* We can't leave displen at 0, because that just means
* unknown displacement, including none.
*/
*displen = 0xff;
break;
default:
break;
}
intn = expr_get_intnum(ep);
if (!intn)
break; /* expr still has unknown values */
/* make sure the displacement will fit in 16 bits if unsigned,
* and 8 bits if signed.
*/
if (!intnum_check_size(intn, 2, 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 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 HAVE_BP 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-bit displacement */
*displen = 2;
*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:
*modrm |= 0100;
*v_modrm = 1;
break;
case 2:
*modrm |= 0200;
*v_modrm = 1;
break;
default:
/* any other size is an error */
ErrorAt(e->filename, e->line,
_("invalid effective address (displacement size)"));
return 0;
}
/* Calculate displacement length (if possible) */
return checkea_calc_displen(ep, 2, havereg == HAVE_NONE,
havereg == HAVE_BP, displen, modrm,
v_modrm);
}
return 1;
}

@ -761,9 +761,9 @@ expr_checkea_get_reg32(ExprItem *ei, void *d)
return ret;
}
typedef struct checkea_invalid16_data {
typedef struct checkea_reg16_data {
int bx, si, di, bp; /* total multiplier for each reg */
} checkea_invalid16_data;
} 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).
@ -771,7 +771,7 @@ typedef struct checkea_invalid16_data {
static int *
expr_checkea_get_reg16(ExprItem *ei, void *d)
{
checkea_invalid16_data *data = 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;
@ -910,7 +910,7 @@ expr_checkea_distcheck_reg(expr **ep)
* where the [...] parts are optional.
*
* Don't simplify out constant identities if we're looking for an indexreg: we
* need the multiplier for determining what the indexreg is!
* 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.
@ -928,7 +928,6 @@ expr_checkea_getregusage(expr **ep, int *indexreg, void *data,
e = *ep;
switch (expr_checkea_distcheck_reg(ep)) {
case 0:
ErrorAt(e->filename, e->line, _("invalid effective address"));
return 0;
case 2:
/* Need to simplify again */
@ -968,6 +967,8 @@ expr_checkea_getregusage(expr **ep, int *indexreg, void *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.
@ -982,8 +983,7 @@ expr_checkea_getregusage(expr **ep, int *indexreg, void *data,
(*reg) +=
intnum_get_int(e->terms[i].data.expn->terms[1].data.intn);
if (indexreg)
*indexreg =
e->terms[i].data.expn->terms[0].data.reg.num;
*indexreg = reg-(int *)data;
}
}
break;
@ -998,6 +998,8 @@ expr_checkea_getregusage(expr **ep, int *indexreg, void *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! */
@ -1013,6 +1015,123 @@ expr_checkea_getregusage(expr **ep, int *indexreg, void *data,
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:
*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;
}
*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)
{
@ -1033,8 +1152,6 @@ expr_checkea(expr **ep, unsigned char *addrsize, unsigned char bits,
unsigned char *n_sib)
{
expr *e = *ep;
const intnum *intn;
long dispval;
if (*addrsize == 0) {
/* we need to figure out the address size from what we know about:
@ -1066,9 +1183,21 @@ expr_checkea(expr **ep, unsigned char *addrsize, unsigned char bits,
}
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 = 0;*/ /* "base" register (for SIB) */
int indexreg = 0; /* "index" register (for SIB) */
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)) {
@ -1083,6 +1212,153 @@ expr_checkea(expr **ep, unsigned char *addrsize, unsigned char bits,
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] */,
@ -1092,7 +1368,7 @@ expr_checkea(expr **ep, unsigned char *addrsize, unsigned char bits,
0003 /* [BP+DI] */, 0377 /* invalid */, 0377 /* invalid */,
0377 /* invalid */
};
checkea_invalid16_data reg16mult = {0, 0, 0, 0};
checkea_reg16_data reg16mult = {0, 0, 0, 0};
enum {
HAVE_NONE = 0,
HAVE_BX = 1<<0,
@ -1142,107 +1418,13 @@ expr_checkea(expr **ep, unsigned char *addrsize, unsigned char bits,
return 0;
}
/* Set ModRM byte for registers */
*modrm |= modrm16[havereg];
*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.
*/
switch (havereg) {
case HAVE_NONE:
/* no register in expression, so it must be disp16, and
* as the Mod bits are set to 0 above, we're done with
* the ModRM byte.
*/
*displen = 2;
*v_modrm = 1;
break;
case HAVE_BP:
/* for BP, there *must* be a displacement value, but we
* may not know the size (8 or 16) for sure right now.
* We can't leave displen at 0, because that just means
* unknown displacement, including none.
*/
*displen = 0xff;
break;
default:
break;
}
intn = expr_get_intnum(ep);
if (!intn)
break; /* expr still has unknown values */
/* make sure the displacement will fit in 16 bits if unsigned,
* and 8 bits if signed.
*/
if (!intnum_check_size(intn, 2, 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 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 HAVE_BP 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-bit displacement */
*displen = 2;
*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:
*modrm |= 0100;
*v_modrm = 1;
break;
case 2:
*modrm |= 0200;
*v_modrm = 1;
break;
default:
/* any other size is an error */
ErrorAt(e->filename, e->line,
_("invalid effective address (displacement size)"));
return 0;
}
/* Calculate displacement length (if possible) */
return checkea_calc_displen(ep, 2, havereg == HAVE_NONE,
havereg == HAVE_BP, displen, modrm,
v_modrm);
}
return 1;
}

@ -761,9 +761,9 @@ expr_checkea_get_reg32(ExprItem *ei, void *d)
return ret;
}
typedef struct checkea_invalid16_data {
typedef struct checkea_reg16_data {
int bx, si, di, bp; /* total multiplier for each reg */
} checkea_invalid16_data;
} 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).
@ -771,7 +771,7 @@ typedef struct checkea_invalid16_data {
static int *
expr_checkea_get_reg16(ExprItem *ei, void *d)
{
checkea_invalid16_data *data = 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;
@ -910,7 +910,7 @@ expr_checkea_distcheck_reg(expr **ep)
* where the [...] parts are optional.
*
* Don't simplify out constant identities if we're looking for an indexreg: we
* need the multiplier for determining what the indexreg is!
* 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.
@ -928,7 +928,6 @@ expr_checkea_getregusage(expr **ep, int *indexreg, void *data,
e = *ep;
switch (expr_checkea_distcheck_reg(ep)) {
case 0:
ErrorAt(e->filename, e->line, _("invalid effective address"));
return 0;
case 2:
/* Need to simplify again */
@ -968,6 +967,8 @@ expr_checkea_getregusage(expr **ep, int *indexreg, void *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.
@ -982,8 +983,7 @@ expr_checkea_getregusage(expr **ep, int *indexreg, void *data,
(*reg) +=
intnum_get_int(e->terms[i].data.expn->terms[1].data.intn);
if (indexreg)
*indexreg =
e->terms[i].data.expn->terms[0].data.reg.num;
*indexreg = reg-(int *)data;
}
}
break;
@ -998,6 +998,8 @@ expr_checkea_getregusage(expr **ep, int *indexreg, void *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! */
@ -1013,6 +1015,123 @@ expr_checkea_getregusage(expr **ep, int *indexreg, void *data,
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:
*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;
}
*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)
{
@ -1033,8 +1152,6 @@ expr_checkea(expr **ep, unsigned char *addrsize, unsigned char bits,
unsigned char *n_sib)
{
expr *e = *ep;
const intnum *intn;
long dispval;
if (*addrsize == 0) {
/* we need to figure out the address size from what we know about:
@ -1066,9 +1183,21 @@ expr_checkea(expr **ep, unsigned char *addrsize, unsigned char bits,
}
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 = 0;*/ /* "base" register (for SIB) */
int indexreg = 0; /* "index" register (for SIB) */
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)) {
@ -1083,6 +1212,153 @@ expr_checkea(expr **ep, unsigned char *addrsize, unsigned char bits,
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] */,
@ -1092,7 +1368,7 @@ expr_checkea(expr **ep, unsigned char *addrsize, unsigned char bits,
0003 /* [BP+DI] */, 0377 /* invalid */, 0377 /* invalid */,
0377 /* invalid */
};
checkea_invalid16_data reg16mult = {0, 0, 0, 0};
checkea_reg16_data reg16mult = {0, 0, 0, 0};
enum {
HAVE_NONE = 0,
HAVE_BX = 1<<0,
@ -1142,107 +1418,13 @@ expr_checkea(expr **ep, unsigned char *addrsize, unsigned char bits,
return 0;
}
/* Set ModRM byte for registers */
*modrm |= modrm16[havereg];
*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.
*/
switch (havereg) {
case HAVE_NONE:
/* no register in expression, so it must be disp16, and
* as the Mod bits are set to 0 above, we're done with
* the ModRM byte.
*/
*displen = 2;
*v_modrm = 1;
break;
case HAVE_BP:
/* for BP, there *must* be a displacement value, but we
* may not know the size (8 or 16) for sure right now.
* We can't leave displen at 0, because that just means
* unknown displacement, including none.
*/
*displen = 0xff;
break;
default:
break;
}
intn = expr_get_intnum(ep);
if (!intn)
break; /* expr still has unknown values */
/* make sure the displacement will fit in 16 bits if unsigned,
* and 8 bits if signed.
*/
if (!intnum_check_size(intn, 2, 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 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 HAVE_BP 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-bit displacement */
*displen = 2;
*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:
*modrm |= 0100;
*v_modrm = 1;
break;
case 2:
*modrm |= 0200;
*v_modrm = 1;
break;
default:
/* any other size is an error */
ErrorAt(e->filename, e->line,
_("invalid effective address (displacement size)"));
return 0;
}
/* Calculate displacement length (if possible) */
return checkea_calc_displen(ep, 2, havereg == HAVE_NONE,
havereg == HAVE_BP, displen, modrm,
v_modrm);
}
return 1;
}

Loading…
Cancel
Save