target-i386: Split up gen_lea_modrm
This is immediately usable by lea and multi-byte nop, and will be required to implement parts of the mpx spec. Signed-off-by: Richard Henderson <rth@twiddle.net>
This commit is contained in:
parent
7f0b7141b4
commit
a074ce42a3
@ -1807,37 +1807,52 @@ static void gen_shifti(DisasContext *s1, int op, TCGMemOp ot, int d, int c)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void gen_lea_modrm(CPUX86State *env, DisasContext *s, int modrm)
|
/* Decompose an address. */
|
||||||
{
|
|
||||||
|
typedef struct AddressParts {
|
||||||
|
int def_seg;
|
||||||
|
int base;
|
||||||
|
int index;
|
||||||
|
int scale;
|
||||||
target_long disp;
|
target_long disp;
|
||||||
int havesib, base, index, scale;
|
} AddressParts;
|
||||||
int mod, rm, code, def_seg, ovr_seg;
|
|
||||||
TCGv sum;
|
static AddressParts gen_lea_modrm_0(CPUX86State *env, DisasContext *s,
|
||||||
|
int modrm)
|
||||||
|
{
|
||||||
|
int def_seg, base, index, scale, mod, rm;
|
||||||
|
target_long disp;
|
||||||
|
bool havesib;
|
||||||
|
|
||||||
def_seg = R_DS;
|
def_seg = R_DS;
|
||||||
ovr_seg = s->override;
|
index = -1;
|
||||||
|
scale = 0;
|
||||||
|
disp = 0;
|
||||||
|
|
||||||
mod = (modrm >> 6) & 3;
|
mod = (modrm >> 6) & 3;
|
||||||
rm = modrm & 7;
|
rm = modrm & 7;
|
||||||
|
base = rm | REX_B(s);
|
||||||
|
|
||||||
|
if (mod == 3) {
|
||||||
|
/* Normally filtered out earlier, but including this path
|
||||||
|
simplifies multi-byte nop, as well as bndcl, bndcu, bndcn. */
|
||||||
|
goto done;
|
||||||
|
}
|
||||||
|
|
||||||
switch (s->aflag) {
|
switch (s->aflag) {
|
||||||
case MO_64:
|
case MO_64:
|
||||||
case MO_32:
|
case MO_32:
|
||||||
havesib = 0;
|
havesib = 0;
|
||||||
base = rm;
|
if (rm == 4) {
|
||||||
index = -1;
|
int code = cpu_ldub_code(env, s->pc++);
|
||||||
scale = 0;
|
|
||||||
|
|
||||||
if (base == 4) {
|
|
||||||
havesib = 1;
|
|
||||||
code = cpu_ldub_code(env, s->pc++);
|
|
||||||
scale = (code >> 6) & 3;
|
scale = (code >> 6) & 3;
|
||||||
index = ((code >> 3) & 7) | REX_X(s);
|
index = ((code >> 3) & 7) | REX_X(s);
|
||||||
if (index == 4) {
|
if (index == 4) {
|
||||||
index = -1; /* no index */
|
index = -1; /* no index */
|
||||||
}
|
}
|
||||||
base = (code & 7);
|
base = (code & 7) | REX_B(s);
|
||||||
|
havesib = 1;
|
||||||
}
|
}
|
||||||
base |= REX_B(s);
|
|
||||||
|
|
||||||
switch (mod) {
|
switch (mod) {
|
||||||
case 0:
|
case 0:
|
||||||
@ -1846,10 +1861,9 @@ static void gen_lea_modrm(CPUX86State *env, DisasContext *s, int modrm)
|
|||||||
disp = (int32_t)cpu_ldl_code(env, s->pc);
|
disp = (int32_t)cpu_ldl_code(env, s->pc);
|
||||||
s->pc += 4;
|
s->pc += 4;
|
||||||
if (CODE64(s) && !havesib) {
|
if (CODE64(s) && !havesib) {
|
||||||
|
base = -2;
|
||||||
disp += s->pc + s->rip_offset;
|
disp += s->pc + s->rip_offset;
|
||||||
}
|
}
|
||||||
} else {
|
|
||||||
disp = 0;
|
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case 1:
|
case 1:
|
||||||
@ -1866,46 +1880,19 @@ static void gen_lea_modrm(CPUX86State *env, DisasContext *s, int modrm)
|
|||||||
if (base == R_ESP && s->popl_esp_hack) {
|
if (base == R_ESP && s->popl_esp_hack) {
|
||||||
disp += s->popl_esp_hack;
|
disp += s->popl_esp_hack;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Compute the address, with a minimum number of TCG ops. */
|
|
||||||
TCGV_UNUSED(sum);
|
|
||||||
if (index >= 0) {
|
|
||||||
if (scale == 0) {
|
|
||||||
sum = cpu_regs[index];
|
|
||||||
} else {
|
|
||||||
tcg_gen_shli_tl(cpu_A0, cpu_regs[index], scale);
|
|
||||||
sum = cpu_A0;
|
|
||||||
}
|
|
||||||
if (base >= 0) {
|
|
||||||
tcg_gen_add_tl(cpu_A0, sum, cpu_regs[base]);
|
|
||||||
sum = cpu_A0;
|
|
||||||
}
|
|
||||||
} else if (base >= 0) {
|
|
||||||
sum = cpu_regs[base];
|
|
||||||
}
|
|
||||||
if (TCGV_IS_UNUSED(sum)) {
|
|
||||||
tcg_gen_movi_tl(cpu_A0, disp);
|
|
||||||
sum = cpu_A0;
|
|
||||||
} else if (disp != 0) {
|
|
||||||
tcg_gen_addi_tl(cpu_A0, sum, disp);
|
|
||||||
sum = cpu_A0;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (base == R_EBP || base == R_ESP) {
|
if (base == R_EBP || base == R_ESP) {
|
||||||
def_seg = R_SS;
|
def_seg = R_SS;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case MO_16:
|
case MO_16:
|
||||||
sum = cpu_A0;
|
|
||||||
if (mod == 0) {
|
if (mod == 0) {
|
||||||
if (rm == 6) {
|
if (rm == 6) {
|
||||||
|
base = -1;
|
||||||
disp = cpu_lduw_code(env, s->pc);
|
disp = cpu_lduw_code(env, s->pc);
|
||||||
s->pc += 2;
|
s->pc += 2;
|
||||||
tcg_gen_movi_tl(cpu_A0, disp);
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
disp = 0;
|
|
||||||
} else if (mod == 1) {
|
} else if (mod == 1) {
|
||||||
disp = (int8_t)cpu_ldub_code(env, s->pc++);
|
disp = (int8_t)cpu_ldub_code(env, s->pc++);
|
||||||
} else {
|
} else {
|
||||||
@ -1915,102 +1902,89 @@ static void gen_lea_modrm(CPUX86State *env, DisasContext *s, int modrm)
|
|||||||
|
|
||||||
switch (rm) {
|
switch (rm) {
|
||||||
case 0:
|
case 0:
|
||||||
tcg_gen_add_tl(cpu_A0, cpu_regs[R_EBX], cpu_regs[R_ESI]);
|
base = R_EBX;
|
||||||
|
index = R_ESI;
|
||||||
break;
|
break;
|
||||||
case 1:
|
case 1:
|
||||||
tcg_gen_add_tl(cpu_A0, cpu_regs[R_EBX], cpu_regs[R_EDI]);
|
base = R_EBX;
|
||||||
|
index = R_EDI;
|
||||||
break;
|
break;
|
||||||
case 2:
|
case 2:
|
||||||
tcg_gen_add_tl(cpu_A0, cpu_regs[R_EBP], cpu_regs[R_ESI]);
|
base = R_EBP;
|
||||||
|
index = R_ESI;
|
||||||
def_seg = R_SS;
|
def_seg = R_SS;
|
||||||
break;
|
break;
|
||||||
case 3:
|
case 3:
|
||||||
tcg_gen_add_tl(cpu_A0, cpu_regs[R_EBP], cpu_regs[R_EDI]);
|
base = R_EBP;
|
||||||
|
index = R_EDI;
|
||||||
def_seg = R_SS;
|
def_seg = R_SS;
|
||||||
break;
|
break;
|
||||||
case 4:
|
case 4:
|
||||||
sum = cpu_regs[R_ESI];
|
base = R_ESI;
|
||||||
break;
|
break;
|
||||||
case 5:
|
case 5:
|
||||||
sum = cpu_regs[R_EDI];
|
base = R_EDI;
|
||||||
break;
|
break;
|
||||||
case 6:
|
case 6:
|
||||||
sum = cpu_regs[R_EBP];
|
base = R_EBP;
|
||||||
def_seg = R_SS;
|
def_seg = R_SS;
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
case 7:
|
case 7:
|
||||||
sum = cpu_regs[R_EBX];
|
base = R_EBX;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
if (disp != 0) {
|
|
||||||
tcg_gen_addi_tl(cpu_A0, sum, disp);
|
|
||||||
sum = cpu_A0;
|
|
||||||
}
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
tcg_abort();
|
tcg_abort();
|
||||||
}
|
}
|
||||||
|
|
||||||
gen_lea_v_seg(s, s->aflag, sum, def_seg, ovr_seg);
|
done:
|
||||||
|
return (AddressParts){ def_seg, base, index, scale, disp };
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Compute the address, with a minimum number of TCG ops. */
|
||||||
|
static TCGv gen_lea_modrm_1(AddressParts a)
|
||||||
|
{
|
||||||
|
TCGv ea;
|
||||||
|
|
||||||
|
TCGV_UNUSED(ea);
|
||||||
|
if (a.index >= 0) {
|
||||||
|
if (a.scale == 0) {
|
||||||
|
ea = cpu_regs[a.index];
|
||||||
|
} else {
|
||||||
|
tcg_gen_shli_tl(cpu_A0, cpu_regs[a.index], a.scale);
|
||||||
|
ea = cpu_A0;
|
||||||
|
}
|
||||||
|
if (a.base >= 0) {
|
||||||
|
tcg_gen_add_tl(cpu_A0, ea, cpu_regs[a.base]);
|
||||||
|
ea = cpu_A0;
|
||||||
|
}
|
||||||
|
} else if (a.base >= 0) {
|
||||||
|
ea = cpu_regs[a.base];
|
||||||
|
}
|
||||||
|
if (TCGV_IS_UNUSED(ea)) {
|
||||||
|
tcg_gen_movi_tl(cpu_A0, a.disp);
|
||||||
|
ea = cpu_A0;
|
||||||
|
} else if (a.disp != 0) {
|
||||||
|
tcg_gen_addi_tl(cpu_A0, ea, a.disp);
|
||||||
|
ea = cpu_A0;
|
||||||
|
}
|
||||||
|
|
||||||
|
return ea;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void gen_lea_modrm(CPUX86State *env, DisasContext *s, int modrm)
|
||||||
|
{
|
||||||
|
AddressParts a = gen_lea_modrm_0(env, s, modrm);
|
||||||
|
TCGv ea = gen_lea_modrm_1(a);
|
||||||
|
gen_lea_v_seg(s, s->aflag, ea, a.def_seg, s->override);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void gen_nop_modrm(CPUX86State *env, DisasContext *s, int modrm)
|
static void gen_nop_modrm(CPUX86State *env, DisasContext *s, int modrm)
|
||||||
{
|
{
|
||||||
int mod, rm, base, code;
|
(void)gen_lea_modrm_0(env, s, modrm);
|
||||||
|
|
||||||
mod = (modrm >> 6) & 3;
|
|
||||||
if (mod == 3)
|
|
||||||
return;
|
|
||||||
rm = modrm & 7;
|
|
||||||
|
|
||||||
switch (s->aflag) {
|
|
||||||
case MO_64:
|
|
||||||
case MO_32:
|
|
||||||
base = rm;
|
|
||||||
|
|
||||||
if (base == 4) {
|
|
||||||
code = cpu_ldub_code(env, s->pc++);
|
|
||||||
base = (code & 7);
|
|
||||||
}
|
|
||||||
|
|
||||||
switch (mod) {
|
|
||||||
case 0:
|
|
||||||
if (base == 5) {
|
|
||||||
s->pc += 4;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case 1:
|
|
||||||
s->pc++;
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
case 2:
|
|
||||||
s->pc += 4;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
|
|
||||||
case MO_16:
|
|
||||||
switch (mod) {
|
|
||||||
case 0:
|
|
||||||
if (rm == 6) {
|
|
||||||
s->pc += 2;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case 1:
|
|
||||||
s->pc++;
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
case 2:
|
|
||||||
s->pc += 2;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
|
|
||||||
default:
|
|
||||||
tcg_abort();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* used for LEA and MOV AX, mem */
|
/* used for LEA and MOV AX, mem */
|
||||||
@ -5302,19 +5276,16 @@ static target_ulong disas_insn(CPUX86State *env, DisasContext *s,
|
|||||||
break;
|
break;
|
||||||
|
|
||||||
case 0x8d: /* lea */
|
case 0x8d: /* lea */
|
||||||
ot = dflag;
|
|
||||||
modrm = cpu_ldub_code(env, s->pc++);
|
modrm = cpu_ldub_code(env, s->pc++);
|
||||||
mod = (modrm >> 6) & 3;
|
mod = (modrm >> 6) & 3;
|
||||||
if (mod == 3)
|
if (mod == 3)
|
||||||
goto illegal_op;
|
goto illegal_op;
|
||||||
reg = ((modrm >> 3) & 7) | rex_r;
|
reg = ((modrm >> 3) & 7) | rex_r;
|
||||||
/* we must ensure that no segment is added */
|
{
|
||||||
s->override = -1;
|
AddressParts a = gen_lea_modrm_0(env, s, modrm);
|
||||||
val = s->addseg;
|
TCGv ea = gen_lea_modrm_1(a);
|
||||||
s->addseg = 0;
|
gen_op_mov_reg_v(dflag, reg, ea);
|
||||||
gen_lea_modrm(env, s, modrm);
|
}
|
||||||
s->addseg = val;
|
|
||||||
gen_op_mov_reg_v(ot, reg, cpu_A0);
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 0xa0: /* mov EAX, Ov */
|
case 0xa0: /* mov EAX, Ov */
|
||||||
|
Loading…
Reference in New Issue
Block a user