diff --git a/qemu/target/i386/translate.c b/qemu/target/i386/translate.c index 5cfbd680e7..2b00bb3609 100644 --- a/qemu/target/i386/translate.c +++ b/qemu/target/i386/translate.c @@ -5037,8 +5037,10 @@ static target_ulong disas_insn(DisasContext *s, CPUState *cpu) rex_r = (rex_byte & 0x4) << 1; s->rex_x = (rex_byte & 0x2) << 2; REX_B(s) = (rex_byte & 0x1) << 3; - /* select uniform byte register addressing */ - s->x86_64_hregs = true; + /* select uniform byte register addressing + * only when not decoding LAHF (0x9f) / SAHF (0x9e) + */ + s->x86_64_hregs = (b & 0x9e) != 0x9e; } /* In 64-bit mode, the default data size is 32-bit. Select 64-bit diff --git a/tests/unit/test_x86.c b/tests/unit/test_x86.c index 8deb08daed..893ec521a7 100644 --- a/tests/unit/test_x86.c +++ b/tests/unit/test_x86.c @@ -2618,6 +2618,70 @@ static void test_x86_aas_flags(void) OK(uc_close(uc)); } +static void test_x86_lahf_with_rex(void) +{ + uc_engine *uc; + + char code[] = { + // lahf + 0x40, 0x9f + }; + + uc_common_setup(&uc, UC_ARCH_X86, UC_MODE_64, code, sizeof(code)); + + uint64_t rax = 0x1122334455667788; + uint64_t rsp = 0; + uint64_t rflags = 0x246; + + OK(uc_reg_write(uc, UC_X86_REG_RAX, &rax)); + OK(uc_reg_write(uc, UC_X86_REG_RSP, &rsp)); + OK(uc_reg_write(uc, UC_X86_REG_RFLAGS, &rflags)); + + OK(uc_emu_start(uc, code_start, code_start + sizeof(code), 0, 0)); + + OK(uc_reg_read(uc, UC_X86_REG_RAX, &rax)); + OK(uc_reg_read(uc, UC_X86_REG_RSP, &rsp)); + OK(uc_reg_read(uc, UC_X86_REG_RFLAGS, &rflags)); + + TEST_CHECK(rax == 0x1122334455664688); + TEST_CHECK(rsp == 0); + TEST_CHECK(rflags == 0x246); + + OK(uc_close(uc)); +} + +static void test_x86_sahf_with_rex(void) +{ + uc_engine *uc; + + char code[] = { + // sahf + 0x40, 0x9e + }; + + uc_common_setup(&uc, UC_ARCH_X86, UC_MODE_64, code, sizeof(code)); + + uint64_t rax = 0xff << 8; + uint64_t rsp = 0; + uint64_t rflags = 2; + + OK(uc_reg_write(uc, UC_X86_REG_RAX, &rax)); + OK(uc_reg_write(uc, UC_X86_REG_RSP, &rsp)); + OK(uc_reg_write(uc, UC_X86_REG_RFLAGS, &rflags)); + + OK(uc_emu_start(uc, code_start, code_start + sizeof(code), 0, 0)); + + OK(uc_reg_read(uc, UC_X86_REG_RAX, &rax)); + OK(uc_reg_read(uc, UC_X86_REG_RSP, &rsp)); + OK(uc_reg_read(uc, UC_X86_REG_RFLAGS, &rflags)); + + TEST_CHECK(rax == 0xff << 8); + TEST_CHECK(rsp == 0); + TEST_CHECK(rflags == 0xd7); + + OK(uc_close(uc)); +} + static void test_x86_group_1a(void) { uc_engine *uc; @@ -2809,6 +2873,8 @@ TEST_LIST = { {"test_x86_mem_hooks_pc_guarantee", test_x86_mem_hooks_pc_guarantee}, {"test_x86_aaa_flags", test_x86_aaa_flags}, {"test_x86_aas_flags", test_x86_aas_flags}, + {"test_x86_lahf_with_rex", test_x86_lahf_with_rex}, + {"test_x86_sahf_with_rex", test_x86_sahf_with_rex}, {"test_x86_group_1a", test_x86_group_1a}, {"test_x86_lock_bt_mem", test_x86_lock_bt_mem}, {"test_x86_lock_bt_reg", test_x86_lock_bt_reg},