1013 lines
36 KiB
C
1013 lines
36 KiB
C
/*
|
|
* x86 expression handling
|
|
*
|
|
* Copyright (C) 2001-2007 Peter Johnson
|
|
*
|
|
* Redistribution and use in source and binary forms, with or without
|
|
* modification, are permitted provided that the following conditions
|
|
* are met:
|
|
* 1. Redistributions of source code must retain the above copyright
|
|
* notice, this list of conditions and the following disclaimer.
|
|
* 2. Redistributions in binary form must reproduce the above copyright
|
|
* notice, this list of conditions and the following disclaimer in the
|
|
* documentation and/or other materials provided with the distribution.
|
|
*
|
|
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND OTHER CONTRIBUTORS ``AS IS''
|
|
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
|
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
|
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR OTHER CONTRIBUTORS BE
|
|
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
|
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
|
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
|
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
|
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
|
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
|
* POSSIBILITY OF SUCH DAMAGE.
|
|
*/
|
|
#include <util.h>
|
|
/*@unused@*/ RCSID("$Id: x86expr.c 2199 2009-05-10 05:24:46Z peter $");
|
|
|
|
#include <libyasm.h>
|
|
|
|
#include "x86arch.h"
|
|
|
|
|
|
typedef struct x86_checkea_reg3264_data {
|
|
int *regs; /* total multiplier for each reg */
|
|
unsigned char bits;
|
|
unsigned char addrsize;
|
|
} x86_checkea_reg3264_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 /*@null@*/ /*@dependent@*/ int *
|
|
x86_expr_checkea_get_reg3264(yasm_expr__item *ei, int *regnum,
|
|
/*returned*/ void *d)
|
|
{
|
|
x86_checkea_reg3264_data *data = d;
|
|
|
|
switch ((x86_expritem_reg_size)(ei->data.reg & ~0xFUL)) {
|
|
case X86_REG32:
|
|
if (data->addrsize != 32)
|
|
return 0;
|
|
*regnum = (unsigned int)(ei->data.reg & 0xF);
|
|
break;
|
|
case X86_REG64:
|
|
if (data->addrsize != 64)
|
|
return 0;
|
|
*regnum = (unsigned int)(ei->data.reg & 0xF);
|
|
break;
|
|
case X86_RIP:
|
|
if (data->bits != 64)
|
|
return 0;
|
|
*regnum = 16;
|
|
break;
|
|
default:
|
|
return 0;
|
|
}
|
|
|
|
/* overwrite with 0 to eliminate register from displacement expr */
|
|
ei->type = YASM_EXPR_INT;
|
|
ei->data.intn = yasm_intnum_create_uint(0);
|
|
|
|
/* we're okay */
|
|
return &data->regs[*regnum];
|
|
}
|
|
|
|
typedef struct x86_checkea_reg16_data {
|
|
int bx, si, di, bp; /* total multiplier for each reg */
|
|
} x86_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 /*@null@*/ int *
|
|
x86_expr_checkea_get_reg16(yasm_expr__item *ei, int *regnum, void *d)
|
|
{
|
|
x86_checkea_reg16_data *data = d;
|
|
/* in order: ax,cx,dx,bx,sp,bp,si,di */
|
|
/*@-nullassign@*/
|
|
static int *reg16[8] = {0,0,0,0,0,0,0,0};
|
|
/*@=nullassign@*/
|
|
|
|
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 & ~0xFUL) != X86_REG16)
|
|
return 0;
|
|
|
|
/* & 7 for sanity check */
|
|
*regnum = (unsigned int)(ei->data.reg & 0x7);
|
|
|
|
/* only allow BX, SI, DI, BP */
|
|
if (!reg16[*regnum])
|
|
return 0;
|
|
|
|
/* overwrite with 0 to eliminate register from displacement expr */
|
|
ei->type = YASM_EXPR_INT;
|
|
ei->data.intn = yasm_intnum_create_uint(0);
|
|
|
|
/* we're okay */
|
|
return reg16[*regnum];
|
|
}
|
|
|
|
/* 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
|
|
x86_expr_checkea_distcheck_reg(yasm_expr **ep, unsigned int bits)
|
|
{
|
|
yasm_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 YASM_EXPR_REG:
|
|
/* Check op to make sure it's valid to use w/register. */
|
|
switch (e->op) {
|
|
case YASM_EXPR_MUL:
|
|
/* Check for reg*reg */
|
|
if (havereg != -1)
|
|
return 0;
|
|
break;
|
|
case YASM_EXPR_ADD:
|
|
case YASM_EXPR_IDENT:
|
|
break;
|
|
default:
|
|
return 0;
|
|
}
|
|
havereg = i;
|
|
break;
|
|
case YASM_EXPR_FLOAT:
|
|
/* Floats not allowed. */
|
|
return 0;
|
|
case YASM_EXPR_EXPR:
|
|
if (yasm_expr__contains(e->terms[i].data.expn,
|
|
YASM_EXPR_REG)) {
|
|
int ret2;
|
|
|
|
/* Check op to make sure it's valid to use w/register. */
|
|
if (e->op != YASM_EXPR_ADD && e->op != YASM_EXPR_MUL)
|
|
return 0;
|
|
/* Check for reg*reg */
|
|
if (e->op == YASM_EXPR_MUL && havereg != -1)
|
|
return 0;
|
|
havereg = i;
|
|
havereg_expr = i;
|
|
/* Recurse to check lower levels */
|
|
ret2 =
|
|
x86_expr_checkea_distcheck_reg(&e->terms[i].data.expn,
|
|
bits);
|
|
if (ret2 == 0)
|
|
return 0;
|
|
if (ret2 == 2)
|
|
retval = 2;
|
|
} else if (yasm_expr__contains(e->terms[i].data.expn,
|
|
YASM_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 == YASM_EXPR_MUL && havereg_expr != -1) {
|
|
yasm_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 != YASM_EXPR_EXPR ||
|
|
e->terms[havereg_expr].data.expn->op != YASM_EXPR_ADD)
|
|
yasm_internal_error(N_("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 = yasm_expr__copy_except(e, havereg_expr);
|
|
assert(ne != NULL);
|
|
/* 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 = YASM_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 = YASM_EXPR_NONE; /* don't delete it! */
|
|
yasm_expr_destroy(e); /* but everything else */
|
|
e = ne;
|
|
/*@-onlytrans@*/
|
|
*ep = ne;
|
|
/*@=onlytrans@*/
|
|
}
|
|
|
|
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 1 if invalid register usage, 2 if unable to determine all values,
|
|
* and 0 if all values successfully determined and saved in data.
|
|
*/
|
|
static int
|
|
x86_expr_checkea_getregusage(yasm_expr **ep, /*@null@*/ int *indexreg,
|
|
int *pcrel, unsigned int bits, void *data,
|
|
int *(*get_reg)(yasm_expr__item *ei, int *regnum, void *d))
|
|
{
|
|
int i;
|
|
int *reg;
|
|
int regnum;
|
|
int indexval = 0;
|
|
int indexmult = 0;
|
|
yasm_expr *e, *wrt;
|
|
|
|
/*@-unqualifiedtrans@*/
|
|
*ep = yasm_expr__level_tree(*ep, 1, 1, indexreg == 0, 0, NULL, NULL);
|
|
|
|
/* Check for WRT rip first */
|
|
wrt = yasm_expr_extract_wrt(ep);
|
|
if (wrt && wrt->op == YASM_EXPR_IDENT &&
|
|
wrt->terms[0].type == YASM_EXPR_REG) {
|
|
if (bits != 64) { /* only valid in 64-bit mode */
|
|
yasm_expr_destroy(wrt);
|
|
return 1;
|
|
}
|
|
reg = get_reg(&wrt->terms[0], ®num, data);
|
|
if (!reg || regnum != 16) { /* only accept rip */
|
|
yasm_expr_destroy(wrt);
|
|
return 1;
|
|
}
|
|
(*reg)++;
|
|
|
|
/* Delete WRT. Set pcrel to 1 to indicate to x86
|
|
* bytecode code to do PC-relative displacement transform.
|
|
*/
|
|
*pcrel = 1;
|
|
yasm_expr_destroy(wrt);
|
|
} else if (wrt) {
|
|
yasm_expr_destroy(wrt);
|
|
return 1;
|
|
}
|
|
|
|
/*@=unqualifiedtrans@*/
|
|
assert(*ep != NULL);
|
|
e = *ep;
|
|
switch (x86_expr_checkea_distcheck_reg(ep, bits)) {
|
|
case 0:
|
|
return 1;
|
|
case 2:
|
|
/* Need to simplify again */
|
|
*ep = yasm_expr__level_tree(*ep, 1, 1, indexreg == 0, 0, NULL,
|
|
NULL);
|
|
e = *ep;
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
|
|
switch (e->op) {
|
|
case YASM_EXPR_ADD:
|
|
/* Prescan for non-int multipliers against a reg.
|
|
* This is invalid due to the optimizer structure.
|
|
*/
|
|
for (i=0; i<e->numterms; i++)
|
|
if (e->terms[i].type == YASM_EXPR_EXPR) {
|
|
yasm_expr__order_terms(e->terms[i].data.expn);
|
|
if (e->terms[i].data.expn->terms[0].type ==
|
|
YASM_EXPR_REG) {
|
|
if (e->terms[i].data.expn->numterms > 2)
|
|
return 1;
|
|
if (e->terms[i].data.expn->terms[1].type !=
|
|
YASM_EXPR_INT)
|
|
return 1;
|
|
}
|
|
}
|
|
|
|
/*@fallthrough@*/
|
|
case YASM_EXPR_IDENT:
|
|
/* Check each term for register (and possible multiplier). */
|
|
for (i=0; i<e->numterms; i++) {
|
|
if (e->terms[i].type == YASM_EXPR_REG) {
|
|
reg = get_reg(&e->terms[i], ®num, data);
|
|
if (!reg)
|
|
return 1;
|
|
(*reg)++;
|
|
/* Let last, largest multipler win indexreg */
|
|
if (indexreg && *reg > 0 && indexval <= *reg &&
|
|
!indexmult) {
|
|
*indexreg = regnum;
|
|
indexval = *reg;
|
|
}
|
|
} else if (e->terms[i].type == YASM_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 ==
|
|
YASM_EXPR_REG) {
|
|
long delta;
|
|
if (e->terms[i].data.expn->terms[1].type !=
|
|
YASM_EXPR_INT)
|
|
yasm_internal_error(
|
|
N_("Non-integer value in reg expn"));
|
|
reg = get_reg(&e->terms[i].data.expn->terms[0],
|
|
®num, data);
|
|
if (!reg)
|
|
return 1;
|
|
delta = yasm_intnum_get_int(
|
|
e->terms[i].data.expn->terms[1].data.intn);
|
|
(*reg) += delta;
|
|
/* Let last, largest multipler win indexreg */
|
|
if (indexreg && delta > 0 && indexval <= *reg) {
|
|
*indexreg = regnum;
|
|
indexval = *reg;
|
|
indexmult = 1;
|
|
} else if (indexreg && *indexreg == regnum &&
|
|
delta < 0 && *reg <= 1) {
|
|
*indexreg = -1;
|
|
indexval = 0;
|
|
indexmult = 0;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
break;
|
|
case YASM_EXPR_MUL:
|
|
/* Here, too, check for non-int multipliers against a reg. */
|
|
yasm_expr__order_terms(e);
|
|
if (e->terms[0].type == YASM_EXPR_REG) {
|
|
long delta;
|
|
if (e->numterms > 2)
|
|
return 1;
|
|
if (e->terms[1].type != YASM_EXPR_INT)
|
|
return 1;
|
|
reg = get_reg(&e->terms[0], ®num, data);
|
|
if (!reg)
|
|
return 1;
|
|
delta = yasm_intnum_get_int(e->terms[1].data.intn);
|
|
(*reg) += delta;
|
|
if (indexreg)
|
|
{
|
|
if (delta < 0 && *reg <= 1)
|
|
{
|
|
*indexreg = -1;
|
|
indexval = 0;
|
|
indexmult = 0;
|
|
}
|
|
else
|
|
*indexreg = regnum;
|
|
}
|
|
}
|
|
break;
|
|
case YASM_EXPR_SEGOFF:
|
|
/* No registers are allowed on either side. */
|
|
if (yasm_expr__contains(e, YASM_EXPR_REG))
|
|
return 1;
|
|
break;
|
|
default:
|
|
/* Should never get here! */
|
|
yasm_internal_error(N_("unexpected expr op"));
|
|
}
|
|
|
|
/* 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 = yasm_expr_simplify(*ep, 0);
|
|
/* e = *ep; */
|
|
|
|
return 0;
|
|
}
|
|
|
|
/* Calculate the displacement length, if possible.
|
|
* Takes several extra inputs so it can be used by both 32-bit and 16-bit
|
|
* expressions:
|
|
* wordsize=16 for 16-bit, =32 for 32-bit.
|
|
* noreg=1 if the *ModRM byte* has no registers used.
|
|
* dispreq=1 if a displacement value is *required* (even if =0).
|
|
* Returns 0 if successfully calculated, 1 if not.
|
|
*/
|
|
/*@-nullstate@*/
|
|
static int
|
|
x86_checkea_calc_displen(x86_effaddr *x86_ea, unsigned int wordsize, int noreg,
|
|
int dispreq)
|
|
{
|
|
/*@null@*/ /*@only@*/ yasm_intnum *num;
|
|
|
|
x86_ea->valid_modrm = 0; /* default to not yet valid */
|
|
|
|
switch (x86_ea->ea.disp.size) {
|
|
case 0:
|
|
break;
|
|
/* If not 0, the displacement length was forced; set the Mod bits
|
|
* appropriately and we're done with the ModRM byte.
|
|
*/
|
|
case 8:
|
|
/* Byte is only a valid override if there are registers in the
|
|
* EA. With no registers, we must have a 16/32 value.
|
|
*/
|
|
if (noreg) {
|
|
yasm_warn_set(YASM_WARN_IMPLICIT_SIZE_OVERRIDE,
|
|
N_("invalid displacement size; fixed"));
|
|
x86_ea->ea.disp.size = wordsize;
|
|
} else
|
|
x86_ea->modrm |= 0100;
|
|
x86_ea->valid_modrm = 1;
|
|
return 0;
|
|
case 16:
|
|
case 32:
|
|
/* Don't allow changing displacement different from BITS setting
|
|
* directly; require an address-size override to change it.
|
|
*/
|
|
if (wordsize != x86_ea->ea.disp.size) {
|
|
yasm_error_set(YASM_ERROR_VALUE,
|
|
N_("invalid effective address (displacement size)"));
|
|
return 1;
|
|
}
|
|
if (!noreg)
|
|
x86_ea->modrm |= 0200;
|
|
x86_ea->valid_modrm = 1;
|
|
return 0;
|
|
default:
|
|
/* we shouldn't ever get any other size! */
|
|
yasm_internal_error(N_("strange EA displacement size"));
|
|
}
|
|
|
|
/* The displacement length hasn't been forced (or the forcing wasn't
|
|
* valid), 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.
|
|
*/
|
|
x86_ea->ea.disp.size = wordsize;
|
|
x86_ea->valid_modrm = 1;
|
|
return 0;
|
|
}
|
|
|
|
if (dispreq) {
|
|
/* for BP/EBP, there *must* be a displacement value, but we
|
|
* may not know the size (8 or 16/32) for sure right now.
|
|
*/
|
|
x86_ea->ea.need_nonzero_len = 1;
|
|
}
|
|
|
|
if (x86_ea->ea.disp.rel) {
|
|
/* Relative displacement; basically all object formats need non-byte
|
|
* for relocation here, so just do that. (TODO: handle this
|
|
* differently?)
|
|
*/
|
|
x86_ea->ea.disp.size = wordsize;
|
|
x86_ea->modrm |= 0200;
|
|
x86_ea->valid_modrm = 1;
|
|
return 0;
|
|
}
|
|
|
|
/* At this point there's 3 possibilities for the displacement:
|
|
* - None (if =0)
|
|
* - signed 8 bit (if in -128 to 127 range)
|
|
* - 16/32 bit (word size)
|
|
* For now, check intnum value right now; if it's not 0,
|
|
* assume 8 bit and set up for allowing 16 bit later.
|
|
* FIXME: The complex expression equaling zero is probably a rare case,
|
|
* so we ignore it for now.
|
|
*/
|
|
num = yasm_value_get_intnum(&x86_ea->ea.disp, NULL, 0);
|
|
if (!num) {
|
|
/* Still has unknown values. */
|
|
x86_ea->ea.need_nonzero_len = 1;
|
|
x86_ea->modrm |= 0100;
|
|
x86_ea->valid_modrm = 1;
|
|
return 0;
|
|
}
|
|
|
|
/* Figure out what size displacement we will have. */
|
|
if (yasm_intnum_is_zero(num) && !x86_ea->ea.need_nonzero_len) {
|
|
/* If we know that the displacement is 0 right now,
|
|
* go ahead and delete the expr and make it so no
|
|
* displacement value is included in the output.
|
|
* The Mod bits of ModRM are set to 0 above, and
|
|
* we're done with the ModRM byte!
|
|
*/
|
|
yasm_value_delete(&x86_ea->ea.disp);
|
|
x86_ea->ea.need_disp = 0;
|
|
} else if (yasm_intnum_in_range(num, -128, 127)) {
|
|
/* It fits into a signed byte */
|
|
x86_ea->ea.disp.size = 8;
|
|
x86_ea->modrm |= 0100;
|
|
} else {
|
|
/* It's a 16/32-bit displacement */
|
|
x86_ea->ea.disp.size = wordsize;
|
|
x86_ea->modrm |= 0200;
|
|
}
|
|
x86_ea->valid_modrm = 1; /* We're done with ModRM */
|
|
|
|
yasm_intnum_destroy(num);
|
|
return 0;
|
|
}
|
|
/*@=nullstate@*/
|
|
|
|
static int
|
|
x86_expr_checkea_getregsize_callback(yasm_expr__item *ei, void *d)
|
|
{
|
|
unsigned char *addrsize = (unsigned char *)d;
|
|
|
|
if (ei->type == YASM_EXPR_REG) {
|
|
switch ((x86_expritem_reg_size)(ei->data.reg & ~0xFUL)) {
|
|
case X86_REG16:
|
|
*addrsize = 16;
|
|
break;
|
|
case X86_REG32:
|
|
*addrsize = 32;
|
|
break;
|
|
case X86_REG64:
|
|
case X86_RIP:
|
|
*addrsize = 64;
|
|
break;
|
|
default:
|
|
return 0;
|
|
}
|
|
return 1;
|
|
} else
|
|
return 0;
|
|
}
|
|
|
|
int
|
|
yasm_x86__expr_checkea(x86_effaddr *x86_ea, unsigned char *addrsize,
|
|
unsigned int bits, int address16_op, unsigned char *rex,
|
|
yasm_bytecode *bc)
|
|
{
|
|
int retval;
|
|
|
|
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 (x86_ea->ea.disp.size) {
|
|
case 16:
|
|
/* must be 16-bit */
|
|
*addrsize = 16;
|
|
break;
|
|
case 64:
|
|
/* We have to support this for the MemOffs case, but it's
|
|
* otherwise illegal. It's also illegal in non-64-bit mode.
|
|
*/
|
|
if (x86_ea->need_modrm || x86_ea->need_sib) {
|
|
yasm_error_set(YASM_ERROR_VALUE,
|
|
N_("invalid effective address (displacement size)"));
|
|
return 1;
|
|
}
|
|
*addrsize = 64;
|
|
break;
|
|
case 32:
|
|
/* Must be 32-bit in 16-bit or 32-bit modes. In 64-bit mode,
|
|
* we don't know unless we look at the registers, except in the
|
|
* MemOffs case (see the end of this function).
|
|
*/
|
|
if (bits != 64 || (!x86_ea->need_modrm && !x86_ea->need_sib)) {
|
|
*addrsize = 32;
|
|
break;
|
|
}
|
|
/*@fallthrough@*/
|
|
default:
|
|
/* check for use of 16 or 32-bit registers; if none are used
|
|
* default to bits setting.
|
|
*/
|
|
if (!x86_ea->ea.disp.abs ||
|
|
!yasm_expr__traverse_leaves_in(x86_ea->ea.disp.abs,
|
|
addrsize, x86_expr_checkea_getregsize_callback))
|
|
*addrsize = bits;
|
|
/* TODO: Add optional warning here if switched address size
|
|
* from bits setting just by register use.. eg [ax] in
|
|
* 32-bit mode would generate a warning.
|
|
*/
|
|
}
|
|
}
|
|
|
|
if ((*addrsize == 32 || *addrsize == 64) &&
|
|
((x86_ea->need_modrm && !x86_ea->valid_modrm) ||
|
|
(x86_ea->need_sib && !x86_ea->valid_sib))) {
|
|
int i;
|
|
unsigned char low3;
|
|
typedef enum {
|
|
REG3264_NONE = -1,
|
|
REG3264_EAX = 0,
|
|
REG3264_ECX,
|
|
REG3264_EDX,
|
|
REG3264_EBX,
|
|
REG3264_ESP,
|
|
REG3264_EBP,
|
|
REG3264_ESI,
|
|
REG3264_EDI,
|
|
REG64_R8,
|
|
REG64_R9,
|
|
REG64_R10,
|
|
REG64_R11,
|
|
REG64_R12,
|
|
REG64_R13,
|
|
REG64_R14,
|
|
REG64_R15,
|
|
REG64_RIP
|
|
} reg3264type;
|
|
int reg3264mult[17] = {0, 0, 0, 0, 0, 0, 0, 0,
|
|
0, 0, 0, 0, 0, 0, 0, 0, 0};
|
|
x86_checkea_reg3264_data reg3264_data;
|
|
int basereg = REG3264_NONE; /* "base" register (for SIB) */
|
|
int indexreg = REG3264_NONE; /* "index" register (for SIB) */
|
|
|
|
/* We can only do 64-bit addresses in 64-bit mode. */
|
|
if (*addrsize == 64 && bits != 64) {
|
|
yasm_error_set(YASM_ERROR_TYPE,
|
|
N_("invalid effective address (64-bit in non-64-bit mode)"));
|
|
return 1;
|
|
}
|
|
|
|
if (x86_ea->ea.pc_rel && bits != 64) {
|
|
yasm_warn_set(YASM_WARN_GENERAL,
|
|
N_("RIP-relative directive ignored in non-64-bit mode"));
|
|
x86_ea->ea.pc_rel = 0;
|
|
}
|
|
|
|
reg3264_data.regs = reg3264mult;
|
|
reg3264_data.bits = bits;
|
|
reg3264_data.addrsize = *addrsize;
|
|
if (x86_ea->ea.disp.abs) {
|
|
int pcrel = 0;
|
|
switch (x86_expr_checkea_getregusage
|
|
(&x86_ea->ea.disp.abs, &indexreg, &pcrel, bits,
|
|
®3264_data, x86_expr_checkea_get_reg3264)) {
|
|
case 1:
|
|
yasm_error_set(YASM_ERROR_VALUE,
|
|
N_("invalid effective address"));
|
|
return 1;
|
|
case 2:
|
|
if (pcrel)
|
|
yasm_value_set_curpos_rel(&x86_ea->ea.disp, bc, 1);
|
|
return 2;
|
|
default:
|
|
if (pcrel)
|
|
yasm_value_set_curpos_rel(&x86_ea->ea.disp, bc, 1);
|
|
break;
|
|
}
|
|
}
|
|
|
|
/* If indexreg mult is 0, discard it.
|
|
* This is possible because of the way indexreg is found in
|
|
* expr_checkea_getregusage().
|
|
*/
|
|
if (indexreg != REG3264_NONE && reg3264mult[indexreg] == 0)
|
|
indexreg = REG3264_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<17; i++) {
|
|
if (reg3264mult[i] < 0) {
|
|
yasm_error_set(YASM_ERROR_VALUE,
|
|
N_("invalid effective address"));
|
|
return 1;
|
|
}
|
|
if (i != indexreg && reg3264mult[i] == 1 &&
|
|
basereg == REG3264_NONE)
|
|
basereg = i;
|
|
else if (indexreg == REG3264_NONE && reg3264mult[i] > 0)
|
|
indexreg = i;
|
|
}
|
|
|
|
/* Handle certain special cases of indexreg mults when basereg is
|
|
* empty.
|
|
*/
|
|
if (indexreg != REG3264_NONE && basereg == REG3264_NONE)
|
|
switch (reg3264mult[indexreg]) {
|
|
case 1:
|
|
/* Only optimize this way if nosplit wasn't specified */
|
|
if (!x86_ea->ea.nosplit) {
|
|
basereg = indexreg;
|
|
indexreg = -1;
|
|
}
|
|
break;
|
|
case 2:
|
|
/* Only split if nosplit wasn't specified */
|
|
if (!x86_ea->ea.nosplit) {
|
|
basereg = indexreg;
|
|
reg3264mult[indexreg] = 1;
|
|
}
|
|
break;
|
|
case 3:
|
|
case 5:
|
|
case 9:
|
|
basereg = indexreg;
|
|
reg3264mult[indexreg]--;
|
|
break;
|
|
}
|
|
|
|
/* Make sure there's no other registers than the basereg and indexreg
|
|
* we just found.
|
|
*/
|
|
for (i=0; i<17; i++)
|
|
if (i != basereg && i != indexreg && reg3264mult[i] != 0) {
|
|
yasm_error_set(YASM_ERROR_VALUE,
|
|
N_("invalid effective address"));
|
|
return 1;
|
|
}
|
|
|
|
/* Check the index multiplier value for validity if present. */
|
|
if (indexreg != REG3264_NONE && reg3264mult[indexreg] != 1 &&
|
|
reg3264mult[indexreg] != 2 && reg3264mult[indexreg] != 4 &&
|
|
reg3264mult[indexreg] != 8) {
|
|
yasm_error_set(YASM_ERROR_VALUE, N_("invalid effective address"));
|
|
return 1;
|
|
}
|
|
|
|
/* ESP is not a legal indexreg. */
|
|
if (indexreg == REG3264_ESP) {
|
|
/* If mult>1 or basereg is ESP also, there's no way to make it
|
|
* legal.
|
|
*/
|
|
if (reg3264mult[REG3264_ESP] > 1 || basereg == REG3264_ESP) {
|
|
yasm_error_set(YASM_ERROR_VALUE,
|
|
N_("invalid effective address"));
|
|
return 1;
|
|
}
|
|
/* If mult==1 and basereg is not ESP, swap indexreg w/basereg. */
|
|
indexreg = basereg;
|
|
basereg = REG3264_ESP;
|
|
}
|
|
|
|
/* RIP is only legal if it's the ONLY register used. */
|
|
if (indexreg == REG64_RIP ||
|
|
(basereg == REG64_RIP && indexreg != REG3264_NONE)) {
|
|
yasm_error_set(YASM_ERROR_VALUE, N_("invalid effective address"));
|
|
return 1;
|
|
}
|
|
|
|
/* 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.
|
|
*/
|
|
|
|
/* If we're supposed to be RIP-relative and there's no register
|
|
* usage, change to RIP-relative.
|
|
*/
|
|
if (basereg == REG3264_NONE && indexreg == REG3264_NONE &&
|
|
x86_ea->ea.pc_rel) {
|
|
basereg = REG64_RIP;
|
|
yasm_value_set_curpos_rel(&x86_ea->ea.disp, bc, 1);
|
|
}
|
|
|
|
/* First determine R/M (Mod is later determined from disp size) */
|
|
x86_ea->need_modrm = 1; /* we always need ModRM */
|
|
if (basereg == REG3264_NONE && indexreg == REG3264_NONE) {
|
|
/* Just a disp32: in 64-bit mode the RM encoding is used for RIP
|
|
* offset addressing, so we need to use the SIB form instead.
|
|
*/
|
|
if (bits == 64) {
|
|
x86_ea->modrm |= 4;
|
|
x86_ea->need_sib = 1;
|
|
} else {
|
|
x86_ea->modrm |= 5;
|
|
x86_ea->sib = 0;
|
|
x86_ea->valid_sib = 0;
|
|
x86_ea->need_sib = 0;
|
|
}
|
|
} else if (basereg == REG64_RIP) {
|
|
x86_ea->modrm |= 5;
|
|
x86_ea->sib = 0;
|
|
x86_ea->valid_sib = 0;
|
|
x86_ea->need_sib = 0;
|
|
/* RIP always requires a 32-bit displacement */
|
|
x86_ea->valid_modrm = 1;
|
|
x86_ea->ea.disp.size = 32;
|
|
return 0;
|
|
} else if (indexreg == REG3264_NONE) {
|
|
/* basereg only */
|
|
/* Don't need to go to the full effort of determining what type
|
|
* of register basereg is, as x86_set_rex_from_reg doesn't pay
|
|
* much attention.
|
|
*/
|
|
if (yasm_x86__set_rex_from_reg(rex, &low3,
|
|
(unsigned int)(X86_REG64 | basereg),
|
|
bits, X86_REX_B))
|
|
return 1;
|
|
x86_ea->modrm |= low3;
|
|
/* we don't need an SIB *unless* basereg is ESP or R12 */
|
|
if (basereg == REG3264_ESP || basereg == REG64_R12)
|
|
x86_ea->need_sib = 1;
|
|
else {
|
|
x86_ea->sib = 0;
|
|
x86_ea->valid_sib = 0;
|
|
x86_ea->need_sib = 0;
|
|
}
|
|
} else {
|
|
/* index or both base and index */
|
|
x86_ea->modrm |= 4;
|
|
x86_ea->need_sib = 1;
|
|
}
|
|
|
|
/* Determine SIB if needed */
|
|
if (x86_ea->need_sib == 1) {
|
|
x86_ea->sib = 0; /* start with 0 */
|
|
|
|
/* Special case: no basereg */
|
|
if (basereg == REG3264_NONE)
|
|
x86_ea->sib |= 5;
|
|
else {
|
|
if (yasm_x86__set_rex_from_reg(rex, &low3, (unsigned int)
|
|
(X86_REG64 | basereg), bits,
|
|
X86_REX_B))
|
|
return 1;
|
|
x86_ea->sib |= low3;
|
|
}
|
|
|
|
/* Put in indexreg, checking for none case */
|
|
if (indexreg == REG3264_NONE)
|
|
x86_ea->sib |= 040;
|
|
/* Any scale field is valid, just leave at 0. */
|
|
else {
|
|
if (yasm_x86__set_rex_from_reg(rex, &low3, (unsigned int)
|
|
(X86_REG64 | indexreg), bits,
|
|
X86_REX_X))
|
|
return 1;
|
|
x86_ea->sib |= low3 << 3;
|
|
/* Set scale field, 1 case -> 0, so don't bother. */
|
|
switch (reg3264mult[indexreg]) {
|
|
case 2:
|
|
x86_ea->sib |= 0100;
|
|
break;
|
|
case 4:
|
|
x86_ea->sib |= 0200;
|
|
break;
|
|
case 8:
|
|
x86_ea->sib |= 0300;
|
|
break;
|
|
}
|
|
}
|
|
|
|
x86_ea->valid_sib = 1; /* Done with SIB */
|
|
}
|
|
|
|
/* Calculate displacement length (if possible) */
|
|
retval = x86_checkea_calc_displen
|
|
(x86_ea, 32, basereg == REG3264_NONE,
|
|
basereg == REG3264_EBP || basereg == REG64_R13);
|
|
return retval;
|
|
} else if (*addrsize == 16 && x86_ea->need_modrm && !x86_ea->valid_modrm) {
|
|
static const unsigned char modrm16[16] = {
|
|
0006 /* disp16 */, 0007 /* [BX] */, 0004 /* [SI] */,
|
|
0000 /* [BX+SI] */, 0005 /* [DI] */, 0001 /* [BX+DI] */,
|
|
0377 /* invalid */, 0377 /* invalid */, 0006 /* [BP]+d */,
|
|
0377 /* invalid */, 0002 /* [BP+SI] */, 0377 /* invalid */,
|
|
0003 /* [BP+DI] */, 0377 /* invalid */, 0377 /* invalid */,
|
|
0377 /* invalid */
|
|
};
|
|
x86_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;
|
|
|
|
/* 64-bit mode does not allow 16-bit addresses */
|
|
if (bits == 64 && !address16_op) {
|
|
yasm_error_set(YASM_ERROR_TYPE,
|
|
N_("16-bit addresses not supported in 64-bit mode"));
|
|
return 1;
|
|
}
|
|
|
|
/* 16-bit cannot have SIB */
|
|
x86_ea->sib = 0;
|
|
x86_ea->valid_sib = 0;
|
|
x86_ea->need_sib = 0;
|
|
|
|
if (x86_ea->ea.disp.abs) {
|
|
int pcrel = 0;
|
|
switch (x86_expr_checkea_getregusage
|
|
(&x86_ea->ea.disp.abs, (int *)NULL, &pcrel, bits,
|
|
®16mult, x86_expr_checkea_get_reg16)) {
|
|
case 1:
|
|
yasm_error_set(YASM_ERROR_VALUE,
|
|
N_("invalid effective address"));
|
|
return 1;
|
|
case 2:
|
|
if (pcrel)
|
|
yasm_value_set_curpos_rel(&x86_ea->ea.disp, bc, 1);
|
|
return 2;
|
|
default:
|
|
if (pcrel)
|
|
yasm_value_set_curpos_rel(&x86_ea->ea.disp, bc, 1);
|
|
break;
|
|
}
|
|
}
|
|
|
|
/* reg multipliers not 0 or 1 are illegal. */
|
|
if (reg16mult.bx & ~1 || reg16mult.si & ~1 || reg16mult.di & ~1 ||
|
|
reg16mult.bp & ~1) {
|
|
yasm_error_set(YASM_ERROR_VALUE, N_("invalid effective address"));
|
|
return 1;
|
|
}
|
|
|
|
/* 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) {
|
|
yasm_error_set(YASM_ERROR_VALUE, N_("invalid effective address"));
|
|
return 1;
|
|
}
|
|
|
|
/* Set ModRM byte for registers */
|
|
x86_ea->modrm |= modrm16[havereg];
|
|
|
|
/* Calculate displacement length (if possible) */
|
|
retval = x86_checkea_calc_displen
|
|
(x86_ea, 16, havereg == HAVE_NONE, havereg == HAVE_BP);
|
|
return retval;
|
|
} else if (!x86_ea->need_modrm && !x86_ea->need_sib) {
|
|
/* Special case for MOV MemOffs opcode: displacement but no modrm. */
|
|
switch (*addrsize) {
|
|
case 64:
|
|
if (bits != 64) {
|
|
yasm_error_set(YASM_ERROR_TYPE,
|
|
N_("invalid effective address (64-bit in non-64-bit mode)"));
|
|
return 1;
|
|
}
|
|
x86_ea->ea.disp.size = 64;
|
|
break;
|
|
case 32:
|
|
x86_ea->ea.disp.size = 32;
|
|
break;
|
|
case 16:
|
|
/* 64-bit mode does not allow 16-bit addresses */
|
|
if (bits == 64 && !address16_op) {
|
|
yasm_error_set(YASM_ERROR_TYPE,
|
|
N_("16-bit addresses not supported in 64-bit mode"));
|
|
return 1;
|
|
}
|
|
x86_ea->ea.disp.size = 16;
|
|
break;
|
|
}
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
int
|
|
yasm_x86__floatnum_tobytes(yasm_arch *arch, const yasm_floatnum *flt,
|
|
unsigned char *buf, size_t destsize, size_t valsize,
|
|
size_t shift, int warn)
|
|
{
|
|
if (!yasm_floatnum_check_size(flt, valsize)) {
|
|
yasm_error_set(YASM_ERROR_FLOATING_POINT,
|
|
N_("invalid floating point constant size"));
|
|
return 1;
|
|
}
|
|
|
|
yasm_floatnum_get_sized(flt, buf, destsize, valsize, shift, 0, warn);
|
|
return 0;
|
|
}
|