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 <jin.kyu.song@intel.com>
This commit is contained in:
Jin Kyu Song 2013-12-10 16:24:45 -08:00
parent 478f2dafff
commit 4360ba28f0
3 changed files with 57 additions and 39 deletions

View file

@ -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;

5
eval.c
View file

@ -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++;
}

6
nasm.h
View file

@ -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 */