summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJin Kyu Song <jin.kyu.song@intel.com>2013-12-10 16:24:45 -0800
committerJin Kyu Song <jin.kyu.song@intel.com>2013-12-11 16:56:19 -0800
commit4360ba28f0e4767ffe28ef3a037aaa103b5660b6 (patch)
treed66cad3a8c786b4291c28879d038caaffd53a897
parent478f2dafff5b58c7c965cfe2277ff71e1492815a (diff)
downloadnasm-4360ba28f0e4767ffe28ef3a037aaa103b5660b6.tar.gz
nasm-4360ba28f0e4767ffe28ef3a037aaa103b5660b6.tar.bz2
nasm-4360ba28f0e4767ffe28ef3a037aaa103b5660b6.zip
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>
-rw-r--r--assemble.c85
-rw-r--r--eval.c5
-rw-r--r--nasm.h6
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 */