aboutsummaryrefslogtreecommitdiffstats
path: root/contrib/tools/yasm/modules/arch/x86/x86expr.c
diff options
context:
space:
mode:
authorsomov <somov@yandex-team.ru>2022-02-10 16:45:47 +0300
committerDaniil Cherednik <dcherednik@yandex-team.ru>2022-02-10 16:45:47 +0300
commita5950576e397b1909261050b8c7da16db58f10b1 (patch)
tree7ba7677f6a4c3e19e2cefab34d16df2c8963b4d4 /contrib/tools/yasm/modules/arch/x86/x86expr.c
parent81eddc8c0b55990194e112b02d127b87d54164a9 (diff)
downloadydb-a5950576e397b1909261050b8c7da16db58f10b1.tar.gz
Restoring authorship annotation for <somov@yandex-team.ru>. Commit 1 of 2.
Diffstat (limited to 'contrib/tools/yasm/modules/arch/x86/x86expr.c')
-rw-r--r--contrib/tools/yasm/modules/arch/x86/x86expr.c2122
1 files changed, 1061 insertions, 1061 deletions
diff --git a/contrib/tools/yasm/modules/arch/x86/x86expr.c b/contrib/tools/yasm/modules/arch/x86/x86expr.c
index e9ddcce57e..141cdec2bf 100644
--- a/contrib/tools/yasm/modules/arch/x86/x86expr.c
+++ b/contrib/tools/yasm/modules/arch/x86/x86expr.c
@@ -1,1061 +1,1061 @@
-/*
- * 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;
-}
+/*
+ * 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;
+}