⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 x86expr.c

📁 支持AMD64的汇编编译器源码
💻 C
📖 第 1 页 / 共 2 页
字号:
/* * x86 expression handling * *  Copyright (C) 2001  Peter Johnson * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright *    notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright *    notice, this list of conditions and the following disclaimer in the *    documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND OTHER CONTRIBUTORS ``AS IS'' * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR OTHER CONTRIBUTORS BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. */#include <util.h>/*@unused@*/ RCSID("$Id: x86expr.c 1168 2004-10-31 01:07:52Z peter $");#define YASM_LIB_INTERNAL#define YASM_EXPR_INTERNAL#include <libyasm.h>#include "x86arch.h"typedef struct x86_checkea_reg3264_data {    int *regs;		/* total multiplier for each reg */    unsigned char bits;    unsigned char addrsize;} x86_checkea_reg3264_data;/* Only works if ei->type == EXPR_REG (doesn't check). * Overwrites ei with intnum of 0 (to eliminate regs from the final expr). */static /*@null@*/ /*@dependent@*/ int *x86_expr_checkea_get_reg3264(yasm_expr__item *ei, int *regnum,			     /*returned*/ void *d){    x86_checkea_reg3264_data *data = d;    switch ((x86_expritem_reg_size)(ei->data.reg & ~0xFUL)) {	case X86_REG32:	    if (data->addrsize != 32)		return 0;	    *regnum = ei->data.reg & 0xF;	    break;	case X86_REG64:	    if (data->addrsize != 64)		return 0;	    *regnum = 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 = 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 intx86_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 intx86_expr_checkea_getregusage(yasm_expr **ep, /*@null@*/ yasm_expr **wrt,    /*@null@*/ int *indexreg, unsigned char *pcrel, unsigned int bits,    void *data, int *(*get_reg)(yasm_expr__item *ei, int *regnum, void *d),    yasm_calc_bc_dist_func calc_bc_dist){    int i;    int *reg;    int regnum;    int indexval = 0;    int indexmult = 0;    yasm_expr *e;    /*@-unqualifiedtrans@*/    *ep = yasm_expr__level_tree(*ep, 1, indexreg == 0, calc_bc_dist, NULL,				NULL, NULL);    if (*wrt)	*wrt = yasm_expr__level_tree(*wrt, 1, indexreg == 0, calc_bc_dist,				     NULL, NULL, NULL);    /*@=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, indexreg == 0, NULL, NULL,					NULL, NULL);	    e = *ep;	    break;	default:	    break;    }    if (*wrt && (*wrt)->op == YASM_EXPR_IDENT &&	(*wrt)->terms[0].type == YASM_EXPR_REG) {	/* Handle xx WRT rip. */	if (bits != 64)		    /* only valid in 64-bit mode */	    return 1;	reg = get_reg(&(*wrt)->terms[0], &regnum, data);	if (!reg || regnum != 16)   /* only accept rip */	    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);	/* Drill down to next WRT and recurse if there was one. */	*wrt = yasm_expr_extract_wrt(ep);	if (*wrt)	    return x86_expr_checkea_getregusage(ep, wrt, indexreg, pcrel,						bits, data, get_reg,						calc_bc_dist);    }    switch (e->op) {	case YASM_EXPR_ADD:	    /* Prescan for non-int multipliers against a reg.	     * This is because if any of the terms is a more complex	     * expr (eg, undetermined value), we don't want to try to	     * figure out *any* of the expression, because each register	     * lookup overwrites the register with a 0 value!  And storing	     * the state of this routine from one excution to the next	     * would be a major chore.	     */	    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 2;			if (e->terms[i].data.expn->terms[1].type !=			    YASM_EXPR_INT)			    return 2;		    }		}	    /*@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) {			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;			(*reg) += yasm_intnum_get_int(			    e->terms[i].data.expn->terms[1].data.intn);			/* Let last, largest multipler win indexreg */			if (indexreg && *reg > 0 && indexval <= *reg) {			    *indexreg = regnum;			    indexval = *reg;			    indexmult = 1;			}		    }		}	    }	    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) {		if (e->numterms > 2)		    return 2;		if (e->terms[1].type != YASM_EXPR_INT)		    return 2;		reg = get_reg(&e->terms[0], &regnum, data);		if (!reg)		    return 1;		(*reg) += yasm_intnum_get_int(e->terms[1].data.intn);		if (indexreg)		    *indexreg = regnum;	    }	    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, NULL);    /* 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=2 for 16-bit, =4 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 intx86_checkea_calc_displen(yasm_expr **ep, unsigned int wordsize, int noreg,			 int dispreq, unsigned char *displen,			 unsigned char *modrm, unsigned char *v_modrm){    yasm_expr *e = *ep;    const yasm_intnum *intn;    long dispval;    *v_modrm = 0;	/* default to not yet valid */    switch (*displen) {	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 1:	    /* Byte is not valid override in noreg case; fix it. */	    if (noreg) {		*displen = 0;		yasm__warning(YASM_WARN_GENERAL, e->line,			      N_("invalid displacement size; fixed"));	    } else		*modrm |= 0100;	    *v_modrm = 1;	    break;	case 2:	case 4:	    if (wordsize != *displen) {		yasm__error(e->line,		    N_("invalid effective address (displacement size)"));		return 1;	    }	    /* 2/4 is not valid override in noreg case; fix it. */	    if (noreg) {		if (wordsize != *displen)		    yasm__warning(YASM_WARN_GENERAL, e->line,				  N_("invalid displacement size; fixed"));		*displen = 0;	    } else		*modrm |= 0200;	    *v_modrm = 1;	    break;	default:	    /* we shouldn't ever get any other size! */	    yasm_internal_error(N_("strange EA displacement size"));    }    if (*displen == 0) {	/* 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.	     */	    *displen = wordsize;	    *v_modrm = 1;	    return 0;	} else 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.	     * We can't leave displen at 0, because that just means	     * unknown displacement, including none.	     */	    *displen = 0xff;	}	intn = yasm_expr_get_intnum(ep, NULL);	if (!intn) {	    /* expr still has unknown values: assume 16/32-bit disp */	    *displen = wordsize;	    *modrm |= 0200;	    *v_modrm = 1;	    return 0;	}		/* don't try to find out what size displacement we have if	 * displen is known.	 */	if (*displen != 0 && *displen != 0xff) {	    if (*displen == 1)		*modrm |= 0100;	    else		*modrm |= 0200;	    *v_modrm = 1;	    return 0;	}	dispval = yasm_intnum_get_int(intn);

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -