Skip to content

Commit 87610ba

Browse files
authored
Fix emulator detection (#1966)
* Add a quick test helper macro to test_x86.c * Add regression tests for bswap and rex prefixes * Properly ignore REX prefixes when appropriate * Fix bswap ax emulator detection
1 parent 8e6499f commit 87610ba

File tree

2 files changed

+235
-19
lines changed

2 files changed

+235
-19
lines changed

qemu/target/i386/translate.c

Lines changed: 37 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -4792,12 +4792,12 @@ static target_ulong disas_insn(DisasContext *s, CPUState *cpu)
47924792
{
47934793
TCGContext *tcg_ctx = s->uc->tcg_ctx;
47944794
CPUX86State *env = cpu->env_ptr;
4795-
int b, prefixes;
4795+
int b, prefixes, prefix_count;
47964796
int shift;
47974797
MemOp ot, aflag, dflag;
47984798
int modrm, reg, rm, mod, op, opreg, val;
47994799
target_ulong next_eip, tval;
4800-
int rex_w, rex_r;
4800+
int rex_w, rex_r, rex_byte, rex_index;
48014801
target_ulong pc_start = s->base.pc_next;
48024802
TCGOp *tcg_op, *prev_op = NULL;
48034803
bool insn_hook = false;
@@ -4854,43 +4854,57 @@ static target_ulong disas_insn(DisasContext *s, CPUState *cpu)
48544854
prefixes = 0;
48554855
rex_w = -1;
48564856
rex_r = 0;
4857+
rex_byte = 0;
4858+
rex_index = -1;
4859+
prefix_count = 0;
48574860

48584861
next_byte:
48594862
b = x86_ldub_code(env, s);
48604863
/* Collect prefixes. */
48614864
switch (b) {
48624865
case 0xf3:
48634866
prefixes |= PREFIX_REPZ;
4867+
prefix_count++;
48644868
goto next_byte;
48654869
case 0xf2:
48664870
prefixes |= PREFIX_REPNZ;
4871+
prefix_count++;
48674872
goto next_byte;
48684873
case 0xf0:
48694874
prefixes |= PREFIX_LOCK;
4875+
prefix_count++;
48704876
goto next_byte;
48714877
case 0x2e:
48724878
s->override = R_CS;
4879+
prefix_count++;
48734880
goto next_byte;
48744881
case 0x36:
48754882
s->override = R_SS;
4883+
prefix_count++;
48764884
goto next_byte;
48774885
case 0x3e:
48784886
s->override = R_DS;
4887+
prefix_count++;
48794888
goto next_byte;
48804889
case 0x26:
48814890
s->override = R_ES;
4891+
prefix_count++;
48824892
goto next_byte;
48834893
case 0x64:
48844894
s->override = R_FS;
4895+
prefix_count++;
48854896
goto next_byte;
48864897
case 0x65:
48874898
s->override = R_GS;
4899+
prefix_count++;
48884900
goto next_byte;
48894901
case 0x66:
48904902
prefixes |= PREFIX_DATA;
4903+
prefix_count++;
48914904
goto next_byte;
48924905
case 0x67:
48934906
prefixes |= PREFIX_ADR;
4907+
prefix_count++;
48944908
goto next_byte;
48954909
#ifdef TARGET_X86_64
48964910
case 0x40:
@@ -4910,13 +4924,9 @@ static target_ulong disas_insn(DisasContext *s, CPUState *cpu)
49104924
case 0x4e:
49114925
case 0x4f:
49124926
if (CODE64(s)) {
4913-
/* REX prefix */
4914-
rex_w = (b >> 3) & 1;
4915-
rex_r = (b & 0x4) << 1;
4916-
s->rex_x = (b & 0x2) << 2;
4917-
REX_B(s) = (b & 0x1) << 3;
4918-
/* select uniform byte register addressing */
4919-
s->x86_64_hregs = true;
4927+
rex_byte = b;
4928+
rex_index = prefix_count;
4929+
prefix_count++;
49204930
goto next_byte;
49214931
}
49224932
break;
@@ -4944,7 +4954,7 @@ static target_ulong disas_insn(DisasContext *s, CPUState *cpu)
49444954
goto illegal_op;
49454955
}
49464956
#ifdef TARGET_X86_64
4947-
if (s->x86_64_hregs) {
4957+
if (rex_byte != 0) {
49484958
goto illegal_op;
49494959
}
49504960
#endif
@@ -4979,11 +4989,23 @@ static target_ulong disas_insn(DisasContext *s, CPUState *cpu)
49794989
s->vex_l = (vex3 >> 2) & 1;
49804990
prefixes |= pp_prefix[vex3 & 3] | PREFIX_VEX;
49814991
}
4992+
prefix_count++;
49824993
break;
49834994
}
49844995

49854996
/* Post-process prefixes. */
49864997
if (CODE64(s)) {
4998+
/* 2.2.1: A REX prefix is ignored when it does not immediately precede the opcode byte */
4999+
if (rex_byte != 0 && rex_index + 1 == prefix_count) {
5000+
/* REX prefix */
5001+
rex_w = (rex_byte >> 3) & 1;
5002+
rex_r = (rex_byte & 0x4) << 1;
5003+
s->rex_x = (rex_byte & 0x2) << 2;
5004+
REX_B(s) = (rex_byte & 0x1) << 3;
5005+
/* select uniform byte register addressing */
5006+
s->x86_64_hregs = true;
5007+
}
5008+
49875009
/* In 64-bit mode, the default data size is 32-bit. Select 64-bit
49885010
data with rex_w, and 16-bit data with 0x66; rex_w takes precedence
49895011
over 0x66 if both are present. */
@@ -7807,12 +7829,16 @@ static target_ulong disas_insn(DisasContext *s, CPUState *cpu)
78077829
gen_op_mov_reg_v(s, MO_64, reg, s->T0);
78087830
} else
78097831
#endif
7810-
{
7832+
if (dflag == MO_32) {
78117833
gen_op_mov_v_reg(s, MO_32, s->T0, reg);
78127834
tcg_gen_ext32u_tl(tcg_ctx, s->T0, s->T0);
78137835
tcg_gen_bswap32_tl(tcg_ctx, s->T0, s->T0);
78147836
gen_op_mov_reg_v(s, MO_32, reg, s->T0);
78157837
}
7838+
else {
7839+
tcg_gen_movi_tl(tcg_ctx, s->T0, 0);
7840+
gen_op_mov_reg_v(s, MO_16, reg, s->T0);
7841+
}
78167842
break;
78177843
case 0xd6: /* salc */
78187844
if (CODE64(s))

0 commit comments

Comments
 (0)