From 4360ba28f0e4767ffe28ef3a037aaa103b5660b6 Mon Sep 17 00:00:00 2001 From: Jin Kyu Song Date: Tue, 10 Dec 2013 16:24:45 -0800 Subject: [PATCH] mib: Handle MIB EA in a different way from regular EA's In mib operands, users' intention should be preserved. e.g.) [eax + eax*1] and [eax*2] must be distinguished and encoded differently. So a new EA flag EAF_MIB for mib operands is added. And a new EA hint EAH_SUMMED for the case of [eax+eax*4] being parsed as [eax*5] is also added. NOSPLIT specifier does not have an effect in mib, so [nosplit eax + eax*1] will be encoded as [eax, eax] rather than [eax*2] as in a regular EA. Signed-off-by: Jin Kyu Song --- assemble.c | 85 ++++++++++++++++++++++++++++++++++++-------------------------- eval.c | 5 +++- nasm.h | 6 +++-- 3 files changed, 57 insertions(+), 39 deletions(-) diff --git a/assemble.c b/assemble.c index bdf9a10..4ff9e25 100644 --- a/assemble.c +++ b/assemble.c @@ -1231,27 +1231,18 @@ static int64_t calcsize(int32_t segment, int64_t offset, int bits, } } - /* - * if a separate form of MIB (ICC style) is used, - * the index reg info is merged into mem operand - */ - if (mib_index != R_none) { - opy->indexreg = mib_index; - opy->scale = 1; - opy->hintbase = mib_index; - opy->hinttype = EAH_NOTBASE; - } - - /* - * only for mib operands, make a single reg index [reg*1]. - * gas uses this form to explicitly denote index register. - */ - if (itemp_has(temp, IF_MIB) && - (opy->indexreg == -1 && opy->hintbase == opy->basereg && - opy->hinttype == EAH_NOTBASE)) { - opy->indexreg = opy->basereg; - opy->basereg = -1; - opy->scale = 1; + if (itemp_has(temp, IF_MIB)) { + opy->eaflags |= EAF_MIB; + /* + * if a separate form of MIB (ICC style) is used, + * the index reg info is merged into mem operand + */ + if (mib_index != R_none) { + opy->indexreg = mib_index; + opy->scale = 1; + opy->hintbase = mib_index; + opy->hinttype = EAH_NOTBASE; + } } if (process_ea(opy, &ea_data, bits, @@ -2379,6 +2370,7 @@ static enum ea_type process_ea(operand *input, ea *output, int bits, { bool forw_ref = !!(input->opflags & OPFLAG_UNKNOWN); int addrbits = ins->addr_size; + int eaflags = input->eaflags; output->type = EA_SCALAR; output->rip = false; @@ -2434,8 +2426,8 @@ static enum ea_type process_ea(operand *input, ea *output, int bits, input->type |= MEMORY; } - if (input->eaflags & EAF_BYTEOFFS || - (input->eaflags & EAF_WORDOFFS && + if (eaflags & EAF_BYTEOFFS || + (eaflags & EAF_WORDOFFS && input->disp_size != (addrbits != 16 ? 32 : 16))) { nasm_error(ERR_WARNING | ERR_PASS1, "displacement size ignored on absolute address"); } @@ -2556,7 +2548,7 @@ static enum ea_type process_ea(operand *input, ea *output, int bits, base = (bt & 7); if (base != REG_NUM_EBP && o == 0 && seg == NO_SEG && !forw_ref && - !(input->eaflags & (EAF_BYTEOFFS | EAF_WORDOFFS))) + !(eaflags & (EAF_BYTEOFFS | EAF_WORDOFFS))) mod = 0; else if (IS_MOD_01()) mod = 1; @@ -2611,19 +2603,40 @@ static enum ea_type process_ea(operand *input, ea *output, int bits, t = bt, bt = it, it = t; x = bx, bx = ix, ix = x; } - if (bt == it) /* convert EAX+2*EAX to 3*EAX */ - bt = -1, bx = 0, s++; + if (bt == -1 && s == 1 && !(hb == i && ht == EAH_NOTBASE)) { /* make single reg base, unless hint */ bt = it, bx = ix, it = -1, ix = 0; } - if (((s == 2 && it != REG_NUM_ESP && !(input->eaflags & EAF_TIMESTWO)) || - s == 3 || s == 5 || s == 9) && bt == -1) - bt = it, bx = ix, s--; /* convert 3*EAX to EAX+2*EAX */ - if (it == -1 && (bt & 7) != REG_NUM_ESP && - (input->eaflags & EAF_TIMESTWO)) - it = bt, ix = bx, bt = -1, bx = 0, s = 1; - /* convert [NOSPLIT EAX] to sib format with 0x0 displacement */ + if (eaflags & EAF_MIB) { + /* only for mib operands */ + if (it == -1 && (hb == b && ht == EAH_NOTBASE)) { + /* + * make a single reg index [reg*1]. + * gas uses this form for an explicit index register. + */ + it = bt, ix = bx, bt = -1, bx = 0, s = 1; + } + if ((ht == EAH_SUMMED) && bt == -1) { + /* separate once summed index into [base, index] */ + bt = it, bx = ix, s--; + } + } else { + if (((s == 2 && it != REG_NUM_ESP && + !(eaflags & EAF_TIMESTWO)) || + s == 3 || s == 5 || s == 9) && bt == -1) { + /* convert 3*EAX to EAX+2*EAX */ + bt = it, bx = ix, s--; + } + if (it == -1 && (bt & 7) != REG_NUM_ESP && + (eaflags & EAF_TIMESTWO)) { + /* + * convert [NOSPLIT EAX] + * to sib format with 0x0 displacement - [EAX*1+0]. + */ + it = bt, ix = bx, bt = -1, bx = 0, s = 1; + } + } if (s == 1 && it == REG_NUM_ESP) { /* swap ESP into base if scale is 1 */ t = it, it = bt, bt = t; @@ -2647,7 +2660,7 @@ static enum ea_type process_ea(operand *input, ea *output, int bits, rm = (bt & 7); if (rm != REG_NUM_EBP && o == 0 && seg == NO_SEG && !forw_ref && - !(input->eaflags & (EAF_BYTEOFFS | EAF_WORDOFFS))) + !(eaflags & (EAF_BYTEOFFS | EAF_WORDOFFS))) mod = 0; else if (IS_MOD_01()) mod = 1; @@ -2691,7 +2704,7 @@ static enum ea_type process_ea(operand *input, ea *output, int bits, base = (bt & 7); if (base != REG_NUM_EBP && o == 0 && seg == NO_SEG && !forw_ref && - !(input->eaflags & (EAF_BYTEOFFS | EAF_WORDOFFS))) + !(eaflags & (EAF_BYTEOFFS | EAF_WORDOFFS))) mod = 0; else if (IS_MOD_01()) mod = 1; @@ -2776,7 +2789,7 @@ static enum ea_type process_ea(operand *input, ea *output, int bits, goto err; /* so panic if it does */ if (o == 0 && seg == NO_SEG && !forw_ref && rm != 6 && - !(input->eaflags & (EAF_BYTEOFFS | EAF_WORDOFFS))) + !(eaflags & (EAF_BYTEOFFS | EAF_WORDOFFS))) mod = 0; else if (IS_MOD_01()) mod = 1; diff --git a/eval.c b/eval.c index c57ff04..403a793 100644 --- a/eval.c +++ b/eval.c @@ -148,8 +148,11 @@ static expr *add_vectors(expr * p, expr * q) lasttype = p++->type; } else { /* *p and *q have same type */ int64_t sum = p->value + q->value; - if (sum) + if (sum) { addtotemp(p->type, sum); + if (hint) + hint->type = EAH_SUMMED; + } lasttype = p->type; p++, q++; } diff --git a/nasm.h b/nasm.h index 736c290..18de37c 100644 --- a/nasm.h +++ b/nasm.h @@ -584,13 +584,15 @@ enum ea_flags { /* special EA flags */ EAF_TIMESTWO = 4, /* really do EAX*2 not EAX+EAX */ EAF_REL = 8, /* IP-relative addressing */ EAF_ABS = 16, /* non-IP-relative addressing */ - EAF_FSGS = 32 /* fs/gs segment override present */ + EAF_FSGS = 32, /* fs/gs segment override present */ + EAF_MIB = 64, /* mib operand */ }; enum eval_hint { /* values for `hinttype' */ EAH_NOHINT = 0, /* no hint at all - our discretion */ EAH_MAKEBASE = 1, /* try to make given reg the base */ - EAH_NOTBASE = 2 /* try _not_ to make reg the base */ + EAH_NOTBASE = 2, /* try _not_ to make reg the base */ + EAH_SUMMED = 3, /* base and index are summed into index */ }; typedef struct operand { /* operand to an instruction */ -- 2.7.4