// http://ref.x86asm.net/coder32.html export interface X86Encoding { opcode: number os?: number e?: number fixed_g?: number custom?: number custom_modrm_resolve?: number custom_sti?: number prefix?: number block_boundary?: number no_block_boundary_in_interpreted?: number no_next_instruction?: number absolute_jump?: number jump_offset_imm?: number conditional_jump?: number imm8?: number imm8s?: number imm16?: number imm1632?: number imm32?: number immaddr?: number extra_imm8?: number extra_imm16?: number mask_flags?: number skip?: number skip_mem?: number skip_reg?: number is_string?: number is_fpu?: number task_switch_test?: number sse?: number reg_ud?: number mem_ud?: number ignore_mod?: number } const zf = 1 << 6 const of = 1 << 11 const cf = 1 << 0 const af = 1 << 4 const pf = 1 << 2 const sf = 1 << 7 // Test intel-specific behaviour // Setting this to true can make some tests fail const TESTS_ASSUME_INTEL = false // === Types of instructions // // create entry | check for compiled code | instruction // -------------+-------------------------+----------------------------------------------------------- // 1 | optional | pop ds (may change cpu state) // | | trigger_ud, div (exception that doesn't generate conditional return from BB) // | | port io, popf, sti (may call interrupt or continue at next instruction) // | | hlt // -------------+-------------------------+----------------------------------------------------------- // 1 | 1 | call [eax], jmp [eax], int, iret, ret, jmpf, callf, sysenter, sysexit // | | Special case: normal instruction with fallthough to next page // | | Special case: after execution of compiled code // | | -> may create redundant entry points depending on last instruction? // -------------+-------------------------+----------------------------------------------------------- // 1 | 0 | rep movs, rep lods, rep stos, rep cmps, rep scas // | | -> Executed as follows: // | | - Upto including the first call in compiled mode // | | - Back to main loop and repeated in interpreted mode (as entry point is after instruction, not on) // | | - When finished entry pointer *after* instruction is hit and execution continues in compiled mode // -------------+-------------------------+----------------------------------------------------------- // 0 | optional | jmp foo, jnz foo // | | (foo is in the same page as the instruction) // -------------+-------------------------+----------------------------------------------------------- // 1 | 1 | call foo // | | (foo is in the same page as the instruction) // | | -> The entry point is not created for jumps within // | | this page, but speculatively for calls from // | | other pages to the function in this page // -------------+-------------------------+----------------------------------------------------------- // 1 | 1 | call foo, jmp foo, jnz foo // | | (foo is in a different page than the instruction) // e: a modrm byte follows the operand // os: the instruction behaves differently depending on the operand size // fixed_g: the reg field of the modrm byte selects an instruction // skip: skip automatically generated tests (nasmtests) // mask_flags: flags bits to mask in generated tests // prefix: is a prefix instruction // imm8, imm8s, imm16, imm1632, immaddr, extra_imm8, extra_imm16: one or two immediate bytes follows the instruction // custom: will callback jit to generate custom code // block_boundary: may change eip in a way not handled by the jit // no_next_instruction: jit will stop analysing after instruction (e.g., unconditional jump, ret) const encodings: X86Encoding[] = [ { opcode: 0x06, os: 1, custom: 1 }, { opcode: 0x07, os: 1, skip: 1, block_boundary: 1 }, // pop es: block_boundary since it uses non-raising cpu exceptions { opcode: 0x0e, os: 1, custom: 1 }, { opcode: 0x0f, os: 1, prefix: 1 }, { opcode: 0x16, os: 1, custom: 1 }, { opcode: 0x17, block_boundary: 1, os: 1, skip: 1 }, // pop ss { opcode: 0x1e, os: 1, custom: 1 }, { opcode: 0x1f, block_boundary: 1, os: 1, skip: 1 }, // pop ds { opcode: 0x26, prefix: 1 }, { opcode: 0x27, mask_flags: of }, { opcode: 0x2e, prefix: 1 }, { opcode: 0x2f, mask_flags: of }, { opcode: 0x36, prefix: 1 }, { opcode: 0x37, mask_flags: of | sf | pf | zf }, { opcode: 0x3e, prefix: 1 }, { opcode: 0x3f, mask_flags: of | sf | pf | zf }, { opcode: 0x60, os: 1, block_boundary: 1 }, // pusha { opcode: 0x61, os: 1, block_boundary: 1 }, // popa { opcode: 0x62, e: 1, skip: 1 }, { opcode: 0x63, e: 1, block_boundary: 1 }, // arpl { opcode: 0x64, prefix: 1 }, { opcode: 0x65, prefix: 1 }, { opcode: 0x66, prefix: 1 }, { opcode: 0x67, prefix: 1 }, { opcode: 0x68, custom: 1, os: 1, imm1632: 1 }, { opcode: 0x69, os: 1, e: 1, custom: 1, imm1632: 1, mask_flags: TESTS_ASSUME_INTEL ? af : sf | zf | af | pf, }, { opcode: 0x6a, custom: 1, os: 1, imm8s: 1 }, { opcode: 0x6b, os: 1, e: 1, custom: 1, imm8s: 1, mask_flags: TESTS_ASSUME_INTEL ? af : sf | zf | af | pf, }, { opcode: 0x6c, block_boundary: 1, custom: 1, is_string: 1, skip: 1 }, // ins { opcode: 0xf26c, block_boundary: 1, custom: 1, is_string: 1, skip: 1 }, { opcode: 0xf36c, block_boundary: 1, custom: 1, is_string: 1, skip: 1 }, { opcode: 0x6d, block_boundary: 1, custom: 1, is_string: 1, os: 1, skip: 1, }, { opcode: 0xf26d, block_boundary: 1, custom: 1, is_string: 1, os: 1, skip: 1, }, { opcode: 0xf36d, block_boundary: 1, custom: 1, is_string: 1, os: 1, skip: 1, }, { opcode: 0x6e, block_boundary: 1, custom: 1, is_string: 1, skip: 1 }, // outs { opcode: 0xf26e, block_boundary: 1, custom: 1, is_string: 1, skip: 1 }, { opcode: 0xf36e, block_boundary: 1, custom: 1, is_string: 1, skip: 1 }, { opcode: 0x6f, block_boundary: 1, custom: 1, is_string: 1, os: 1, skip: 1, }, { opcode: 0xf26f, block_boundary: 1, custom: 1, is_string: 1, os: 1, skip: 1, }, { opcode: 0xf36f, block_boundary: 1, custom: 1, is_string: 1, os: 1, skip: 1, }, { opcode: 0x84, custom: 1, e: 1 }, { opcode: 0x85, custom: 1, e: 1, os: 1 }, { opcode: 0x86, custom: 1, e: 1 }, { opcode: 0x87, custom: 1, os: 1, e: 1 }, { opcode: 0x88, custom: 1, e: 1 }, { opcode: 0x89, custom: 1, os: 1, e: 1 }, { opcode: 0x8a, custom: 1, e: 1 }, { opcode: 0x8b, custom: 1, os: 1, e: 1 }, { opcode: 0x8c, os: 1, e: 1, custom: 1, skip: 1 }, // mov reg, sreg { opcode: 0x8d, reg_ud: 1, os: 1, e: 1, custom_modrm_resolve: 1, custom: 1, }, // lea { opcode: 0x8e, block_boundary: 1, e: 1, skip: 1 }, // mov sreg { opcode: 0x8f, os: 1, e: 1, fixed_g: 0, custom_modrm_resolve: 1, custom: 1, block_boundary: 1, }, // pop r/m { opcode: 0x90, custom: 1 }, { opcode: 0x91, custom: 1, os: 1 }, { opcode: 0x92, custom: 1, os: 1 }, { opcode: 0x93, custom: 1, os: 1 }, { opcode: 0x94, custom: 1, os: 1 }, { opcode: 0x95, custom: 1, os: 1 }, { opcode: 0x96, custom: 1, os: 1 }, { opcode: 0x97, custom: 1, os: 1 }, { opcode: 0x98, os: 1, custom: 1 }, { opcode: 0x99, os: 1, custom: 1 }, { opcode: 0x9a, os: 1, imm1632: 1, extra_imm16: 1, skip: 1, block_boundary: 1, }, // callf { opcode: 0x9b, block_boundary: 1, skip: 1 }, // fwait: block_boundary since it uses non-raising cpu exceptions { opcode: 0x9c, os: 1, custom: 1, skip: 1 }, // pushf { opcode: 0x9d, os: 1, custom: 1, skip: 1 }, // popf { opcode: 0x9e, custom: 1 }, { opcode: 0x9f, custom: 1 }, { opcode: 0xa0, custom: 1, immaddr: 1 }, { opcode: 0xa1, custom: 1, os: 1, immaddr: 1 }, { opcode: 0xa2, custom: 1, immaddr: 1 }, { opcode: 0xa3, custom: 1, os: 1, immaddr: 1 }, // string instructions aren't jumps, but they modify eip due to how they're implemented { opcode: 0xa4, block_boundary: 0, custom: 1, is_string: 1 }, { opcode: 0xf2a4, block_boundary: 1, custom: 1, is_string: 1 }, { opcode: 0xf3a4, block_boundary: 1, custom: 1, is_string: 1 }, { opcode: 0xa5, block_boundary: 0, custom: 1, is_string: 1, os: 1 }, { opcode: 0xf2a5, block_boundary: 1, custom: 1, is_string: 1, os: 1 }, { opcode: 0xf3a5, block_boundary: 1, custom: 1, is_string: 1, os: 1 }, { opcode: 0xa6, block_boundary: 1, custom: 1, is_string: 1 }, { opcode: 0xf2a6, block_boundary: 1, custom: 1, is_string: 1 }, { opcode: 0xf3a6, block_boundary: 1, custom: 1, is_string: 1 }, { opcode: 0xa7, block_boundary: 1, custom: 1, is_string: 1, os: 1 }, { opcode: 0xf2a7, block_boundary: 1, custom: 1, is_string: 1, os: 1 }, { opcode: 0xf3a7, block_boundary: 1, custom: 1, is_string: 1, os: 1 }, { opcode: 0xa8, custom: 1, imm8: 1 }, { opcode: 0xa9, custom: 1, os: 1, imm1632: 1 }, { opcode: 0xaa, block_boundary: 0, custom: 1, is_string: 1 }, { opcode: 0xf2aa, block_boundary: 1, custom: 1, is_string: 1 }, { opcode: 0xf3aa, block_boundary: 1, custom: 1, is_string: 1 }, { opcode: 0xab, block_boundary: 0, custom: 1, is_string: 1, os: 1 }, { opcode: 0xf2ab, block_boundary: 1, custom: 1, is_string: 1, os: 1 }, { opcode: 0xf3ab, block_boundary: 1, custom: 1, is_string: 1, os: 1 }, { opcode: 0xac, block_boundary: 0, custom: 1, is_string: 1 }, { opcode: 0xf2ac, block_boundary: 1, custom: 1, is_string: 1 }, { opcode: 0xf3ac, block_boundary: 1, custom: 1, is_string: 1 }, { opcode: 0xad, block_boundary: 0, custom: 1, is_string: 1, os: 1 }, { opcode: 0xf2ad, block_boundary: 1, custom: 1, is_string: 1, os: 1 }, { opcode: 0xf3ad, block_boundary: 1, custom: 1, is_string: 1, os: 1 }, { opcode: 0xae, block_boundary: 0, custom: 1, is_string: 1 }, { opcode: 0xf2ae, block_boundary: 1, custom: 1, is_string: 1 }, { opcode: 0xf3ae, block_boundary: 1, custom: 1, is_string: 1 }, { opcode: 0xaf, block_boundary: 0, custom: 1, is_string: 1, os: 1 }, { opcode: 0xf2af, block_boundary: 1, custom: 1, is_string: 1, os: 1 }, { opcode: 0xf3af, block_boundary: 1, custom: 1, is_string: 1, os: 1 }, { opcode: 0xc2, custom: 1, block_boundary: 1, no_next_instruction: 1, os: 1, absolute_jump: 1, imm16: 1, skip: 1, }, // ret { opcode: 0xc3, custom: 1, block_boundary: 1, no_next_instruction: 1, os: 1, absolute_jump: 1, skip: 1, }, { opcode: 0xc4, block_boundary: 1, os: 1, e: 1, skip: 1 }, // les { opcode: 0xc5, block_boundary: 1, os: 1, e: 1, skip: 1 }, // lds { opcode: 0xc6, custom: 1, e: 1, fixed_g: 0, imm8: 1 }, { opcode: 0xc7, custom: 1, os: 1, e: 1, fixed_g: 0, imm1632: 1 }, // XXX: Temporary block boundary { opcode: 0xc8, os: 1, imm16: 1, extra_imm8: 1, block_boundary: 1 }, // enter { opcode: 0xc9, custom: 1, os: 1, skip: 1 }, // leave { opcode: 0xca, block_boundary: 1, no_next_instruction: 1, os: 1, imm16: 1, skip: 1, }, // retf { opcode: 0xcb, block_boundary: 1, no_next_instruction: 1, os: 1, skip: 1 }, { opcode: 0xcc, block_boundary: 1, skip: 1 }, // int { opcode: 0xcd, block_boundary: 1, skip: 1, imm8: 1 }, { opcode: 0xce, block_boundary: 1, skip: 1 }, { opcode: 0xcf, block_boundary: 1, no_next_instruction: 1, os: 1, skip: 1 }, // iret { opcode: 0xd4, imm8: 1, block_boundary: 1 }, // aam, may trigger #de { opcode: 0xd5, imm8: 1, mask_flags: of | cf | af }, { opcode: 0xd6 }, { opcode: 0xd7, skip: 1, custom: 1 }, { opcode: 0xd8, e: 1, fixed_g: 0, custom: 1, is_fpu: 1, task_switch_test: 1, }, { opcode: 0xd8, e: 1, fixed_g: 1, custom: 1, is_fpu: 1, task_switch_test: 1, }, { opcode: 0xd8, e: 1, fixed_g: 2, custom: 1, is_fpu: 1, task_switch_test: 1, }, { opcode: 0xd8, e: 1, fixed_g: 3, custom: 1, is_fpu: 1, task_switch_test: 1, }, { opcode: 0xd8, e: 1, fixed_g: 4, custom: 1, is_fpu: 1, task_switch_test: 1, }, { opcode: 0xd8, e: 1, fixed_g: 5, custom: 1, is_fpu: 1, task_switch_test: 1, }, { opcode: 0xd8, e: 1, fixed_g: 6, custom: 1, is_fpu: 1, task_switch_test: 1, }, { opcode: 0xd8, e: 1, fixed_g: 7, custom: 1, is_fpu: 1, task_switch_test: 1, }, { opcode: 0xd9, e: 1, fixed_g: 0, custom: 1, is_fpu: 1, task_switch_test: 1, os: 1, }, { opcode: 0xd9, e: 1, fixed_g: 1, custom: 1, is_fpu: 1, task_switch_test: 1, os: 1, }, { opcode: 0xd9, e: 1, fixed_g: 2, custom: 1, is_fpu: 1, task_switch_test: 1, os: 1, }, { opcode: 0xd9, e: 1, fixed_g: 3, custom: 1, is_fpu: 1, task_switch_test: 1, os: 1, }, { opcode: 0xd9, e: 1, fixed_g: 4, custom: 1, is_fpu: 1, task_switch_test: 1, os: 1, skip_mem: 1, }, // fldenv (mem) { opcode: 0xd9, e: 1, fixed_g: 5, custom: 1, is_fpu: 1, task_switch_test: 1, os: 1, }, { opcode: 0xd9, e: 1, fixed_g: 6, custom: 1, is_fpu: 1, task_switch_test: 1, os: 1, skip: 1, }, // fstenv (mem), fprem (reg) { opcode: 0xd9, e: 1, fixed_g: 7, custom: 1, is_fpu: 1, task_switch_test: 1, os: 1, skip_reg: 1, }, // fprem, fyl2xp1 (precision issues) { opcode: 0xda, e: 1, fixed_g: 0, custom: 1, is_fpu: 1, task_switch_test: 1, }, { opcode: 0xda, e: 1, fixed_g: 1, custom: 1, is_fpu: 1, task_switch_test: 1, }, { opcode: 0xda, e: 1, fixed_g: 2, custom: 1, is_fpu: 1, task_switch_test: 1, }, { opcode: 0xda, e: 1, fixed_g: 3, custom: 1, is_fpu: 1, task_switch_test: 1, }, { opcode: 0xda, e: 1, fixed_g: 4, custom: 1, is_fpu: 1, task_switch_test: 1, }, { opcode: 0xda, e: 1, fixed_g: 5, custom: 1, is_fpu: 1, task_switch_test: 1, }, { opcode: 0xda, e: 1, fixed_g: 6, custom: 1, is_fpu: 1, task_switch_test: 1, }, { opcode: 0xda, e: 1, fixed_g: 7, custom: 1, is_fpu: 1, task_switch_test: 1, }, { opcode: 0xdb, e: 1, fixed_g: 0, custom: 1, is_fpu: 1, task_switch_test: 1, }, { opcode: 0xdb, e: 1, fixed_g: 1, custom: 1, is_fpu: 1, task_switch_test: 1, }, // fisttp (sse3) { opcode: 0xdb, e: 1, fixed_g: 2, custom: 1, is_fpu: 1, task_switch_test: 1, }, { opcode: 0xdb, e: 1, fixed_g: 3, custom: 1, is_fpu: 1, task_switch_test: 1, }, { opcode: 0xdb, e: 1, fixed_g: 4, custom: 0, is_fpu: 1, task_switch_test: 1, }, { opcode: 0xdb, e: 1, fixed_g: 5, custom: 1, is_fpu: 1, task_switch_test: 1, }, { opcode: 0xdb, e: 1, fixed_g: 6, custom: 1, is_fpu: 1, task_switch_test: 1, }, { opcode: 0xdb, e: 1, fixed_g: 7, custom: 0, is_fpu: 1, task_switch_test: 1, }, { opcode: 0xdc, e: 1, fixed_g: 0, custom: 1, is_fpu: 1, task_switch_test: 1, }, { opcode: 0xdc, e: 1, fixed_g: 1, custom: 1, is_fpu: 1, task_switch_test: 1, }, { opcode: 0xdc, e: 1, fixed_g: 2, custom: 1, is_fpu: 1, task_switch_test: 1, }, { opcode: 0xdc, e: 1, fixed_g: 3, custom: 1, is_fpu: 1, task_switch_test: 1, }, { opcode: 0xdc, e: 1, fixed_g: 4, custom: 1, is_fpu: 1, task_switch_test: 1, }, { opcode: 0xdc, e: 1, fixed_g: 5, custom: 1, is_fpu: 1, task_switch_test: 1, }, { opcode: 0xdc, e: 1, fixed_g: 6, custom: 1, is_fpu: 1, task_switch_test: 1, }, { opcode: 0xdc, e: 1, fixed_g: 7, custom: 1, is_fpu: 1, task_switch_test: 1, }, { opcode: 0xdd, e: 1, fixed_g: 0, custom: 1, is_fpu: 1, task_switch_test: 1, os: 1, }, { opcode: 0xdd, e: 1, fixed_g: 1, custom: 1, is_fpu: 1, task_switch_test: 1, os: 1, }, // fisttp (sse3) { opcode: 0xdd, e: 1, fixed_g: 2, custom: 1, is_fpu: 1, task_switch_test: 1, os: 1, }, { opcode: 0xdd, e: 1, fixed_g: 3, custom: 1, is_fpu: 1, task_switch_test: 1, os: 1, }, { opcode: 0xdd, e: 1, fixed_g: 4, custom: 0, is_fpu: 1, task_switch_test: 1, os: 1, skip_mem: 1, }, // frstor { opcode: 0xdd, e: 1, fixed_g: 5, custom: 1, is_fpu: 1, task_switch_test: 1, os: 1, }, { opcode: 0xdd, e: 1, fixed_g: 6, custom: 0, is_fpu: 1, task_switch_test: 1, os: 1, skip_mem: 1, }, // fsave { opcode: 0xdd, e: 1, fixed_g: 7, custom: 0, is_fpu: 1, task_switch_test: 1, os: 1, skip_mem: 1, }, // fstsw (denormal flag) { opcode: 0xde, e: 1, fixed_g: 0, custom: 1, is_fpu: 1, task_switch_test: 1, }, { opcode: 0xde, e: 1, fixed_g: 1, custom: 1, is_fpu: 1, task_switch_test: 1, }, { opcode: 0xde, e: 1, fixed_g: 2, custom: 1, is_fpu: 1, task_switch_test: 1, }, { opcode: 0xde, e: 1, fixed_g: 3, custom: 1, is_fpu: 1, task_switch_test: 1, }, { opcode: 0xde, e: 1, fixed_g: 4, custom: 1, is_fpu: 1, task_switch_test: 1, }, { opcode: 0xde, e: 1, fixed_g: 5, custom: 1, is_fpu: 1, task_switch_test: 1, }, { opcode: 0xde, e: 1, fixed_g: 6, custom: 1, is_fpu: 1, task_switch_test: 1, }, { opcode: 0xde, e: 1, fixed_g: 7, custom: 1, is_fpu: 1, task_switch_test: 1, }, { opcode: 0xdf, e: 1, fixed_g: 0, custom: 0, is_fpu: 1, task_switch_test: 1, }, { opcode: 0xdf, e: 1, fixed_g: 1, custom: 1, is_fpu: 1, task_switch_test: 1, }, // fisttp (sse3) { opcode: 0xdf, e: 1, fixed_g: 2, custom: 1, is_fpu: 1, task_switch_test: 1, }, { opcode: 0xdf, e: 1, fixed_g: 3, custom: 1, is_fpu: 1, task_switch_test: 1, }, { opcode: 0xdf, e: 1, fixed_g: 4, custom: 1, is_fpu: 1, task_switch_test: 1, skip: 1, }, // unimplemented: Binary Coded Decimals / fsts (denormal flag) { opcode: 0xdf, e: 1, fixed_g: 5, custom: 1, is_fpu: 1, task_switch_test: 1, }, { opcode: 0xdf, e: 1, fixed_g: 6, custom: 1, is_fpu: 1, task_switch_test: 1, }, { opcode: 0xdf, e: 1, fixed_g: 7, custom: 1, is_fpu: 1, task_switch_test: 1, }, // loop, jcxz, etc. { opcode: 0xe0, os: 1, imm8s: 1, no_block_boundary_in_interpreted: 1, skip: 1, block_boundary: 1, jump_offset_imm: 1, custom: 1, conditional_jump: 1, }, { opcode: 0xe1, os: 1, imm8s: 1, no_block_boundary_in_interpreted: 1, skip: 1, block_boundary: 1, jump_offset_imm: 1, custom: 1, conditional_jump: 1, }, { opcode: 0xe2, os: 1, imm8s: 1, no_block_boundary_in_interpreted: 1, skip: 1, block_boundary: 1, jump_offset_imm: 1, custom: 1, conditional_jump: 1, }, { opcode: 0xe3, os: 1, imm8s: 1, no_block_boundary_in_interpreted: 1, skip: 1, block_boundary: 1, jump_offset_imm: 1, custom: 1, conditional_jump: 1, }, // port functions aren't jumps, but they may modify eip due to how they are implemented { opcode: 0xe4, block_boundary: 1, imm8: 1, skip: 1 }, // in { opcode: 0xe5, block_boundary: 1, os: 1, imm8: 1, skip: 1 }, { opcode: 0xe6, block_boundary: 1, imm8: 1, skip: 1 }, // out { opcode: 0xe7, block_boundary: 1, os: 1, imm8: 1, skip: 1 }, { opcode: 0xe8, block_boundary: 1, jump_offset_imm: 1, os: 1, imm1632: 1, custom: 1, skip: 1, }, // call { opcode: 0xe9, block_boundary: 1, no_block_boundary_in_interpreted: 1, jump_offset_imm: 1, no_next_instruction: 1, os: 1, imm1632: 1, custom: 1, skip: 1, }, { opcode: 0xea, block_boundary: 1, no_next_instruction: 1, os: 1, imm1632: 1, extra_imm16: 1, skip: 1, }, // jmpf { opcode: 0xeb, block_boundary: 1, no_block_boundary_in_interpreted: 1, jump_offset_imm: 1, no_next_instruction: 1, os: 1, imm8s: 1, custom: 1, skip: 1, }, { opcode: 0xec, block_boundary: 1, skip: 1 }, // in { opcode: 0xed, block_boundary: 1, os: 1, skip: 1 }, { opcode: 0xee, block_boundary: 1, skip: 1 }, // out { opcode: 0xef, block_boundary: 1, os: 1, skip: 1 }, { opcode: 0xf0, prefix: 1 }, { opcode: 0xf1, skip: 1 }, { opcode: 0xf2, prefix: 1 }, { opcode: 0xf3, prefix: 1 }, { opcode: 0xf4, block_boundary: 1, no_next_instruction: 1, skip: 1 }, // hlt { opcode: 0xf5 }, { opcode: 0xf6, e: 1, fixed_g: 0, imm8: 1, custom: 1 }, { opcode: 0xf6, e: 1, fixed_g: 1, imm8: 1, custom: 1 }, { opcode: 0xf6, e: 1, fixed_g: 2, custom: 1 }, { opcode: 0xf6, e: 1, fixed_g: 3, custom: 1 }, { opcode: 0xf6, e: 1, fixed_g: 4, mask_flags: TESTS_ASSUME_INTEL ? af | zf : sf | zf | af | pf, }, { opcode: 0xf6, e: 1, fixed_g: 5, mask_flags: TESTS_ASSUME_INTEL ? af | zf : sf | zf | af | pf, }, // div/idiv: Not a block boundary, but doesn't use control flow exceptions { opcode: 0xf6, e: 1, fixed_g: 6, mask_flags: TESTS_ASSUME_INTEL ? 0 : sf | zf | af | pf, block_boundary: 1, }, { opcode: 0xf6, e: 1, fixed_g: 7, mask_flags: TESTS_ASSUME_INTEL ? 0 : sf | zf | af | pf, block_boundary: 1, }, { opcode: 0xf7, os: 1, e: 1, fixed_g: 0, imm1632: 1, custom: 1 }, { opcode: 0xf7, os: 1, e: 1, fixed_g: 1, imm1632: 1, custom: 1 }, { opcode: 0xf7, os: 1, e: 1, fixed_g: 2, custom: 1 }, { opcode: 0xf7, os: 1, e: 1, fixed_g: 3, custom: 1 }, { opcode: 0xf7, os: 1, e: 1, fixed_g: 4, mask_flags: TESTS_ASSUME_INTEL ? af | zf : sf | zf | af | pf, custom: 1, }, { opcode: 0xf7, os: 1, e: 1, fixed_g: 5, mask_flags: TESTS_ASSUME_INTEL ? af | zf : sf | zf | af | pf, custom: 1, }, { opcode: 0xf7, os: 1, e: 1, fixed_g: 6, mask_flags: TESTS_ASSUME_INTEL ? 0 : sf | zf | af | pf, custom: 1, }, { opcode: 0xf7, os: 1, e: 1, fixed_g: 7, mask_flags: TESTS_ASSUME_INTEL ? 0 : sf | zf | af | pf, custom: 1, }, { opcode: 0xf8, custom: 1 }, { opcode: 0xf9, custom: 1 }, { opcode: 0xfa, custom: 1, skip: 1 }, // STI: Note: Has special handling in jit in order to call handle_irqs safely { opcode: 0xfb, custom: 1, custom_sti: 1, skip: 1 }, { opcode: 0xfc, custom: 1 }, { opcode: 0xfd, custom: 1 }, { opcode: 0xfe, e: 1, fixed_g: 0, custom: 1 }, { opcode: 0xfe, e: 1, fixed_g: 1, custom: 1 }, { opcode: 0xff, os: 1, e: 1, fixed_g: 0, custom: 1 }, { opcode: 0xff, os: 1, e: 1, fixed_g: 1, custom: 1 }, { opcode: 0xff, os: 1, e: 1, fixed_g: 2, custom: 1, block_boundary: 1, absolute_jump: 1, skip: 1, }, { opcode: 0xff, os: 1, e: 1, fixed_g: 3, block_boundary: 1, skip: 1 }, { opcode: 0xff, os: 1, e: 1, fixed_g: 4, custom: 1, block_boundary: 1, absolute_jump: 1, no_next_instruction: 1, skip: 1, }, { opcode: 0xff, os: 1, e: 1, fixed_g: 5, block_boundary: 1, no_next_instruction: 1, skip: 1, }, { opcode: 0xff, custom: 1, os: 1, e: 1, fixed_g: 6 }, { opcode: 0x0f00, fixed_g: 0, e: 1, skip: 1, block_boundary: 1, os: 1 }, // sldt, ... { opcode: 0x0f00, fixed_g: 1, e: 1, skip: 1, block_boundary: 1, os: 1 }, { opcode: 0x0f00, fixed_g: 2, e: 1, skip: 1, block_boundary: 1, os: 1 }, { opcode: 0x0f00, fixed_g: 3, e: 1, skip: 1, block_boundary: 1, os: 1 }, { opcode: 0x0f00, fixed_g: 4, e: 1, skip: 1, block_boundary: 1, os: 1 }, { opcode: 0x0f00, fixed_g: 5, e: 1, skip: 1, block_boundary: 1, os: 1 }, { opcode: 0x0f01, fixed_g: 0, e: 1, skip: 1, block_boundary: 1, os: 1 }, // sgdt, ... { opcode: 0x0f01, fixed_g: 1, e: 1, skip: 1, block_boundary: 1, os: 1 }, { opcode: 0x0f01, fixed_g: 2, e: 1, skip: 1, block_boundary: 1, os: 1 }, { opcode: 0x0f01, fixed_g: 3, e: 1, skip: 1, block_boundary: 1, os: 1 }, { opcode: 0x0f01, fixed_g: 4, e: 1, skip: 1, block_boundary: 1, os: 1 }, { opcode: 0x0f01, fixed_g: 6, e: 1, skip: 1, block_boundary: 1, os: 1 }, { opcode: 0x0f01, fixed_g: 7, e: 1, skip: 1, block_boundary: 1, os: 1 }, { opcode: 0x0f02, os: 1, e: 1, skip: 1, block_boundary: 1 }, // lar { opcode: 0x0f03, os: 1, e: 1, skip: 1, block_boundary: 1 }, // lsl { opcode: 0x0f04, skip: 1, block_boundary: 1 }, { opcode: 0x0f05, skip: 1, block_boundary: 1 }, { opcode: 0x0f06, skip: 1, block_boundary: 1 }, // clts { opcode: 0x0f07, skip: 1, block_boundary: 1 }, { opcode: 0x0f08, skip: 1, block_boundary: 1 }, { opcode: 0x0f09, skip: 1, block_boundary: 1 }, // wbinvd { opcode: 0x0f0a, skip: 1, block_boundary: 1 }, // ud2 // Technically has a next instruction, but Linux uses this for assertions // and embeds the assertion message after this instruction, which is likely // the most common use case of ud2 { opcode: 0x0f0b, skip: 1, block_boundary: 1, custom: 1, no_next_instruction: 1, }, { opcode: 0x0f0c, skip: 1, block_boundary: 1 }, { opcode: 0x0f0d, skip: 1, block_boundary: 1 }, { opcode: 0x0f0e, skip: 1, block_boundary: 1 }, { opcode: 0x0f0f, skip: 1, block_boundary: 1 }, { opcode: 0x0f18, e: 1, custom: 1 }, { opcode: 0x0f19, custom: 1, e: 1 }, { opcode: 0x0f1a, skip: 1, block_boundary: 1 }, { opcode: 0x0f1b, skip: 1, block_boundary: 1 }, { opcode: 0x0f1c, custom: 1, e: 1 }, { opcode: 0x0f1d, custom: 1, e: 1 }, { opcode: 0x0f1e, custom: 1, e: 1 }, { opcode: 0x0f1f, custom: 1, e: 1 }, { opcode: 0x0f20, ignore_mod: 1, e: 1, skip: 1, block_boundary: 1 }, // mov reg, creg { opcode: 0x0f21, ignore_mod: 1, e: 1, skip: 1, block_boundary: 1 }, // mov reg, dreg { opcode: 0x0f22, ignore_mod: 1, e: 1, skip: 1, block_boundary: 1 }, // mov creg, reg { opcode: 0x0f23, ignore_mod: 1, e: 1, skip: 1, block_boundary: 1 }, // mov dreg, reg { opcode: 0x0f24, skip: 1, block_boundary: 1 }, { opcode: 0x0f25, skip: 1, block_boundary: 1 }, { opcode: 0x0f26, skip: 1, block_boundary: 1 }, { opcode: 0x0f27, skip: 1, block_boundary: 1 }, { opcode: 0x0f30, skip: 1, block_boundary: 1 }, // wrmsr { opcode: 0x0f31, skip: 1, custom: 1 }, // rdtsc { opcode: 0x0f32, skip: 1, block_boundary: 1 }, // rdmsr { opcode: 0x0f33, skip: 1, block_boundary: 1 }, // rdpmc { opcode: 0x0f34, skip: 1, block_boundary: 1, no_next_instruction: 1 }, // sysenter { opcode: 0x0f35, skip: 1, block_boundary: 1, no_next_instruction: 1 }, // sysexit { opcode: 0x0f36, skip: 1, block_boundary: 1 }, // ud { opcode: 0x0f37, skip: 1, block_boundary: 1 }, // getsec // ssse3+ { opcode: 0x0f38, skip: 1, block_boundary: 1 }, { opcode: 0x0f39, skip: 1, block_boundary: 1 }, { opcode: 0x0f3a, skip: 1, block_boundary: 1 }, { opcode: 0x0f3b, skip: 1, block_boundary: 1 }, { opcode: 0x0f3c, skip: 1, block_boundary: 1 }, { opcode: 0x0f3d, skip: 1, block_boundary: 1 }, { opcode: 0x0f3e, skip: 1, block_boundary: 1 }, { opcode: 0x0f3f, skip: 1, block_boundary: 1 }, { opcode: 0x0fa0, os: 1, custom: 1 }, { opcode: 0x0fa1, os: 1, block_boundary: 1, skip: 1 }, // pop fs: block_boundary since it uses non-raising cpu exceptions { opcode: 0x0fa2, skip: 1 }, { opcode: 0x0fa8, os: 1, custom: 1 }, { opcode: 0x0fa9, os: 1, block_boundary: 1, skip: 1 }, // pop gs { opcode: 0x0fa3, os: 1, e: 1, custom: 1, skip_mem: 1 }, // bt (can also index memory, but not supported by test right now) { opcode: 0x0fab, os: 1, e: 1, custom: 1, skip_mem: 1 }, { opcode: 0x0fb3, os: 1, e: 1, custom: 1, skip_mem: 1 }, { opcode: 0x0fbb, os: 1, e: 1, custom: 1, skip_mem: 1 }, { opcode: 0x0fba, os: 1, e: 1, fixed_g: 4, imm8: 1, custom: 1 }, // bt { opcode: 0x0fba, os: 1, e: 1, fixed_g: 5, imm8: 1, custom: 1 }, { opcode: 0x0fba, os: 1, e: 1, fixed_g: 6, imm8: 1, custom: 1 }, { opcode: 0x0fba, os: 1, e: 1, fixed_g: 7, imm8: 1, custom: 1 }, { opcode: 0x0fbc, os: 1, e: 1, mask_flags: of | sf | af | pf | cf, custom: 1, }, // bsf { opcode: 0x0fbd, os: 1, e: 1, mask_flags: of | sf | af | pf | cf, custom: 1, }, // note: overflow flag only undefined if shift is > 1 { opcode: 0x0fa4, os: 1, e: 1, custom: 1, imm8: 1, mask_flags: af | of }, // shld { opcode: 0x0fa5, os: 1, e: 1, custom: 1, mask_flags: af | of }, { opcode: 0x0fac, os: 1, e: 1, custom: 1, imm8: 1, mask_flags: af | of }, { opcode: 0x0fad, os: 1, e: 1, custom: 1, mask_flags: af | of }, { opcode: 0x0fa6, skip: 1, block_boundary: 1 }, // ud { opcode: 0x0fa7, skip: 1, block_boundary: 1 }, // ud { opcode: 0x0faa, skip: 1 }, { opcode: 0x0fae, e: 1, fixed_g: 0, reg_ud: 1, task_switch_test: 1, skip: 1, block_boundary: 1, }, // fxsave { opcode: 0x0fae, e: 1, fixed_g: 1, reg_ud: 1, task_switch_test: 1, skip: 1, block_boundary: 1, }, // fxrstor { opcode: 0x0fae, e: 1, fixed_g: 2, reg_ud: 1, sse: 1, skip: 1, block_boundary: 1, }, // ldmxcsr { opcode: 0x0fae, e: 1, fixed_g: 3, reg_ud: 1, sse: 1, skip: 1, block_boundary: 1, }, // stmxcsr { opcode: 0x0fae, e: 1, fixed_g: 4, reg_ud: 1, skip: 1, block_boundary: 1 }, // xsave (mem, not implemented) { opcode: 0x0fae, e: 1, fixed_g: 5, skip: 1, custom: 1 }, // lfence (reg, only 0), xrstor (mem, not implemented) { opcode: 0x0fae, e: 1, fixed_g: 6, skip: 1, block_boundary: 1 }, // mfence (reg, only 0), xsaveopt (mem, not implemented) { opcode: 0x0fae, e: 1, fixed_g: 7, skip: 1, block_boundary: 1 }, // sfence (reg, only 0), clflush (mem) { opcode: 0x0faf, os: 1, e: 1, mask_flags: TESTS_ASSUME_INTEL ? af | zf : sf | zf | af | pf, custom: 1, }, // imul { opcode: 0x0fb0, e: 1 }, // cmxchg { opcode: 0x0fb1, os: 1, e: 1, custom: 1 }, { opcode: 0x0fc7, e: 1, fixed_g: 1, os: 1, reg_ud: 1, custom: 1 }, // cmpxchg8b (memory) { opcode: 0x0fc7, e: 1, fixed_g: 6, os: 1, mem_ud: 1, skip: 1 }, // rdrand { opcode: 0x0fb2, block_boundary: 1, os: 1, e: 1, skip: 1 }, // lss { opcode: 0x0fb4, block_boundary: 1, os: 1, e: 1, skip: 1 }, // lfs { opcode: 0x0fb5, block_boundary: 1, os: 1, e: 1, skip: 1 }, // lgs { opcode: 0x0fb6, os: 1, e: 1, custom: 1 }, // movzx { opcode: 0x0fb7, os: 1, e: 1, custom: 1 }, { opcode: 0xf30fb8, os: 1, e: 1, custom: 1 }, // popcnt { opcode: 0x0fb8, os: 1, e: 1, block_boundary: 1 }, // ud { opcode: 0x0fb9, block_boundary: 1 }, // ud2 { opcode: 0x0fbe, os: 1, e: 1, custom: 1 }, // movsx { opcode: 0x0fbf, os: 1, e: 1, custom: 1 }, { opcode: 0x0fc0, e: 1 }, // xadd { opcode: 0x0fc1, os: 1, e: 1, custom: 1 }, { opcode: 0x0fc8, custom: 1 }, // bswap { opcode: 0x0fc9, custom: 1 }, { opcode: 0x0fca, custom: 1 }, { opcode: 0x0fcb, custom: 1 }, { opcode: 0x0fcc, custom: 1 }, { opcode: 0x0fcd, custom: 1 }, { opcode: 0x0fce, custom: 1 }, { opcode: 0x0fcf, custom: 1 }, // mmx, sse { sse: 1, opcode: 0x0f10, e: 1, custom: 1 }, { sse: 1, opcode: 0xf30f10, e: 1, custom: 1 }, { sse: 1, opcode: 0x660f10, e: 1, custom: 1 }, { sse: 1, opcode: 0xf20f10, e: 1, custom: 1 }, { sse: 1, opcode: 0x0f11, e: 1, custom: 1 }, { sse: 1, opcode: 0xf30f11, e: 1, custom: 1 }, { sse: 1, opcode: 0x660f11, e: 1, custom: 1 }, { sse: 1, opcode: 0xf20f11, e: 1, custom: 1 }, { sse: 1, opcode: 0x0f12, e: 1, custom: 1 }, { sse: 1, opcode: 0x660f12, reg_ud: 1, e: 1, custom: 1 }, { sse: 1, opcode: 0xf20f12, e: 1, custom: 1 }, // sse3 { sse: 1, opcode: 0xf30f12, e: 1, custom: 1 }, // sse3 { sse: 1, opcode: 0x0f13, reg_ud: 1, e: 1, custom: 1 }, { sse: 1, opcode: 0x660f13, reg_ud: 1, e: 1, custom: 1 }, { sse: 1, opcode: 0x0f14, e: 1, custom: 1 }, { sse: 1, opcode: 0x660f14, e: 1, custom: 1 }, { sse: 1, opcode: 0x0f15, e: 1, custom: 1 }, { sse: 1, opcode: 0x660f15, e: 1, custom: 1 }, { sse: 1, opcode: 0x0f16, e: 1, custom: 1 }, { sse: 1, opcode: 0x660f16, reg_ud: 1, e: 1, custom: 1 }, { sse: 1, opcode: 0xf30f16, e: 1, custom: 1 }, // sse3 { sse: 1, opcode: 0x0f17, reg_ud: 1, e: 1, custom: 1 }, { sse: 1, opcode: 0x660f17, reg_ud: 1, e: 1, custom: 1 }, { sse: 1, opcode: 0x0f28, e: 1, custom: 1 }, { sse: 1, opcode: 0x660f28, e: 1, custom: 1 }, { sse: 1, opcode: 0x0f29, e: 1, custom: 1 }, { sse: 1, opcode: 0x660f29, e: 1, custom: 1 }, { sse: 1, opcode: 0x0f2a, e: 1, custom: 1 }, { sse: 1, opcode: 0x660f2a, e: 1, custom: 1 }, { sse: 1, opcode: 0xf20f2a, e: 1, custom: 1 }, { sse: 1, opcode: 0xf30f2a, e: 1, custom: 1 }, { sse: 1, opcode: 0x0f2b, reg_ud: 1, e: 1, custom: 1 }, { sse: 1, opcode: 0x660f2b, reg_ud: 1, e: 1, custom: 1 }, { sse: 1, opcode: 0x0f2c, e: 1 }, { sse: 1, opcode: 0x660f2c, e: 1 }, { sse: 1, opcode: 0xf20f2c, e: 1, custom: 1 }, { sse: 1, opcode: 0xf30f2c, e: 1, custom: 1 }, { sse: 1, opcode: 0x0f2d, e: 1 }, { sse: 1, opcode: 0x660f2d, e: 1 }, { sse: 1, opcode: 0xf20f2d, e: 1, custom: 1 }, { sse: 1, opcode: 0xf30f2d, e: 1, custom: 1 }, { sse: 1, opcode: 0x0f2e, e: 1, custom: 1 }, { sse: 1, opcode: 0x660f2e, e: 1, custom: 1 }, { sse: 1, opcode: 0x0f2f, e: 1, custom: 1 }, { sse: 1, opcode: 0x660f2f, e: 1, custom: 1 }, { sse: 1, opcode: 0x0f50, mem_ud: 1, e: 1 }, { sse: 1, opcode: 0x660f50, mem_ud: 1, e: 1 }, { sse: 1, opcode: 0x0f51, e: 1, custom: 1 }, { sse: 1, opcode: 0x660f51, e: 1, custom: 1 }, { sse: 1, opcode: 0xf20f51, e: 1, custom: 1 }, { sse: 1, opcode: 0xf30f51, e: 1, custom: 1 }, // approximation of 1/sqrt(x). Skipped because our approximation doesn't match intel's { sse: 1, opcode: 0x0f52, e: 1, skip: 1, custom: 1 }, { sse: 1, opcode: 0xf30f52, e: 1, skip: 1, custom: 1 }, // reciprocal: approximation of 1/x. Skipped because our approximation doesn't match intel's { sse: 1, opcode: 0x0f53, e: 1, skip: 1, custom: 1 }, { sse: 1, opcode: 0xf30f53, e: 1, skip: 1, custom: 1 }, { sse: 1, opcode: 0x0f54, e: 1, custom: 1 }, { sse: 1, opcode: 0x660f54, e: 1, custom: 1 }, { sse: 1, opcode: 0x0f55, e: 1, custom: 1 }, { sse: 1, opcode: 0x660f55, e: 1, custom: 1 }, { sse: 1, opcode: 0x0f56, e: 1, custom: 1 }, { sse: 1, opcode: 0x660f56, e: 1, custom: 1 }, { sse: 1, opcode: 0x0f57, e: 1, custom: 1 }, { sse: 1, opcode: 0x660f57, e: 1, custom: 1 }, { sse: 1, opcode: 0x0f58, e: 1, custom: 1 }, { sse: 1, opcode: 0x660f58, e: 1, custom: 1 }, { sse: 1, opcode: 0xf20f58, e: 1, custom: 1 }, { sse: 1, opcode: 0xf30f58, e: 1, custom: 1 }, { sse: 1, opcode: 0x0f59, e: 1, custom: 1 }, { sse: 1, opcode: 0x660f59, e: 1, custom: 1 }, { sse: 1, opcode: 0xf20f59, e: 1, custom: 1 }, { sse: 1, opcode: 0xf30f59, e: 1, custom: 1 }, { sse: 1, opcode: 0x0f5a, e: 1, custom: 1 }, { sse: 1, opcode: 0x660f5a, e: 1, custom: 1 }, { sse: 1, opcode: 0xf20f5a, e: 1, custom: 1 }, { sse: 1, opcode: 0xf30f5a, e: 1, custom: 1 }, { sse: 1, opcode: 0x0f5b, e: 1, custom: 1 }, { sse: 1, opcode: 0x660f5b, e: 1, custom: 1 }, // no F2 variant { sse: 1, opcode: 0xf30f5b, e: 1, custom: 1 }, { sse: 1, opcode: 0x0f5c, e: 1, custom: 1 }, { sse: 1, opcode: 0x660f5c, e: 1, custom: 1 }, { sse: 1, opcode: 0xf20f5c, e: 1, custom: 1 }, { sse: 1, opcode: 0xf30f5c, e: 1, custom: 1 }, { sse: 1, opcode: 0x0f5d, e: 1, custom: 1 }, { sse: 1, opcode: 0x660f5d, e: 1, custom: 1 }, { sse: 1, opcode: 0xf20f5d, e: 1, custom: 1 }, { sse: 1, opcode: 0xf30f5d, e: 1, custom: 1 }, { sse: 1, opcode: 0x0f5e, e: 1, custom: 1 }, { sse: 1, opcode: 0x660f5e, e: 1, custom: 1 }, { sse: 1, opcode: 0xf20f5e, e: 1, custom: 1 }, { sse: 1, opcode: 0xf30f5e, e: 1, custom: 1 }, { sse: 1, opcode: 0x0f5f, e: 1, custom: 1 }, { sse: 1, opcode: 0x660f5f, e: 1, custom: 1 }, { sse: 1, opcode: 0xf20f5f, e: 1, custom: 1 }, { sse: 1, opcode: 0xf30f5f, e: 1, custom: 1 }, { sse: 1, opcode: 0x660f60, e: 1, custom: 1 }, { sse: 1, opcode: 0x0f60, e: 1, custom: 1 }, { sse: 1, opcode: 0x660f61, e: 1, custom: 1 }, { sse: 1, opcode: 0x0f61, e: 1, custom: 1 }, { sse: 1, opcode: 0x660f62, e: 1, custom: 1 }, { sse: 1, opcode: 0x0f62, e: 1, custom: 1 }, { sse: 1, opcode: 0x660f63, e: 1, custom: 1 }, { sse: 1, opcode: 0x0f63, e: 1, custom: 1 }, { sse: 1, opcode: 0x660f64, e: 1, custom: 1 }, { sse: 1, opcode: 0x0f64, e: 1, custom: 1 }, { sse: 1, opcode: 0x660f65, e: 1, custom: 1 }, { sse: 1, opcode: 0x0f65, e: 1, custom: 1 }, { sse: 1, opcode: 0x660f66, e: 1, custom: 1 }, { sse: 1, opcode: 0x0f66, e: 1, custom: 1 }, { sse: 1, opcode: 0x660f67, e: 1, custom: 1 }, { sse: 1, opcode: 0x0f67, e: 1, custom: 1 }, { sse: 1, opcode: 0x660f68, e: 1, custom: 1 }, { sse: 1, opcode: 0x0f68, e: 1, custom: 1 }, { sse: 1, opcode: 0x660f69, e: 1, custom: 1 }, { sse: 1, opcode: 0x0f69, e: 1, custom: 1 }, { sse: 1, opcode: 0x660f6a, e: 1, custom: 1 }, { sse: 1, opcode: 0x0f6a, e: 1, custom: 1 }, { sse: 1, opcode: 0x660f6b, e: 1, custom: 1 }, { sse: 1, opcode: 0x0f6b, e: 1, custom: 1 }, { sse: 1, opcode: 0x660f6c, e: 1, custom: 1 }, { sse: 1, opcode: 0x0f6c, e: 1, block_boundary: 1 }, // ud { sse: 1, opcode: 0x660f6d, e: 1, custom: 1 }, { sse: 1, opcode: 0x0f6d, e: 1, block_boundary: 1 }, // ud { sse: 1, opcode: 0x660f6e, e: 1, custom: 1 }, { sse: 1, opcode: 0x0f6e, e: 1, custom: 1 }, { sse: 1, opcode: 0xf30f6f, e: 1, custom: 1 }, { sse: 1, opcode: 0x660f6f, e: 1, custom: 1 }, { sse: 1, opcode: 0x0f6f, e: 1, custom: 1 }, { sse: 1, opcode: 0x0f70, e: 1, imm8: 1, custom: 1 }, { sse: 1, opcode: 0x660f70, e: 1, imm8: 1, custom: 1 }, { sse: 1, opcode: 0xf20f70, e: 1, imm8: 1, custom: 1 }, { sse: 1, opcode: 0xf30f70, e: 1, imm8: 1, custom: 1 }, { sse: 1, opcode: 0x0f71, e: 1, fixed_g: 2, imm8: 1, mem_ud: 1, custom: 1 }, { sse: 1, opcode: 0x660f71, e: 1, fixed_g: 2, imm8: 1, mem_ud: 1, custom: 1, }, { sse: 1, opcode: 0x0f71, e: 1, fixed_g: 4, imm8: 1, mem_ud: 1, custom: 1 }, { sse: 1, opcode: 0x660f71, e: 1, fixed_g: 4, imm8: 1, mem_ud: 1, custom: 1, }, { sse: 1, opcode: 0x0f71, e: 1, fixed_g: 6, imm8: 1, mem_ud: 1, custom: 1 }, { sse: 1, opcode: 0x660f71, e: 1, fixed_g: 6, imm8: 1, mem_ud: 1, custom: 1, }, { sse: 1, opcode: 0x0f72, e: 1, fixed_g: 2, imm8: 1, mem_ud: 1, custom: 1 }, { sse: 1, opcode: 0x660f72, e: 1, fixed_g: 2, imm8: 1, mem_ud: 1, custom: 1, }, { sse: 1, opcode: 0x0f72, e: 1, fixed_g: 4, imm8: 1, mem_ud: 1, custom: 1 }, { sse: 1, opcode: 0x660f72, e: 1, fixed_g: 4, imm8: 1, mem_ud: 1, custom: 1, }, { sse: 1, opcode: 0x0f72, e: 1, fixed_g: 6, imm8: 1, mem_ud: 1, custom: 1 }, { sse: 1, opcode: 0x660f72, e: 1, fixed_g: 6, imm8: 1, mem_ud: 1, custom: 1, }, { sse: 1, opcode: 0x0f73, e: 1, fixed_g: 2, imm8: 1, mem_ud: 1, custom: 1 }, { sse: 1, opcode: 0x660f73, e: 1, fixed_g: 2, imm8: 1, mem_ud: 1, custom: 1, }, { sse: 1, opcode: 0x660f73, e: 1, fixed_g: 3, imm8: 1, mem_ud: 1, custom: 1, }, { sse: 1, opcode: 0x0f73, e: 1, fixed_g: 6, imm8: 1, mem_ud: 1, custom: 1 }, { sse: 1, opcode: 0x660f73, e: 1, fixed_g: 6, imm8: 1, mem_ud: 1, custom: 1, }, { sse: 1, opcode: 0x660f73, e: 1, fixed_g: 7, imm8: 1, mem_ud: 1, custom: 1, }, { sse: 1, opcode: 0x0f74, e: 1, custom: 1 }, { sse: 1, opcode: 0x660f74, e: 1, custom: 1 }, { sse: 1, opcode: 0x0f75, e: 1, custom: 1 }, { sse: 1, opcode: 0x660f75, e: 1, custom: 1 }, { sse: 1, opcode: 0x0f76, e: 1, custom: 1 }, { sse: 1, opcode: 0x660f76, e: 1, custom: 1 }, { sse: 1, opcode: 0x0f77, skip: 1 }, // emms (skip as it breaks gdb printing of float registers) // vmx instructions { opcode: 0x0f78, skip: 1, block_boundary: 1 }, { opcode: 0x0f79, skip: 1, block_boundary: 1 }, { opcode: 0x0f7a, skip: 1, block_boundary: 1 }, // ud { opcode: 0x0f7b, skip: 1, block_boundary: 1 }, // ud { sse: 1, opcode: 0x660f7c, e: 1, custom: 1 }, // sse3 { sse: 1, opcode: 0xf20f7c, e: 1, custom: 1 }, // sse3 { sse: 1, opcode: 0x660f7d, e: 1, custom: 1 }, // sse3 { sse: 1, opcode: 0xf20f7d, e: 1, custom: 1 }, // sse3 { opcode: 0x0f7c, skip: 1, block_boundary: 1 }, // ud { opcode: 0x0f7d, skip: 1, block_boundary: 1 }, // ud { sse: 1, opcode: 0x0f7e, e: 1, custom: 1 }, { sse: 1, opcode: 0x660f7e, e: 1, custom: 1 }, { sse: 1, opcode: 0xf30f7e, e: 1, custom: 1 }, { sse: 1, opcode: 0x0f7f, e: 1, custom: 1 }, { sse: 1, opcode: 0x660f7f, e: 1, custom: 1 }, { sse: 1, opcode: 0xf30f7f, e: 1, custom: 1 }, { sse: 1, opcode: 0x0fc2, e: 1, imm8: 1, custom: 1 }, { sse: 1, opcode: 0x660fc2, e: 1, imm8: 1, custom: 1 }, { sse: 1, opcode: 0xf20fc2, e: 1, imm8: 1, custom: 1 }, { sse: 1, opcode: 0xf30fc2, e: 1, imm8: 1, custom: 1 }, { opcode: 0x0fc3, e: 1, custom: 1, reg_ud: 1 }, // movnti: Uses normal registers, hence not marked as sse { sse: 1, opcode: 0x0fc4, e: 1, imm8: 1, custom: 1 }, { sse: 1, opcode: 0x660fc4, e: 1, imm8: 1, custom: 1 }, { sse: 1, opcode: 0x0fc5, e: 1, mem_ud: 1, imm8: 1, custom: 1 }, { sse: 1, opcode: 0x660fc5, e: 1, mem_ud: 1, imm8: 1, custom: 1 }, { sse: 1, opcode: 0x0fc6, e: 1, imm8: 1, custom: 1 }, { sse: 1, opcode: 0x660fc6, e: 1, imm8: 1, custom: 1 }, { sse: 1, opcode: 0x0fd0, skip: 1, block_boundary: 1 }, // sse3 { sse: 1, opcode: 0x0fd1, e: 1, custom: 1 }, { sse: 1, opcode: 0x660fd1, e: 1, custom: 1 }, { sse: 1, opcode: 0x0fd2, e: 1, custom: 1 }, { sse: 1, opcode: 0x660fd2, e: 1, custom: 1 }, { sse: 1, opcode: 0x0fd3, e: 1, custom: 1 }, { sse: 1, opcode: 0x660fd3, e: 1, custom: 1 }, { sse: 1, opcode: 0x0fd4, e: 1, custom: 1 }, { sse: 1, opcode: 0x660fd4, e: 1, custom: 1 }, { sse: 1, opcode: 0x0fd5, e: 1, custom: 1 }, { sse: 1, opcode: 0x660fd5, e: 1, custom: 1 }, { sse: 1, opcode: 0x660fd6, e: 1, custom: 1 }, { sse: 1, opcode: 0xf20fd6, mem_ud: 1, e: 1 }, { sse: 1, opcode: 0xf30fd6, mem_ud: 1, e: 1 }, { sse: 1, opcode: 0x0fd6, e: 1, block_boundary: 1 }, // ud { sse: 1, opcode: 0x0fd7, e: 1, mem_ud: 1, custom: 1 }, { sse: 1, opcode: 0x660fd7, e: 1, mem_ud: 1, custom: 1 }, { sse: 1, opcode: 0x0fd8, e: 1, custom: 1 }, { sse: 1, opcode: 0x660fd8, e: 1, custom: 1 }, { sse: 1, opcode: 0x0fd9, e: 1, custom: 1 }, { sse: 1, opcode: 0x660fd9, e: 1, custom: 1 }, { sse: 1, opcode: 0x0fda, e: 1, custom: 1 }, { sse: 1, opcode: 0x660fda, e: 1, custom: 1 }, { sse: 1, opcode: 0x0fdb, e: 1, custom: 1 }, { sse: 1, opcode: 0x660fdb, e: 1, custom: 1 }, { sse: 1, opcode: 0x0fdc, e: 1, custom: 1 }, { sse: 1, opcode: 0x660fdc, e: 1, custom: 1 }, { sse: 1, opcode: 0x0fdd, e: 1, custom: 1 }, { sse: 1, opcode: 0x660fdd, e: 1, custom: 1 }, { sse: 1, opcode: 0x0fde, e: 1, custom: 1 }, { sse: 1, opcode: 0x660fde, e: 1, custom: 1 }, { sse: 1, opcode: 0x0fdf, e: 1, custom: 1 }, { sse: 1, opcode: 0x660fdf, e: 1, custom: 1 }, { sse: 1, opcode: 0x0fe0, e: 1, custom: 1 }, { sse: 1, opcode: 0x660fe0, e: 1, custom: 1 }, { sse: 1, opcode: 0x0fe1, e: 1, custom: 1 }, { sse: 1, opcode: 0x660fe1, e: 1, custom: 1 }, { sse: 1, opcode: 0x0fe2, e: 1, custom: 1 }, { sse: 1, opcode: 0x660fe2, e: 1, custom: 1 }, { sse: 1, opcode: 0x0fe3, e: 1, custom: 1 }, { sse: 1, opcode: 0x660fe3, e: 1, custom: 1 }, { sse: 1, opcode: 0x0fe4, e: 1, custom: 1 }, { sse: 1, opcode: 0x660fe4, e: 1, custom: 1 }, { sse: 1, opcode: 0x0fe5, e: 1, custom: 1 }, { sse: 1, opcode: 0x660fe5, e: 1, custom: 1 }, { sse: 1, opcode: 0x660fe6, e: 1, custom: 1 }, { sse: 1, opcode: 0xf20fe6, e: 1, custom: 1 }, { sse: 1, opcode: 0xf30fe6, e: 1, custom: 1 }, { sse: 1, opcode: 0x0fe6, e: 1, block_boundary: 1 }, // ud { sse: 1, opcode: 0x0fe7, e: 1, reg_ud: 1 }, { sse: 1, opcode: 0x660fe7, e: 1, reg_ud: 1, custom: 1 }, { sse: 1, opcode: 0x0fe8, e: 1, custom: 1 }, { sse: 1, opcode: 0x660fe8, e: 1, custom: 1 }, { sse: 1, opcode: 0x0fe9, e: 1, custom: 1 }, { sse: 1, opcode: 0x660fe9, e: 1, custom: 1 }, { sse: 1, opcode: 0x0fea, e: 1, custom: 1 }, { sse: 1, opcode: 0x660fea, e: 1, custom: 1 }, { sse: 1, opcode: 0x0feb, e: 1, custom: 1 }, { sse: 1, opcode: 0x660feb, e: 1, custom: 1 }, { sse: 1, opcode: 0x0fec, e: 1, custom: 1 }, { sse: 1, opcode: 0x660fec, e: 1, custom: 1 }, { sse: 1, opcode: 0x0fed, e: 1, custom: 1 }, { sse: 1, opcode: 0x660fed, e: 1, custom: 1 }, { sse: 1, opcode: 0x0fee, e: 1, custom: 1 }, { sse: 1, opcode: 0x660fee, e: 1, custom: 1 }, { sse: 1, opcode: 0x0fef, e: 1, custom: 1 }, { sse: 1, opcode: 0x660fef, e: 1, custom: 1 }, { sse: 1, opcode: 0x0ff0, skip: 1, block_boundary: 1 }, // sse3 { sse: 1, opcode: 0x0ff1, e: 1, custom: 1 }, { sse: 1, opcode: 0x660ff1, e: 1, custom: 1 }, { sse: 1, opcode: 0x0ff2, e: 1, custom: 1 }, { sse: 1, opcode: 0x660ff2, e: 1, custom: 1 }, { sse: 1, opcode: 0x0ff3, e: 1, custom: 1 }, { sse: 1, opcode: 0x660ff3, e: 1, custom: 1 }, { sse: 1, opcode: 0x0ff4, e: 1, custom: 1 }, { sse: 1, opcode: 0x660ff4, e: 1, custom: 1 }, { sse: 1, opcode: 0x0ff5, e: 1, custom: 1 }, { sse: 1, opcode: 0x660ff5, e: 1, custom: 1 }, { sse: 1, opcode: 0x0ff6, e: 1, custom: 1 }, { sse: 1, opcode: 0x660ff6, e: 1, custom: 1 }, // maskmovq (0FF7), maskmovdqu (660FF7) tested manually // Generated tests don't setup EDI as required (yet) { sse: 1, opcode: 0x0ff7, mem_ud: 1, e: 1, custom: 1, skip: 1 }, { sse: 1, opcode: 0x660ff7, mem_ud: 1, e: 1, custom: 1, skip: 1 }, { sse: 1, opcode: 0x0ff8, e: 1, custom: 1 }, { sse: 1, opcode: 0x660ff8, e: 1, custom: 1 }, { sse: 1, opcode: 0x0ff9, e: 1, custom: 1 }, { sse: 1, opcode: 0x660ff9, e: 1, custom: 1 }, { sse: 1, opcode: 0x0ffa, e: 1, custom: 1 }, { sse: 1, opcode: 0x660ffa, e: 1, custom: 1 }, { sse: 1, opcode: 0x0ffb, e: 1, custom: 1 }, { sse: 1, opcode: 0x660ffb, e: 1, custom: 1 }, { sse: 1, opcode: 0x0ffc, e: 1, custom: 1 }, { sse: 1, opcode: 0x660ffc, e: 1, custom: 1 }, { sse: 1, opcode: 0x0ffd, e: 1, custom: 1 }, { sse: 1, opcode: 0x660ffd, e: 1, custom: 1 }, { sse: 1, opcode: 0x0ffe, e: 1, custom: 1 }, { sse: 1, opcode: 0x660ffe, e: 1, custom: 1 }, { opcode: 0x0fff, block_boundary: 1 }, // ud ] for (let i = 0; i < 8; i++) { encodings.push.apply(encodings, [ { opcode: 0x00 | (i << 3), custom: 1, e: 1 }, { opcode: 0x01 | (i << 3), custom: 1, os: 1, e: 1 }, { opcode: 0x02 | (i << 3), custom: 1, e: 1 }, { opcode: 0x03 | (i << 3), custom: 1, os: 1, e: 1 }, { opcode: 0x04 | (i << 3), custom: 1, imm8: 1 }, { opcode: 0x05 | (i << 3), custom: 1, os: 1, imm1632: 1 }, { opcode: 0x40 | i, os: 1, custom: 1 }, { opcode: 0x48 | i, os: 1, custom: 1 }, { opcode: 0x50 | i, custom: 1, os: 1 }, { opcode: 0x58 | i, custom: 1, os: 1 }, { opcode: 0x70 | i, block_boundary: 1, no_block_boundary_in_interpreted: 1, jump_offset_imm: 1, conditional_jump: 1, os: 1, imm8s: 1, custom: 1, skip: 1, }, { opcode: 0x78 | i, block_boundary: 1, no_block_boundary_in_interpreted: 1, jump_offset_imm: 1, conditional_jump: 1, os: 1, imm8s: 1, custom: 1, skip: 1, }, { opcode: 0x80, e: 1, fixed_g: i, imm8: 1, custom: 1 }, { opcode: 0x81, os: 1, e: 1, fixed_g: i, imm1632: 1, custom: 1 }, { opcode: 0x82, e: 1, fixed_g: i, imm8: 1, custom: 1 }, { opcode: 0x83, os: 1, e: 1, fixed_g: i, imm8s: 1, custom: 1 }, { opcode: 0xb0 | i, custom: 1, imm8: 1 }, { opcode: 0xb8 | i, custom: 1, os: 1, imm1632: 1 }, // note: overflow flag only undefined if shift is > 1 // note: the adjust flag is undefined for shifts > 0 and unaffected by rotates { opcode: 0xc0, e: 1, fixed_g: i, imm8: 1, mask_flags: of | af, custom: 1, }, { opcode: 0xc1, os: 1, e: 1, fixed_g: i, imm8: 1, mask_flags: of | af, custom: 1, }, { opcode: 0xd0, e: 1, fixed_g: i, mask_flags: af, custom: 1 }, { opcode: 0xd1, os: 1, e: 1, fixed_g: i, mask_flags: af, custom: 1 }, { opcode: 0xd2, e: 1, fixed_g: i, mask_flags: of | af, custom: 1 }, { opcode: 0xd3, os: 1, e: 1, fixed_g: i, mask_flags: of | af, custom: 1, }, { opcode: 0x0f40 | i, e: 1, os: 1, custom: 1 }, { opcode: 0x0f48 | i, e: 1, os: 1, custom: 1 }, { opcode: 0x0f80 | i, block_boundary: 1, no_block_boundary_in_interpreted: 1, jump_offset_imm: 1, conditional_jump: 1, imm1632: 1, os: 1, custom: 1, skip: 1, }, { opcode: 0x0f88 | i, block_boundary: 1, no_block_boundary_in_interpreted: 1, jump_offset_imm: 1, conditional_jump: 1, imm1632: 1, os: 1, custom: 1, skip: 1, }, { opcode: 0x0f90 | i, e: 1, custom: 1 }, { opcode: 0x0f98 | i, e: 1, custom: 1 }, ]) } encodings.sort((e1: X86Encoding, e2: X86Encoding): number => { const o1 = (e1.opcode & 0xff00) === 0x0f00 ? e1.opcode & 0xffff : e1.opcode & 0xff const o2 = (e2.opcode & 0xff00) === 0x0f00 ? e2.opcode & 0xffff : e2.opcode & 0xff return o1 - o2 || (e1.fixed_g ?? 0) - (e2.fixed_g ?? 0) }) const result: readonly Readonly[] = Object.freeze( encodings.map((entry) => Object.freeze(entry)), ) export default result