Fix handling of 66h prefix on jumps

It turns out that in x86-64 mode, address and operand size overrides are
ignored by the processor. (Tested that on a real machine.)

Even libopcodes gets this wrong...
This commit is contained in:
Alexis Engelke
2019-01-14 19:53:46 +01:00
parent a799024066
commit 20f6e8c073
3 changed files with 15 additions and 1 deletions

View File

@@ -570,6 +570,8 @@ decode(const uint8_t* buffer, int len, DecodeMode mode, uintptr_t address,
} }
else if (UNLIKELY(imm_control != 0)) else if (UNLIKELY(imm_control != 0))
{ {
struct Operand* operand = &instr->operands[DESC_IMM_IDX(desc)];
uint8_t imm_size; uint8_t imm_size;
if (DESC_IMM_BYTE(desc)) if (DESC_IMM_BYTE(desc))
{ {
@@ -583,6 +585,14 @@ decode(const uint8_t* buffer, int len, DecodeMode mode, uintptr_t address,
{ {
imm_size = 3; imm_size = 3;
} }
#if defined(ARCH_X86_64)
else if (mode == DECODE_64 && UNLIKELY(imm_control == 4))
{
// Jumps are always 8 or 32 bit on x86-64.
imm_size = 4;
operand->size = 8;
}
#endif
else if (prefixes & PREFIX_OPSZ) else if (prefixes & PREFIX_OPSZ)
{ {
imm_size = 2; imm_size = 2;
@@ -634,7 +644,6 @@ decode(const uint8_t* buffer, int len, DecodeMode mode, uintptr_t address,
instr->immediate += instr->address + off; instr->immediate += instr->address + off;
} }
struct Operand* operand = &instr->operands[DESC_IMM_IDX(desc)];
if (UNLIKELY(imm_control == 5)) if (UNLIKELY(imm_control == 5))
{ {
operand->type = OT_REG; operand->type = OT_REG;

4
tests/decode-jmp.txt Normal file
View File

@@ -0,0 +1,4 @@
decode32 e900000000 [JMP imm4:0x1234005]
decode32 66e90100 [JMP imm2:0x4005]
decode64 e900000000 [JMP imm8:0x1234005]
decode64 66e900000000 [JMP imm8:0x1234006]

View File

@@ -19,6 +19,7 @@ testcases = [
['enter', 'decode-enter.sh'], ['enter', 'decode-enter.sh'],
['imul', 'decode-imul.sh'], ['imul', 'decode-imul.sh'],
['inc', 'decode-inc.sh'], ['inc', 'decode-inc.sh'],
['jmp', 'decode-jmp.txt'],
['movsx', 'decode-movsx.sh'], ['movsx', 'decode-movsx.sh'],
['ret', 'decode-ret.sh'], ['ret', 'decode-ret.sh'],