blob: e9ddcce57ecfcca14e64beb8d67d6098374a3dbb [file] [log] [blame]
/*
* 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>
#include <libyasm.h>
#include "x86arch.h"
typedef struct x86_checkea_reg3264_data {
int *regs; /* total multiplier for each reg */
unsigned char vsib_mode;
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_XMMREG:
if (data->vsib_mode != 1)
return 0;
if (data->bits != 64 && (ei->data.reg & 0x8) == 0x8)
return 0;
*regnum = 17+(unsigned int)(ei->data.reg & 0xF);
break;
case X86_YMMREG:
if (data->vsib_mode != 2)
return 0;
if (data->bits != 64 && (ei->data.reg & 0x8) == 0x8)
return 0;
*regnum = 17+(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], &regnum, 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], &regnum, 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],
&regnum, 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], &regnum, 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:
/* If SIB is required, but we're in 16-bit mode, set to 32. */
if (bits == 16 && x86_ea->need_sib == 1) {
*addrsize = 32;
break;
}
/* 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;
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,
SIMDREGS
};
int reg3264mult[33] =
{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
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) */
int regcount = 17; /* normally don't check SIMD regs */
if (x86_ea->vsib_mode != 0)
regcount = 33;
/* 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.vsib_mode = x86_ea->vsib_mode;
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,
&reg3264_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<regcount; 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;
}
if (x86_ea->vsib_mode != 0) {
/* For VSIB, the SIMD register needs to go into the indexreg.
* Also check basereg (must be a GPR if present) and indexreg
* (must be a SIMD register).
*/
if (basereg >= SIMDREGS &&
(indexreg == REG3264_NONE || reg3264mult[indexreg] == 1)) {
int temp = basereg;
basereg = indexreg;
indexreg = temp;
}
if (basereg >= REG64_RIP || indexreg < SIMDREGS) {
yasm_error_set(YASM_ERROR_VALUE,
N_("invalid effective address"));
return 1;
}
} else if (indexreg != REG3264_NONE && basereg == REG3264_NONE)
/* Handle certain special cases of indexreg mults when basereg is
* empty.
*/
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<regcount; 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 (indexreg >= SIMDREGS) {
if (yasm_x86__set_rex_from_reg(rex, &low3,
(unsigned int)(X86_XMMREG | (indexreg-SIMDREGS)),
bits, X86_REX_X))
return 1;
} 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,
&reg16mult, 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;
}