diff options
author | somov <somov@yandex-team.ru> | 2022-02-10 16:45:47 +0300 |
---|---|---|
committer | Daniil Cherednik <dcherednik@yandex-team.ru> | 2022-02-10 16:45:47 +0300 |
commit | a5950576e397b1909261050b8c7da16db58f10b1 (patch) | |
tree | 7ba7677f6a4c3e19e2cefab34d16df2c8963b4d4 /contrib/tools/yasm/modules/arch/x86/x86expr.c | |
parent | 81eddc8c0b55990194e112b02d127b87d54164a9 (diff) | |
download | ydb-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.c | 2122 |
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], ®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: - /* 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, - ®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<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, - ®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; -} +/* + * 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], ®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: + /* 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, + ®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<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, + ®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; +} |