/* * 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 /*@unused@*/ RCSID("$Id: x86expr.c 2199 2009-05-10 05:24:46Z peter $"); #include #include "x86arch.h" typedef struct x86_checkea_reg3264_data { int *regs; /* total multiplier for each reg */ unsigned char bits; unsigned char addrsize; } x86_checkea_reg3264_data; /* Only works if ei->type == EXPR_REG (doesn't check). * Overwrites ei with intnum of 0 (to eliminate regs from the final expr). */ static /*@null@*/ /*@dependent@*/ int * x86_expr_checkea_get_reg3264(yasm_expr__item *ei, int *regnum, /*returned*/ void *d) { x86_checkea_reg3264_data *data = d; switch ((x86_expritem_reg_size)(ei->data.reg & ~0xFUL)) { case X86_REG32: if (data->addrsize != 32) return 0; *regnum = (unsigned int)(ei->data.reg & 0xF); break; case X86_REG64: if (data->addrsize != 64) return 0; *regnum = (unsigned int)(ei->data.reg & 0xF); break; case X86_RIP: if (data->bits != 64) return 0; *regnum = 16; break; default: return 0; } /* overwrite with 0 to eliminate register from displacement expr */ ei->type = YASM_EXPR_INT; ei->data.intn = yasm_intnum_create_uint(0); /* we're okay */ return &data->regs[*regnum]; } typedef struct x86_checkea_reg16_data { int bx, si, di, bp; /* total multiplier for each reg */ } x86_checkea_reg16_data; /* Only works if ei->type == EXPR_REG (doesn't check). * Overwrites ei with intnum of 0 (to eliminate regs from the final expr). */ static /*@null@*/ int * x86_expr_checkea_get_reg16(yasm_expr__item *ei, int *regnum, void *d) { x86_checkea_reg16_data *data = d; /* in order: ax,cx,dx,bx,sp,bp,si,di */ /*@-nullassign@*/ static int *reg16[8] = {0,0,0,0,0,0,0,0}; /*@=nullassign@*/ reg16[3] = &data->bx; reg16[5] = &data->bp; reg16[6] = &data->si; reg16[7] = &data->di; /* don't allow 32-bit registers */ if ((ei->data.reg & ~0xFUL) != X86_REG16) return 0; /* & 7 for sanity check */ *regnum = (unsigned int)(ei->data.reg & 0x7); /* only allow BX, SI, DI, BP */ if (!reg16[*regnum]) return 0; /* overwrite with 0 to eliminate register from displacement expr */ ei->type = YASM_EXPR_INT; ei->data.intn = yasm_intnum_create_uint(0); /* we're okay */ return reg16[*regnum]; } /* Distribute over registers to help bring them to the topmost level of e. * Also check for illegal operations against registers. * Returns 0 if something was illegal, 1 if legal and nothing in e changed, * and 2 if legal and e needs to be simplified. * * Only half joking: Someday make this/checkea able to accept crazy things * like: (bx+di)*(bx+di)-bx*bx-2*bx*di-di*di+di? Probably not: NASM never * accepted such things, and it's doubtful such an expn is valid anyway * (even though the above one is). But even macros would be hard-pressed * to generate something like this. * * e must already have been simplified for this function to work properly * (as it doesn't think things like SUB are valid). * * IMPLEMENTATION NOTE: About the only thing this function really needs to * "distribute" is: (non-float-expn or intnum) * (sum expn of registers). * * TODO: Clean up this code, make it easier to understand. */ static int x86_expr_checkea_distcheck_reg(yasm_expr **ep, unsigned int bits) { yasm_expr *e = *ep; int i; int havereg = -1, havereg_expr = -1; int retval = 1; /* default to legal, no changes */ for (i=0; inumterms; 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; iterms[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; inumterms; 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; inumterms; i++) { if (e->terms[i].type == YASM_EXPR_REG) { reg = get_reg(&e->terms[i], ®num, data); if (!reg) return 1; (*reg)++; /* Let last, largest multipler win indexreg */ if (indexreg && *reg > 0 && indexval <= *reg && !indexmult) { *indexreg = regnum; indexval = *reg; } } else if (e->terms[i].type == YASM_EXPR_EXPR) { /* Already ordered from ADD above, just grab the value. * Sanity check for EXPR_INT. */ if (e->terms[i].data.expn->terms[0].type == YASM_EXPR_REG) { long delta; if (e->terms[i].data.expn->terms[1].type != YASM_EXPR_INT) yasm_internal_error( N_("Non-integer value in reg expn")); reg = get_reg(&e->terms[i].data.expn->terms[0], ®num, data); if (!reg) return 1; delta = yasm_intnum_get_int( e->terms[i].data.expn->terms[1].data.intn); (*reg) += delta; /* Let last, largest multipler win indexreg */ if (indexreg && delta > 0 && indexval <= *reg) { *indexreg = regnum; indexval = *reg; indexmult = 1; } else if (indexreg && *indexreg == regnum && delta < 0 && *reg <= 1) { *indexreg = -1; indexval = 0; indexmult = 0; } } } } break; case YASM_EXPR_MUL: /* Here, too, check for non-int multipliers against a reg. */ yasm_expr__order_terms(e); if (e->terms[0].type == YASM_EXPR_REG) { long delta; if (e->numterms > 2) return 1; if (e->terms[1].type != YASM_EXPR_INT) return 1; reg = get_reg(&e->terms[0], ®num, data); if (!reg) return 1; delta = yasm_intnum_get_int(e->terms[1].data.intn); (*reg) += delta; if (indexreg) { if (delta < 0 && *reg <= 1) { *indexreg = -1; indexval = 0; indexmult = 0; } else *indexreg = regnum; } } break; case YASM_EXPR_SEGOFF: /* No registers are allowed on either side. */ if (yasm_expr__contains(e, YASM_EXPR_REG)) return 1; break; default: /* Should never get here! */ yasm_internal_error(N_("unexpected expr op")); } /* Simplify expr, which is now really just the displacement. This * should get rid of the 0's we put in for registers in the callback. */ *ep = yasm_expr_simplify(*ep, 0); /* e = *ep; */ return 0; } /* Calculate the displacement length, if possible. * Takes several extra inputs so it can be used by both 32-bit and 16-bit * expressions: * wordsize=16 for 16-bit, =32 for 32-bit. * noreg=1 if the *ModRM byte* has no registers used. * dispreq=1 if a displacement value is *required* (even if =0). * Returns 0 if successfully calculated, 1 if not. */ /*@-nullstate@*/ static int x86_checkea_calc_displen(x86_effaddr *x86_ea, unsigned int wordsize, int noreg, int dispreq) { /*@null@*/ /*@only@*/ yasm_intnum *num; x86_ea->valid_modrm = 0; /* default to not yet valid */ switch (x86_ea->ea.disp.size) { case 0: break; /* If not 0, the displacement length was forced; set the Mod bits * appropriately and we're done with the ModRM byte. */ case 8: /* Byte is only a valid override if there are registers in the * EA. With no registers, we must have a 16/32 value. */ if (noreg) { yasm_warn_set(YASM_WARN_IMPLICIT_SIZE_OVERRIDE, N_("invalid displacement size; fixed")); x86_ea->ea.disp.size = wordsize; } else x86_ea->modrm |= 0100; x86_ea->valid_modrm = 1; return 0; case 16: case 32: /* Don't allow changing displacement different from BITS setting * directly; require an address-size override to change it. */ if (wordsize != x86_ea->ea.disp.size) { yasm_error_set(YASM_ERROR_VALUE, N_("invalid effective address (displacement size)")); return 1; } if (!noreg) x86_ea->modrm |= 0200; x86_ea->valid_modrm = 1; return 0; default: /* we shouldn't ever get any other size! */ yasm_internal_error(N_("strange EA displacement size")); } /* The displacement length hasn't been forced (or the forcing wasn't * valid), try to determine what it is. */ if (noreg) { /* No register in ModRM expression, so it must be disp16/32, * and as the Mod bits are set to 0 by the caller, we're done * with the ModRM byte. */ x86_ea->ea.disp.size = wordsize; x86_ea->valid_modrm = 1; return 0; } if (dispreq) { /* for BP/EBP, there *must* be a displacement value, but we * may not know the size (8 or 16/32) for sure right now. */ x86_ea->ea.need_nonzero_len = 1; } if (x86_ea->ea.disp.rel) { /* Relative displacement; basically all object formats need non-byte * for relocation here, so just do that. (TODO: handle this * differently?) */ x86_ea->ea.disp.size = wordsize; x86_ea->modrm |= 0200; x86_ea->valid_modrm = 1; return 0; } /* At this point there's 3 possibilities for the displacement: * - None (if =0) * - signed 8 bit (if in -128 to 127 range) * - 16/32 bit (word size) * For now, check intnum value right now; if it's not 0, * assume 8 bit and set up for allowing 16 bit later. * FIXME: The complex expression equaling zero is probably a rare case, * so we ignore it for now. */ num = yasm_value_get_intnum(&x86_ea->ea.disp, NULL, 0); if (!num) { /* Still has unknown values. */ x86_ea->ea.need_nonzero_len = 1; x86_ea->modrm |= 0100; x86_ea->valid_modrm = 1; return 0; } /* Figure out what size displacement we will have. */ if (yasm_intnum_is_zero(num) && !x86_ea->ea.need_nonzero_len) { /* If we know that the displacement is 0 right now, * go ahead and delete the expr and make it so no * displacement value is included in the output. * The Mod bits of ModRM are set to 0 above, and * we're done with the ModRM byte! */ yasm_value_delete(&x86_ea->ea.disp); x86_ea->ea.need_disp = 0; } else if (yasm_intnum_in_range(num, -128, 127)) { /* It fits into a signed byte */ x86_ea->ea.disp.size = 8; x86_ea->modrm |= 0100; } else { /* It's a 16/32-bit displacement */ x86_ea->ea.disp.size = wordsize; x86_ea->modrm |= 0200; } x86_ea->valid_modrm = 1; /* We're done with ModRM */ yasm_intnum_destroy(num); return 0; } /*@=nullstate@*/ static int x86_expr_checkea_getregsize_callback(yasm_expr__item *ei, void *d) { unsigned char *addrsize = (unsigned char *)d; if (ei->type == YASM_EXPR_REG) { switch ((x86_expritem_reg_size)(ei->data.reg & ~0xFUL)) { case X86_REG16: *addrsize = 16; break; case X86_REG32: *addrsize = 32; break; case X86_REG64: case X86_RIP: *addrsize = 64; break; default: return 0; } return 1; } else return 0; } int yasm_x86__expr_checkea(x86_effaddr *x86_ea, unsigned char *addrsize, unsigned int bits, int address16_op, unsigned char *rex, yasm_bytecode *bc) { int retval; if (*addrsize == 0) { /* we need to figure out the address size from what we know about: * - the displacement length * - what registers are used in the expression * - the bits setting */ switch (x86_ea->ea.disp.size) { case 16: /* must be 16-bit */ *addrsize = 16; break; case 64: /* We have to support this for the MemOffs case, but it's * otherwise illegal. It's also illegal in non-64-bit mode. */ if (x86_ea->need_modrm || x86_ea->need_sib) { yasm_error_set(YASM_ERROR_VALUE, N_("invalid effective address (displacement size)")); return 1; } *addrsize = 64; break; case 32: /* Must be 32-bit in 16-bit or 32-bit modes. In 64-bit mode, * we don't know unless we look at the registers, except in the * MemOffs case (see the end of this function). */ if (bits != 64 || (!x86_ea->need_modrm && !x86_ea->need_sib)) { *addrsize = 32; break; } /*@fallthrough@*/ default: /* check for use of 16 or 32-bit registers; if none are used * default to bits setting. */ if (!x86_ea->ea.disp.abs || !yasm_expr__traverse_leaves_in(x86_ea->ea.disp.abs, addrsize, x86_expr_checkea_getregsize_callback)) *addrsize = bits; /* TODO: Add optional warning here if switched address size * from bits setting just by register use.. eg [ax] in * 32-bit mode would generate a warning. */ } } if ((*addrsize == 32 || *addrsize == 64) && ((x86_ea->need_modrm && !x86_ea->valid_modrm) || (x86_ea->need_sib && !x86_ea->valid_sib))) { int i; unsigned char low3; typedef enum { REG3264_NONE = -1, REG3264_EAX = 0, REG3264_ECX, REG3264_EDX, REG3264_EBX, REG3264_ESP, REG3264_EBP, REG3264_ESI, REG3264_EDI, REG64_R8, REG64_R9, REG64_R10, REG64_R11, REG64_R12, REG64_R13, REG64_R14, REG64_R15, REG64_RIP } reg3264type; int reg3264mult[17] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; x86_checkea_reg3264_data reg3264_data; int basereg = REG3264_NONE; /* "base" register (for SIB) */ int indexreg = REG3264_NONE; /* "index" register (for SIB) */ /* We can only do 64-bit addresses in 64-bit mode. */ if (*addrsize == 64 && bits != 64) { yasm_error_set(YASM_ERROR_TYPE, N_("invalid effective address (64-bit in non-64-bit mode)")); return 1; } if (x86_ea->ea.pc_rel && bits != 64) { yasm_warn_set(YASM_WARN_GENERAL, N_("RIP-relative directive ignored in non-64-bit mode")); x86_ea->ea.pc_rel = 0; } reg3264_data.regs = reg3264mult; reg3264_data.bits = bits; reg3264_data.addrsize = *addrsize; if (x86_ea->ea.disp.abs) { int pcrel = 0; switch (x86_expr_checkea_getregusage (&x86_ea->ea.disp.abs, &indexreg, &pcrel, bits, ®3264_data, x86_expr_checkea_get_reg3264)) { case 1: yasm_error_set(YASM_ERROR_VALUE, N_("invalid effective address")); return 1; case 2: if (pcrel) yasm_value_set_curpos_rel(&x86_ea->ea.disp, bc, 1); return 2; default: if (pcrel) yasm_value_set_curpos_rel(&x86_ea->ea.disp, bc, 1); break; } } /* If indexreg mult is 0, discard it. * This is possible because of the way indexreg is found in * expr_checkea_getregusage(). */ if (indexreg != REG3264_NONE && reg3264mult[indexreg] == 0) indexreg = REG3264_NONE; /* Find a basereg (*1, but not indexreg), if there is one. * Also, if an indexreg hasn't been assigned, try to find one. * Meanwhile, check to make sure there's no negative register mults. */ for (i=0; i<17; i++) { if (reg3264mult[i] < 0) { yasm_error_set(YASM_ERROR_VALUE, N_("invalid effective address")); return 1; } if (i != indexreg && reg3264mult[i] == 1 && basereg == REG3264_NONE) basereg = i; else if (indexreg == REG3264_NONE && reg3264mult[i] > 0) indexreg = i; } /* Handle certain special cases of indexreg mults when basereg is * empty. */ if (indexreg != REG3264_NONE && basereg == REG3264_NONE) switch (reg3264mult[indexreg]) { case 1: /* Only optimize this way if nosplit wasn't specified */ if (!x86_ea->ea.nosplit) { basereg = indexreg; indexreg = -1; } break; case 2: /* Only split if nosplit wasn't specified */ if (!x86_ea->ea.nosplit) { basereg = indexreg; reg3264mult[indexreg] = 1; } break; case 3: case 5: case 9: basereg = indexreg; reg3264mult[indexreg]--; break; } /* Make sure there's no other registers than the basereg and indexreg * we just found. */ for (i=0; i<17; i++) if (i != basereg && i != indexreg && reg3264mult[i] != 0) { yasm_error_set(YASM_ERROR_VALUE, N_("invalid effective address")); return 1; } /* Check the index multiplier value for validity if present. */ if (indexreg != REG3264_NONE && reg3264mult[indexreg] != 1 && reg3264mult[indexreg] != 2 && reg3264mult[indexreg] != 4 && reg3264mult[indexreg] != 8) { yasm_error_set(YASM_ERROR_VALUE, N_("invalid effective address")); return 1; } /* ESP is not a legal indexreg. */ if (indexreg == REG3264_ESP) { /* If mult>1 or basereg is ESP also, there's no way to make it * legal. */ if (reg3264mult[REG3264_ESP] > 1 || basereg == REG3264_ESP) { yasm_error_set(YASM_ERROR_VALUE, N_("invalid effective address")); return 1; } /* If mult==1 and basereg is not ESP, swap indexreg w/basereg. */ indexreg = basereg; basereg = REG3264_ESP; } /* RIP is only legal if it's the ONLY register used. */ if (indexreg == REG64_RIP || (basereg == REG64_RIP && indexreg != REG3264_NONE)) { yasm_error_set(YASM_ERROR_VALUE, N_("invalid effective address")); return 1; } /* At this point, we know the base and index registers and that the * memory expression is (essentially) valid. Now build the ModRM and * (optional) SIB bytes. */ /* If we're supposed to be RIP-relative and there's no register * usage, change to RIP-relative. */ if (basereg == REG3264_NONE && indexreg == REG3264_NONE && x86_ea->ea.pc_rel) { basereg = REG64_RIP; yasm_value_set_curpos_rel(&x86_ea->ea.disp, bc, 1); } /* First determine R/M (Mod is later determined from disp size) */ x86_ea->need_modrm = 1; /* we always need ModRM */ if (basereg == REG3264_NONE && indexreg == REG3264_NONE) { /* Just a disp32: in 64-bit mode the RM encoding is used for RIP * offset addressing, so we need to use the SIB form instead. */ if (bits == 64) { x86_ea->modrm |= 4; x86_ea->need_sib = 1; } else { x86_ea->modrm |= 5; x86_ea->sib = 0; x86_ea->valid_sib = 0; x86_ea->need_sib = 0; } } else if (basereg == REG64_RIP) { x86_ea->modrm |= 5; x86_ea->sib = 0; x86_ea->valid_sib = 0; x86_ea->need_sib = 0; /* RIP always requires a 32-bit displacement */ x86_ea->valid_modrm = 1; x86_ea->ea.disp.size = 32; return 0; } else if (indexreg == REG3264_NONE) { /* basereg only */ /* Don't need to go to the full effort of determining what type * of register basereg is, as x86_set_rex_from_reg doesn't pay * much attention. */ if (yasm_x86__set_rex_from_reg(rex, &low3, (unsigned int)(X86_REG64 | basereg), bits, X86_REX_B)) return 1; x86_ea->modrm |= low3; /* we don't need an SIB *unless* basereg is ESP or R12 */ if (basereg == REG3264_ESP || basereg == REG64_R12) x86_ea->need_sib = 1; else { x86_ea->sib = 0; x86_ea->valid_sib = 0; x86_ea->need_sib = 0; } } else { /* index or both base and index */ x86_ea->modrm |= 4; x86_ea->need_sib = 1; } /* Determine SIB if needed */ if (x86_ea->need_sib == 1) { x86_ea->sib = 0; /* start with 0 */ /* Special case: no basereg */ if (basereg == REG3264_NONE) x86_ea->sib |= 5; else { if (yasm_x86__set_rex_from_reg(rex, &low3, (unsigned int) (X86_REG64 | basereg), bits, X86_REX_B)) return 1; x86_ea->sib |= low3; } /* Put in indexreg, checking for none case */ if (indexreg == REG3264_NONE) x86_ea->sib |= 040; /* Any scale field is valid, just leave at 0. */ else { if (yasm_x86__set_rex_from_reg(rex, &low3, (unsigned int) (X86_REG64 | indexreg), bits, X86_REX_X)) return 1; x86_ea->sib |= low3 << 3; /* Set scale field, 1 case -> 0, so don't bother. */ switch (reg3264mult[indexreg]) { case 2: x86_ea->sib |= 0100; break; case 4: x86_ea->sib |= 0200; break; case 8: x86_ea->sib |= 0300; break; } } x86_ea->valid_sib = 1; /* Done with SIB */ } /* Calculate displacement length (if possible) */ retval = x86_checkea_calc_displen (x86_ea, 32, basereg == REG3264_NONE, basereg == REG3264_EBP || basereg == REG64_R13); return retval; } else if (*addrsize == 16 && x86_ea->need_modrm && !x86_ea->valid_modrm) { static const unsigned char modrm16[16] = { 0006 /* disp16 */, 0007 /* [BX] */, 0004 /* [SI] */, 0000 /* [BX+SI] */, 0005 /* [DI] */, 0001 /* [BX+DI] */, 0377 /* invalid */, 0377 /* invalid */, 0006 /* [BP]+d */, 0377 /* invalid */, 0002 /* [BP+SI] */, 0377 /* invalid */, 0003 /* [BP+DI] */, 0377 /* invalid */, 0377 /* invalid */, 0377 /* invalid */ }; x86_checkea_reg16_data reg16mult = {0, 0, 0, 0}; enum { HAVE_NONE = 0, HAVE_BX = 1<<0, HAVE_SI = 1<<1, HAVE_DI = 1<<2, HAVE_BP = 1<<3 } havereg = HAVE_NONE; /* 64-bit mode does not allow 16-bit addresses */ if (bits == 64 && !address16_op) { yasm_error_set(YASM_ERROR_TYPE, N_("16-bit addresses not supported in 64-bit mode")); return 1; } /* 16-bit cannot have SIB */ x86_ea->sib = 0; x86_ea->valid_sib = 0; x86_ea->need_sib = 0; if (x86_ea->ea.disp.abs) { int pcrel = 0; switch (x86_expr_checkea_getregusage (&x86_ea->ea.disp.abs, (int *)NULL, &pcrel, bits, ®16mult, x86_expr_checkea_get_reg16)) { case 1: yasm_error_set(YASM_ERROR_VALUE, N_("invalid effective address")); return 1; case 2: if (pcrel) yasm_value_set_curpos_rel(&x86_ea->ea.disp, bc, 1); return 2; default: if (pcrel) yasm_value_set_curpos_rel(&x86_ea->ea.disp, bc, 1); break; } } /* reg multipliers not 0 or 1 are illegal. */ if (reg16mult.bx & ~1 || reg16mult.si & ~1 || reg16mult.di & ~1 || reg16mult.bp & ~1) { yasm_error_set(YASM_ERROR_VALUE, N_("invalid effective address")); return 1; } /* Set havereg appropriately */ if (reg16mult.bx > 0) havereg |= HAVE_BX; if (reg16mult.si > 0) havereg |= HAVE_SI; if (reg16mult.di > 0) havereg |= HAVE_DI; if (reg16mult.bp > 0) havereg |= HAVE_BP; /* Check the modrm value for invalid combinations. */ if (modrm16[havereg] & 0070) { yasm_error_set(YASM_ERROR_VALUE, N_("invalid effective address")); return 1; } /* Set ModRM byte for registers */ x86_ea->modrm |= modrm16[havereg]; /* Calculate displacement length (if possible) */ retval = x86_checkea_calc_displen (x86_ea, 16, havereg == HAVE_NONE, havereg == HAVE_BP); return retval; } else if (!x86_ea->need_modrm && !x86_ea->need_sib) { /* Special case for MOV MemOffs opcode: displacement but no modrm. */ switch (*addrsize) { case 64: if (bits != 64) { yasm_error_set(YASM_ERROR_TYPE, N_("invalid effective address (64-bit in non-64-bit mode)")); return 1; } x86_ea->ea.disp.size = 64; break; case 32: x86_ea->ea.disp.size = 32; break; case 16: /* 64-bit mode does not allow 16-bit addresses */ if (bits == 64 && !address16_op) { yasm_error_set(YASM_ERROR_TYPE, N_("16-bit addresses not supported in 64-bit mode")); return 1; } x86_ea->ea.disp.size = 16; break; } } return 0; } int yasm_x86__floatnum_tobytes(yasm_arch *arch, const yasm_floatnum *flt, unsigned char *buf, size_t destsize, size_t valsize, size_t shift, int warn) { if (!yasm_floatnum_check_size(flt, valsize)) { yasm_error_set(YASM_ERROR_FLOATING_POINT, N_("invalid floating point constant size")); return 1; } yasm_floatnum_get_sized(flt, buf, destsize, valsize, shift, 0, warn); return 0; }