; Advanced x86 Encoder. define x86 x86 define x87 x87 define MMX MMX define SSE SSE define AVX AVX define AVX_512 AVX_512 define MPX MPX include 'xcalm.inc' repeat 3 calminstruction c#% line& local buffer, collection match , line jyes commit take collection, line exit commit: take buffer, collection jyes commit out: take line, buffer jno done assemble line jump out done: end calminstruction end repeat macro ? line& local proxy define proxy line match name: associations, proxy c1 calminstruction x86.use.name? c2 calminstruction x86.require.name? c3 calminstruction x86.requireexact.name? iterate association, associations define proxy association match item operator value, proxy if ~ defined x86.item restore x86.item x86.item = 0 define x86.settings item end if x86.name.item := value match ==, operator c1 compute x86.item, value c2 check x86.item >= value c2 jno unsatisfied c3 check x86.item = value c3 jno unsatisfied else match |, operator c1 compute x86.item, x86.item or 1 shl (value) c2 check x86.item and 1 shl (value) c2 jno unsatisfied c3 check x86.item and 1 shl (value) c3 jno unsatisfied else match +, operator c1 compute x86.item, x86.item or (value) c2 check x86.item and (value) = value c2 jno unsatisfied c3 check x86.item and (value) = value c3 jno unsatisfied else err 'unknown syntax (',`association,')' end match else err 'incomplete expression (',`association,')' end match end iterate c1 end calminstruction c2 exit unsatisfied: err string `name + ' or higher required' shl (lengthof `name * 8) end calminstruction c3 exit unsatisfied: err string `name + ' required' shl (lengthof `name * 8) end calminstruction else c1 macro x86.settings.store c2 macro x86.settings.restore irpv item, x86.settings c1 x86.item =: x86.item c2 restore x86.item end irpv c1 end macro c1 c2 end macro c2 line end match end macro 16: mode = 16 32: mode = 32 64: mode = 64 bits16: mode = 16 bits32: mode = 32 bits64: mode = 64 8086: cpu = 0 80186: cpu = 1 80286: cpu = 2 80386: cpu = 3 80486: cpu = 4 P5: cpu = 5 P6: cpu = 6 P68: cpu = 7 x64: cpu = 8 8087: fpu = 1 80187: fpu = 2 80287: fpu = 3 80387: fpu = 4 MMX: simd = 5 SSE: simd = 10 SSE2: simd = 20 SSE3: simd = 30 SSSE3: simd = 31 SSE4.1: simd = 41 SSE4.2: simd = 42 AVX: simd = 50 AVX2: simd = 51 AVX512F: simd = 60 PCLMULQDQ: ext | 1 MONITOR: ext | 3 VMX: ext | 5 SMX: ext | 6 FMA: ext | 12 CMPXCHG16B: ext | 13 MOVBE: ext | 22 POPCNT: ext | 23 AESNI: ext | 25 XSAVE: ext | 26 F16C: ext | 29 RDRAND: ext | 30 FSGSBASE: ext | 32 + 0 BMI1: ext | 32 + 3 HLE: ext | 32 + 4 BMI2: ext | 32 + 8 RTM: ext | 32 + 11 MPX: ext | 32 + 14 AVX512DQ: ext | 32 + 17 RDSEED: ext | 32 + 18 ADX: ext | 32 + 19 AVX512_IFMA: ext | 32 + 21 AVX512PF: ext | 32 + 26 AVX512ER: ext | 32 + 27 AVX512CD: ext | 32 + 28 AVX512BW: ext | 32 + 30 AVX512VL: ext | 32 + 31 AVX512_VBMI: ext | 64 + 1 AVX512_VBMI2: ext | 64 + 6 CET_SS: ext | 64 + 7 GFNI: ext | 64 + 8 VAES: ext | 64 + 9 VPCLMULQDQ: ext | 64 + 10 AVX512_VNNI: ext | 64 + 11 AVX512_BITALG: ext | 64 + 12 AVX512_VPOPCNTDQ: ext | 64 + 14 MOVDIRI: ext | 64 + 27 MOVDIR64B: ext | 64 + 28 AVX512_4VNNIW: ext | 96 + 2 CET_IBT: ext | 96 + 20 3DNow: ext | 128 + 31 ; Some CPU presets: i8086: cpu = 0, fpu = 0, simd = 0, ext = 0 i186: cpu = 1, fpu = 0, simd = 0, ext = 0 i286: cpu = 2, fpu = 0, simd = 0, ext = 0 i386: cpu = 3, fpu = 0, simd = 0, ext = 0 i486: cpu = 4, fpu = 0, simd = 0, ext = 0 Pentium: cpu = 5, fpu = 5, simd = 0, ext = 0 PentiumPro: cpu = 6, fpu = 5, simd = 0, ext = 0 PentiumMMX: cpu = 5, fpu = 5, simd = 5, ext = 0 Pentium2: cpu = 6, fpu = 5, simd = 5, ext = 0 Pentium3: cpu = 6, fpu = 5, simd = 10, ext = 0 Pentium4: cpu = 7, fpu = 5, simd = 30, ext = 0 AMD64: cpu = 8, fpu = 5, simd = 20, ext = x86.3DNow.ext SSE4: simd = x86.SSE4.2.simd, ext + x86.POPCNT.ext AVX512: simd = x86.AVX512F.simd, ext + x86.AVX512VL.ext + x86.AVX512BW.ext + x86.AVX512DQ.ext + x86.AVX512CD.ext + x86.AVX512_IFMA.ext + x86.AVX512_VBMI.ext everything: cpu = 8, fpu = 5, simd = 60, ext = -1 ; Following settings are just hints of a preference, instruction encoder may listen to them ; when it is possible without altering the meaning of the instruction. immauto: immsize = 0 imm8: immsize = 1 imm16: immsize = 2 imm32: immsize = 4 imm64: immsize = 8 ; Following settings select the position of r/m operand for few instructions that ; can be encoded either way, and are ignored otherwise. rmauto: rmposition = 0 rm1: rmposition = 1 rmdst: rmposition = 1 rm2: rmposition = 2 rmsrc: rmposition = 2 ; Enable or disable automatic RIP-relative addressing in long mode. ripauto: userip = 0 rip: userip = 1 norip: userip = -1 absolute: userip = -1 purge ?, c1, c2, c3 ; To select a group of settings: ; use i386 ; To require a group of settings (with optional "+"): ; require i386+ ; To check a single setting: ; if x86.simd >= x86.PentiumMMX.simd macro require? name* match min+, name x86.require.min else x86.requireexact.name end match end macro macro use? names*& iterate name, names x86.use.name end iterate end macro calminstruction ?? &line& local settings, instruction match {settings} instruction, line jyes annotated assemble line exit annotated: asm x86.settings.store arrange settings, =use settings assemble settings assemble instruction asm x86.settings.restore end calminstruction element x86.reg element x86.r8 : x86.reg + 1 element x86.r16 : x86.reg + 2 element x86.r32 : x86.reg + 4 element x86.r64 : x86.reg + 8 element al? : x86.r8 + 0 element cl? : x86.r8 + 1 element dl? : x86.r8 + 2 element bl? : x86.r8 + 3 element spl? : x86.r8 + 4 element bpl? : x86.r8 + 5 element sil? : x86.r8 + 6 element dil? : x86.r8 + 7 element ah? : x86.r8 - 4 element ch? : x86.r8 - 5 element dh? : x86.r8 - 6 element bh? : x86.r8 - 7 repeat 8, i:8 element r#i#b? : x86.r8 + i element r#i#l? : x86.r8 + i end repeat element ax? : x86.r16 + 0 element cx? : x86.r16 + 1 element dx? : x86.r16 + 2 element bx? : x86.r16 + 3 element sp? : x86.r16 + 4 element bp? : x86.r16 + 5 element si? : x86.r16 + 6 element di? : x86.r16 + 7 repeat 8, i:8 element r#i#w? : x86.r16 + i end repeat element eax? : x86.r32 + 0 element ecx? : x86.r32 + 1 element edx? : x86.r32 + 2 element ebx? : x86.r32 + 3 element esp? : x86.r32 + 4 element ebp? : x86.r32 + 5 element esi? : x86.r32 + 6 element edi? : x86.r32 + 7 repeat 8, i:8 element r#i#d? : x86.r32 + i end repeat element rax? : x86.r64 + 0 element rcx? : x86.r64 + 1 element rdx? : x86.r64 + 2 element rbx? : x86.r64 + 3 element rsp? : x86.r64 + 4 element rbp? : x86.r64 + 5 element rsi? : x86.r64 + 6 element rdi? : x86.r64 + 7 repeat 8, i:8 element r#i? : x86.r64 + i end repeat element x86.ip element eip? : x86.ip + 4 element rip? : x86.ip + 8 element x86.sreg element es? : x86.sreg + 0 element cs? : x86.sreg + 1 element ss? : x86.sreg + 2 element ds? : x86.sreg + 3 element fs? : x86.sreg + 4 element gs? : x86.sreg + 5 element x86.creg element x86.crx : x86.creg + 0 element x86.drx : x86.creg + 1 repeat 16, i:0 element cr#i? : x86.crx + i element dr#i? : x86.drx + i end repeat define x86.byte? :1 define x86.word? :2 define x86.dword? :4 define x86.pword? :6 define x86.fword? :6 define x86.qword? :8 define x86.tword? :10 define x86.tbyte? :10 define x86.dqword? :16 define x86.xword? :16 define x86.qqword? :32 define x86.yword? :32 define x86.dqqword? :64 define x86.zword? :64 x86.REX_REQUIRED = 100h x86.REX_FORBIDDEN = 200h macro use16? use bits16 end macro macro use32? use bits32 end macro macro use64? use bits64 end macro macro useavx256? use avx2 end macro macro useavx512? use avx512f end macro use16 define @dest @dest define @src @src define @src2 @src2 define @aux @aux iterate context, @dest,@src,@src2,@aux namespace context iterate name, size, type, segment_prefix, prefix, opcode_prefix, rex_prefix, \ imm, unresolved, displacement, displacement_size, auto_relative, \ address, address_registers, segment, offset, jump_type, \ mode, mod, rm, \ scale, index, base define name end iterate calminstruction x86.parse_operand#context operand local i, pre, suf, sym compute segment_prefix, 0 compute prefix, 0 compute opcode_prefix, 0 compute rex_prefix, 0 compute size, 0 compute displacement_size, 0 transform operand match pre suf, operand jno no_size_prefix transform pre, x86 jno no_size_prefix match :size, pre jno no_size_prefix arrange operand, suf no_size_prefix: match [address], operand jyes memory_operand match =ptr? address, operand jyes memory_operand match segment:offset, operand jyes far_operand immediate_operand: compute type, 'imm' compute imm, +operand compute unresolved, 0 check defined operand jyes operand_resolved compute unresolved, 1 operand_resolved: check imm eq 1 elementof imm jno operand_ready check 1 metadataof (1 metadataof imm) relativeto x86.reg jyes register_operand check 1 metadataof imm relativeto x86.sreg jyes segment_register_operand operand_ready: exit register_operand: compute type, 'reg' compute mode, x86.mode compute mod, 11b compute rm, 1 metadataof imm - 1 elementof (1 metadataof imm) check size & size <> 1 metadataof (1 metadataof imm) - x86.reg jyes operand_sizes_do_not_match compute size, 1 metadataof (1 metadataof imm) - x86.reg check rm < 0 jyes register_precluding_rex check size = 1 & rm >= 4 & rm < 8 jyes register_requiring_rex exit register_precluding_rex: compute rm, x86.REX_FORBIDDEN - rm exit register_requiring_rex: compute rm, x86.REX_REQUIRED + rm exit segment_register_operand: compute type, 'sreg' compute mode, x86.mode compute mod, 11b compute rm, 1 metadataof imm - x86.sreg check size & size <> 2 & size <> 4 jyes invalid_operand_size check rm >= 4 jno operand_ready call x86.require.80386 exit memory_operand: compute type, 'mem' match segment:address, address jno segment_prefix_ok check segment eq 1 elementof segment & 1 metadataof segment relativeto x86.sreg jno invalid_operand compute segment, 1 metadataof segment - x86.sreg check segment >= 4 jyes segment_prefix_386 compute segment_prefix, 26h + segment shl 3 jump segment_prefix_ok segment_prefix_386: call x86.require.80386 compute segment_prefix, 64h + segment-4 segment_prefix_ok: compute mode, 0 match pre suf, address jno no_address_size_prefix transform pre, x86 jno no_address_size_prefix match :pre, pre jno no_address_size_prefix arrange address, suf check pre = 2 | pre = 4 | pre = 8 jno invalid_address_size compute mode, pre shl 3 no_address_size_prefix: compute scale, 0 compute index, 0 compute base, 0 check size jyes size_override compute size, sizeof address size_override: compute address, address compute address_registers, 0 compute i, 1 extract_registers: check i > elementsof address jyes registers_extracted check i metadataof address relativeto x86.r16 | i metadataof address relativeto x86.r32 | i metadataof address relativeto x86.r64 | i metadataof address relativeto x86.ip jno next_term compute address_registers, address_registers + i elementof address * i scaleof address next_term: compute i, i+1 jump extract_registers registers_extracted: compute displacement, address - address_registers compute auto_relative, 0 check address_registers eq 0 jyes direct_address check mode & mode <> 0 scaleof (1 metadataof (1 metadataof address_registers)) shl 3 & ~ 1 metadataof address_registers relativeto x86.ip jyes invalid_address check 1 metadataof address_registers relativeto x86.r64 | 1 metadataof address_registers relativeto x86.r32 jyes address_32bit_64bit check 1 metadataof address_registers relativeto x86.r16 jyes address_16bit check address_registers eq rip | address_registers eq eip jyes rip_relative_address jump invalid_address rip_relative_address: compute mode, 0 scaleof (1 metadataof address_registers) shl 3 compute mod, 0 compute rm, 5 compute displacement_size, 4 exit direct_address: compute mod, 0 check x86.mode = 64 jyes direct_address_in_long_mode check mode = 0 jno mode_ok compute mode, x86.mode check mode = 16 & displacement relativeto 0 & displacement >= 10000h jno mode_ok compute mode, 32 mode_ok: check mode = 16 jyes direct_address_16bit direct_address_32bit: compute rm, 5 compute displacement_size, 4 exit direct_address_16bit: compute rm, 6 compute displacement_size, 2 exit direct_address_in_long_mode: compute displacement_size, 4 check (x86.userip = 0 & mode = 0 & segment_prefix < 64h) | x86.userip = 1 jyes auto_relative_address check mode = 16 jyes invalid_address_size compute rm, 4 compute base, 5 compute index, 4 compute scale, 1 check mode = 32 jno direct_address_displacement_ready check ~ displacement relativeto 0 | displacement >= 100000000h | displacement < -100000000h jyes address_out_of_range compute displacement, displacement and 0FFFFFFFFh direct_address_displacement_ready: check displacement relativeto 0 & displacement > 7FFFFFFFh & displacement < 100000000h jyes direct_address_switch_to_32bit compute mode, 64 compute displacement_size, 8 exit direct_address_switch_to_32bit: compute mode, 32 exit auto_relative_address: compute mode, 64 compute rm, 5 compute auto_relative, 1 exit address_16bit: compute mode, 16 check address_registers relativeto bx+si jyes rm_0 check address_registers relativeto bx+di jyes rm_1 check address_registers relativeto bp+si jyes rm_2 check address_registers relativeto bp+di jyes rm_3 check address_registers relativeto si jyes rm_4 check address_registers relativeto di jyes rm_5 check address_registers relativeto bp jyes rm_6 check address_registers relativeto bx jyes rm_7 jump invalid_address rm_0: compute rm, 0 jump rm_ok rm_1: compute rm, 1 jump rm_ok rm_2: compute rm, 2 jump rm_ok rm_3: compute rm, 3 jump rm_ok rm_4: compute rm, 4 jump rm_ok rm_5: compute rm, 5 jump rm_ok rm_6: compute rm, 6 jump rm_ok rm_7: compute rm, 7 rm_ok: check displacement relativeto 0 jno displacement_16bit check displacement = 0 & rm <> 6 jyes displacement_empty check displacement<80h & displacement>=-80h jyes displacement_8bit check displacement-10000h>=-80h & displacement<10000h jyes displacement_8bit_wrap_16bit displacement_16bit: compute displacement_size, 2 compute mod, 2 exit displacement_empty: compute displacement_size, 0 compute mod, 0 exit displacement_8bit_wrap_16bit: compute displacement, displacement-10000h displacement_8bit: compute displacement_size, 1 compute mod, 1 exit address_32bit_64bit: local address_registers_type check 1 metadataof address_registers relativeto x86.r64 jyes address_64bit address_32bit: compute mode, 32 compute address_registers_type, x86.r32 jump check_address_registers address_64bit: compute mode, 64 compute address_registers_type, x86.r64 check_address_registers: check 2 scaleof address_registers = 0 jyes one_register check 3 scaleof address_registers = 0 & 2 metadataof address_registers relativeto address_registers_type jyes two_registers jump invalid_address one_register: compute scale, 1 scaleof address_registers compute base, 1 metadataof address_registers - address_registers_type check scale = 1 jyes one_register_unscaled check base <> 4 & (scale = 4 | scale = 8) jyes one_register_scaled check base <> 4 & (scale = 2 | scale = 3 | scale = 5 | scale = 9) jyes one_register_split jump invalid_address one_register_unscaled: check base and 111b = 4 jyes one_register_unscaled_in_sib compute rm, base jump setup_displacement one_register_unscaled_in_sib: compute rm, 4 compute index, 4 jump setup_displacement one_register_scaled: compute rm, 4 compute index, base compute base, 5 jump index_only one_register_split: compute rm, 4 compute index, base compute scale, scale - 1 jump setup_displacement two_registers: compute rm,4 check 1 scaleof address_registers = 1 jyes base_first check 2 scaleof address_registers = 1 jyes base_second jump invalid_address base_first: compute base, 1 metadataof address_registers - address_registers_type compute index, 2 metadataof address_registers - address_registers_type compute scale, 2 scaleof address_registers jump process_sib base_second: compute base, 2 metadataof address_registers - address_registers_type compute index, 1 metadataof address_registers - address_registers_type compute scale, 1 scaleof address_registers process_sib: check index = 4 jyes forbidden_index check (x86.mode <> 64 & segment_prefix = 36h) & index = 5 & scale = 1 jyes switch_to_index check (x86.mode = 64 | segment_prefix = 3Eh) & base = 5 & scale = 1 jyes switch_to_base check scale and (scale-1) | scale > 8 jyes invalid_address jump setup_displacement forbidden_index: check scale = 1 jno invalid_address compute index, base compute base, 4 jump setup_displacement switch_to_index: compute index, base compute base,5 jump setup_displacement switch_to_base: compute base, index compute index, 5 jump setup_displacement setup_displacement: check displacement relativeto 0 jno displacement_32bit check displacement = 0 & rm and 111b <> 5 & (rm <> 4 | base and 111b <> 5) jyes displacement_empty check displacement < 80h & displacement >= -80h jyes displacement_8bit check displacement - 1 shl mode >= -80h & displacement < 1 shl mode jyes displacement_8bit_wrap check (x86.mode = 64 | segment_prefix = 3Eh) & base = 5 & index = 5 & scale = 1 jno displacement_32bit compute scale, 2 jump index_only displacement_32bit: compute displacement_size, 4 compute mod, 2 exit displacement_8bit_wrap: compute displacement, displacement - 1 shl mode jump displacement_8bit index_only: compute displacement_size, 4 compute mod, 0 exit far_operand: compute type, 'far' check size & size <> 4 & size <> 6 & size <> 10 jyes operand_sizes_do_not_match exit invalid_operand: err 'invalid operand' exit invalid_operand_size: err 'invalid operand size' exit operand_sizes_do_not_match: err 'operand sizes do not match' exit invalid_address: err 'invalid address' exit invalid_address_size: err 'invalid address size' exit address_out_of_range: err 'address out of range' exit end calminstruction calminstruction x86.parse_jump_operand#context operand match =far? operand, operand jyes far_jump match =near? operand, operand jyes near_jump match =short? operand, operand jyes short_jump compute jump_type, '' jump parse_operand far_jump: compute jump_type, 'far' jump parse_operand near_jump: compute jump_type, 'near' jump parse_operand short_jump: compute jump_type, 'short' parse_operand: call x86.parse_operand#context, operand check type = 'imm' jno done check size = 0 jno verify_target_address compute size, x86.mode shr 3 verify_target_address: check imm relativeto 0 jno done check imm < 0 jyes negative check imm >= 1 shl (size*8) jno done out_of_range: err 'value out of range' exit negative: check imm < - 1 shl (size*8-1) jyes out_of_range compute imm, imm and (1 shl (size*8) - 1) done: end calminstruction calminstruction x86.select_operand_prefix#context size* check size = 8 & x86.cpu < x86.x64.cpu jyes required64 check size = 4 & x86.cpu < x86.80386.cpu jyes required32 check (size = 2 & x86.mode <> 16) | (size = 4 & x86.mode = 16) jyes prefix_66h check size = 8 jyes prefix_48h check size <> 0 & size <> 2 & size <> 4 jyes invalid_size exit prefix_66h: compute prefix, 66h exit prefix_48h: compute prefix, 48h exit invalid_size: err 'invalid operand size' exit required64: err 'instruction requires 64-bit processor' exit required32: err 'instruction requires 32-bit processor' exit end calminstruction calminstruction x86.store_instruction#context opcode*,reg*,imm_size:0,immediate check segment_prefix jno segment_prefix_ok check mode = 64 jyes segment_in_long_mode check mode = 16 & ( rm = 2 | rm = 3 | ( mod > 0 & rm = 6 ) ) jyes ss_segment_default check mode = 32 & ( ( mod > 0 & rm = 5 ) | ( rm = 4 & base = 4 ) | ( mod > 0 & rm = 4 & base = 5 ) ) jyes ss_segment_default ds_segment_default: check segment_prefix = 3Eh jyes segment_prefix_ok jump store_segment_prefix ss_segment_default: check segment_prefix = 36h jyes segment_prefix_ok jump store_segment_prefix segment_in_long_mode: check segment_prefix < 64h jyes segment_prefix_ok store_segment_prefix: emit 1, segment_prefix segment_prefix_ok: check mod <> 11b & mode <> x86.mode jno addressing_prefix_ok check mode = 64 | (mode = 16 & x86.mode = 64) jno store_addressing_prefix err 'illegal addressing mode' store_addressing_prefix: emit 1, 67h addressing_prefix_ok: check (reg or rm) and x86.REX_REQUIRED jno rex_1 compute rex_prefix, rex_prefix or 40h rex_1: check rm and 1000b | (mod <> 11b & mode > 16 & rm = 4 & base and 1000b) jno rex_2 compute rex_prefix, rex_prefix or 41h rex_2: check mod <> 11b & mode > 16 & rm = 4 & index and 1000b jno rex_4 compute rex_prefix, rex_prefix or 42h rex_4: check reg and 1000b jno rex_8 compute rex_prefix, rex_prefix or 44h rex_8: check prefix = 48h jno operand_prefix compute rex_prefix, rex_prefix or 48h jump operand_prefix_ok operand_prefix: check prefix jno operand_prefix_ok emit 1, prefix operand_prefix_ok: check opcode_prefix jno opcode_prefix_ok emit 1, opcode_prefix opcode_prefix_ok: check rex_prefix jno rex_prefix_ok check x86.mode < 64 jyes instruction_requires_long_mode check reg and x86.REX_FORBIDDEN jno store_rex_prefix err 'disallowed combination of registers' jump store_rex_prefix instruction_requires_long_mode: call x86.require.bits64 store_rex_prefix: emit 1, rex_prefix rex_prefix_ok: asm db opcode emit 1, mod shl 6 + (reg and 111b) shl 3 + rm and 111b check mod <> 11b & rm = 4 & mode <> 16 jno sib_ok emit 1, (bsf scale) shl 6 + (index and 111b) shl 3 + base and 111b sib_ok: check displacement_size = 1 jyes displacement_8bit check displacement_size = 2 jyes displacement_16bit check displacement_size = 4 | displacement_size = 8 jno displacement_ok compute displacement, displacement check auto_relative jno auto_relative_ok check imm_size < 8 jyes adjust_auto_relative_displacement compute displacement, displacement - ($ + 4 + 4) jump auto_relative_ok adjust_auto_relative_displacement: compute displacement, displacement - ($ + 4 + imm_size) auto_relative_ok: check mode = 64 & displacement relativeto 0 jno displacement_ready check displacement - 1 shl 64 >= -80000000h & displacement < 1 shl 64 jyes adjust_displacement_wrap check displacement >= -80000000h & displacement < 80000000h jyes displacement_ready err 'address value out of signed range' adjust_displacement_wrap: compute displacement, displacement - 1 shl 64 displacement_ready: call dword, displacement jump displacement_ok displacement_16bit: call word, displacement jump displacement_ok displacement_8bit: emit 1, displacement displacement_ok: check imm_size = 1 jyes immediate_8bit check imm_size = 2 jyes immediate_16bit check imm_size = 4 jyes immediate_32bit check imm_size = 8 jno immediate_ok call x86.simm32, immediate jump immediate_ok immediate_32bit: compute imm, +immediate call dword, imm jump immediate_ok immediate_16bit: compute imm, +immediate call word, imm jump immediate_ok immediate_8bit: compute imm, +immediate emit 1, imm immediate_ok: end calminstruction end namespace end iterate calminstruction x86.store_operand_prefix size*, reg:0 check size = 8 & x86.cpu < x86.x64.cpu jyes required64 check size = 4 & x86.cpu < x86.80386.cpu jyes required32 local rex_prefix compute rex_prefix, 0 check (size = 2 & x86.mode <> 16) | (size = 4 & x86.mode = 16) jyes prefix_66h check size = 8 jyes rex_8 check size <> 0 & size <> 2 & size <> 4 jno check_register err 'invalid operand size' jump check_register required64: err 'instruction requires 64-bit processor' exit required32: err 'instruction requires 32-bit processor' exit prefix_66h: emit 1, 66h jump check_register rex_8: compute rex_prefix, 48h check_register: check reg and 1000b jyes rex_1 check reg and x86.REX_REQUIRED jno rex_ready compute rex_prefix, rex_prefix or 40h jump rex_ready rex_1: compute rex_prefix, rex_prefix or 41h rex_ready: check rex_prefix jno rex_prefix_ok check x86.mode < 64 jyes instruction_requires_long_mode check reg and x86.REX_FORBIDDEN jno store_rex_prefix err 'disallowed combination of registers' jump store_rex_prefix instruction_requires_long_mode: call x86.require.bits64 store_rex_prefix: emit 1, rex_prefix rex_prefix_ok: end calminstruction calminstruction x86.simm32 immediate* compute immediate, +immediate check immediate eqtype 0.0 jno check_value asm virtual at 0 asm emit 8: immediate asm load immediate:8 from 0 asm end virtual compute immediate, +immediate check_value: check immediate relativeto 0 jyes check_range call dword, immediate exit check_range: check immediate - 1 shl 64 >= -80000000h & immediate < 1 shl 64 jyes wrap check immediate >= 80000000h | immediate < -80000000h jyes out_of_range emit 4, immediate exit wrap: emit 4, immediate - 1 shl 64 exit out_of_range: err 'immediate value out of signed range' end calminstruction iterate , add,0, or,8, adc,10h, sbb,18h, and,20h, sub,28h, xor,30h, cmp,38h calminstruction instr? dest*,src* call x86.parse_operand@dest, dest call x86.parse_operand@src, src local opcode, rm, size compute opcode, basecode check @dest.size = 0 & @src.size = 0 jyes operand_size_not_specified check @dest.size <> 0 & @src.size <> 0 & @dest.size <> @src.size jyes operand_sizes_do_not_match compute size, @dest.size or @src.size main: check @src.type = 'reg' & ( (@dest.type = 'reg' & x86.rmposition <> x86.rmsrc.rmposition) | @dest.type = 'mem' ) jyes reg_rm check (@src.type = 'mem' | @src.type = 'reg' ) & @dest.type = 'reg' jyes rm_reg check @src.type = 'imm' & ( @dest.type = 'reg' | @dest.type = 'mem' ) jyes rm_imm err 'invalid combination of operands' exit operand_size_not_specified: err 'operand size not specified' compute size, 0 jump main operand_sizes_do_not_match: err 'operand sizes do not match' compute size, 0 jump main reg_rm: check size > 1 jno reg_rm_store call x86.select_operand_prefix@dest, size compute opcode, opcode + 1 reg_rm_store: call x86.store_instruction@dest, opcode,@src.rm exit rm_reg: compute opcode, opcode + 2 check size > 1 jno rm_reg_store call x86.select_operand_prefix@src, size compute opcode, opcode + 1 rm_reg_store: call x86.store_instruction@src, opcode,@dest.rm exit rm_imm: check size > 1 jyes rm_imm_word check @dest.type = 'reg' & @dest.rm = 0 jyes al_imm compute opcode, opcode shr 3 xcall x86.store_instruction@dest, (80h),opcode,byte,@src.imm exit al_imm: emit 1, opcode+4 emit 1, @src.imm exit rm_imm_word: call x86.select_operand_prefix@dest, size check @src.imm eqtype 0.0 jno rm_imm_optimize asm virtual at 0 asm emit size: @src.imm asm load @src.imm:size from 0 asm end virtual compute @src.imm, +@src.imm rm_imm_optimize: check x86.immsize < 2 & @src.imm relativeto 0 & @src.imm < 80h & @src.imm >= -80h jyes rm_simm check x86.immsize < 2 & @src.imm relativeto 0 & @src.imm - 1 shl (size shl 3) >= -80h & @src.imm < 1 shl (size shl 3) jyes rm_simm_wrap check @dest.type = 'reg' & @dest.rm = 0 jyes ax_imm compute rm, opcode shr 3 xcall x86.store_instruction@dest, (81h),rm,size,@src.imm exit ax_imm: check @dest.prefix jno ax_imm_prefix_ok emit 1, @dest.prefix ax_imm_prefix_ok: emit 1, opcode+5 check size = 4 jyes imm32 check size = 8 jyes simm32 asm emit size: @src.imm exit imm32: call dword, @src.imm exit simm32: call x86.simm32, @src.imm exit rm_simm_wrap: compute @src.imm, @src.imm - 1 shl (size shl 3) rm_simm: compute rm, opcode shr 3 xcall x86.store_instruction@dest, (83h),rm,byte,@src.imm end calminstruction end iterate iterate , not,2, neg,3, mul,4, div,6, idiv,7 calminstruction instr? src* call x86.parse_operand@src, src check @src.size = 0 jyes operand_size_not_specified main: check @src.type = 'mem' | @src.type = 'reg' jno invalid_operand check @src.size > 1 jyes rm_word xcall x86.store_instruction@src, (0F6h),(postbyte) exit rm_word: call x86.select_operand_prefix@src, @src.size xcall x86.store_instruction@src, (0F7h),(postbyte) exit operand_size_not_specified: err 'operand size not specified' jump main invalid_operand: err 'invalid operand' exit end calminstruction end iterate calminstruction mov? dest*,src* call x86.parse_operand@dest, dest call x86.parse_operand@src, src local ext, rm, size check @dest.size = 0 & @src.size = 0 & @dest.type <> 'sreg' jyes operand_size_not_specified check @dest.size <> 0 & @src.size <> 0 & @dest.size <> @src.size jyes operand_sizes_do_not_match compute size, @dest.size or @src.size main: check @src.type = 'reg' & ( (@dest.type = 'reg' & x86.rmposition <> x86.rmsrc.rmposition) | @dest.type = 'mem' ) jyes mov_rm_reg check (@src.type = 'mem' | @src.type = 'reg') & @dest.type = 'reg' jyes mov_reg_mem check @src.type = 'imm' & ( @dest.type = 'reg' | @dest.type = 'mem' ) jyes mov_rm_imm check @src.type = 'reg' & @dest.type = 'imm' jyes mov_creg_reg check @src.type = 'sreg' & ( @dest.type = 'reg' | @dest.type = 'mem' ) jyes mov_rm_sreg check @dest.type = 'sreg' & @dest.rm <> 1 & ( @src.type = 'reg' | @src.type = 'mem' ) jyes mov_sreg_rm invalid_combination_of_operands: err 'invalid combination of operands' exit operand_size_not_specified: err 'operand size not specified' compute size, 0 jump main operand_sizes_do_not_match: err 'operand sizes do not match' compute size, 0 jump main mov_rm_reg: check @src.type = 'reg' & @dest.type = 'mem' & @src.rm = 0 & @dest.address_registers eq 0 & \ ~ @dest.auto_relative & ( @dest.displacement_size <> 8 | ~ @dest.displacement relativeto 0 | @dest.displacement and 0FFFFFFFF80000000h <> 0FFFFFFFF80000000h) jyes mov_dirmem_ax check size > 1 jno mov_reg_rm_8bit call x86.select_operand_prefix@dest, size xcall x86.store_instruction@dest, (89h),@src.rm exit mov_reg_rm_8bit: xcall x86.store_instruction@dest, (88h),@src.rm exit mov_reg_mem: check @src.type = 'mem' & @dest.type = 'reg' & @dest.rm = 0 & @src.address_registers eq 0 & \ ~ @src.auto_relative & ( @src.displacement_size <> 8 | ~ @src.displacement relativeto 0 | @src.displacement and 0FFFFFFFF80000000h <> 0FFFFFFFF80000000h) jyes mov_ax_dirmem check size > 1 jno mov_mem_reg_8bit call x86.select_operand_prefix@src, size xcall x86.store_instruction@src, (8Bh),@dest.rm exit mov_mem_reg_8bit: xcall x86.store_instruction@src, (8Ah),@dest.rm exit mov_dirmem_ax: check x86.mode = 64 jyes mov_dirmem_ax_longmode check @dest.segment_prefix = 0 | @dest.segment_prefix = 3Eh jyes dest_seg_ok emit 1, @dest.segment_prefix dest_seg_ok: check @dest.mode = x86.mode jyes dest_addr_size_ok emit 1, 67h dest_addr_size_ok: check size > 1 jno mov_dirmem_al call x86.store_operand_prefix, size emit 1, 0A3h jump dest_displacement mov_dirmem_al: emit 1, 0A2h dest_displacement: check @dest.mode = 16 jyes dest_displacement_16bit check @dest.displacement_size = 8 jyes dest_displacement_64bit call dword, @dest.address exit dest_displacement_16bit: call word, @dest.address exit dest_displacement_64bit: call qword, @dest.address exit mov_dirmem_ax_longmode: check @dest.displacement_size = 8 & @dest.displacement relativeto 0 & @dest.displacement >= 0 & @dest.displacement < 100000000h jno dest_displacement_size_ok compute @dest.displacement_size, 4 dest_displacement_size_ok: check @dest.segment_prefix & @dest.segment_prefix >= 64h jno dest_longmode_seg_ok emit 1, @dest.segment_prefix dest_longmode_seg_ok: check @dest.mode = 16 jyes illegal_addressing_mode check @dest.displacement_size = 8 jyes dest_addr_size_ok emit 1, 67h jump dest_addr_size_ok mov_ax_dirmem: check x86.mode = 64 jyes mov_ax_dirmem_longmode check @src.segment_prefix = 0 | @src.segment_prefix = 3Eh jyes src_seg_ok emit 1, @src.segment_prefix src_seg_ok: check @src.mode = x86.mode jyes src_addr_size_ok emit 1, 67h src_addr_size_ok: check size > 1 jno mov_al_dirmem call x86.store_operand_prefix, size emit 1, 0A1h jump src_displacement mov_al_dirmem: emit 1, 0A0h src_displacement: check @src.mode = 16 jyes src_displacement_16bit check @src.displacement_size = 8 jyes src_displacement_64bit call dword, @src.address exit src_displacement_16bit: call word, @src.address exit src_displacement_64bit: call qword, @src.address exit mov_ax_dirmem_longmode: check @src.displacement_size = 8 & @src.displacement relativeto 0 & @src.displacement >= 0 & @src.displacement < 100000000h jno src_displacement_size_ok compute @src.displacement_size, 4 src_displacement_size_ok: check @src.segment_prefix & @src.segment_prefix >= 64h jno src_longmode_seg_ok emit 1, @src.segment_prefix src_longmode_seg_ok: check @src.mode = 16 jyes illegal_addressing_mode check @src.displacement_size = 8 jyes src_addr_size_ok emit 1, 67h jump src_addr_size_ok mov_rm_imm: check @dest.type = 'mem' jyes mov_mem_imm check @dest.type = 'reg' & 1 metadataof (1 metadataof @src.imm) relativeto x86.creg & @src.imm relativeto 1 elementof @src.imm jyes mov_reg_creg mov_reg_imm: check size > 1 jno mov_reg_imm_8bit check @src.imm eqtype 0.0 jno mov_reg_imm_optimize asm virtual at 0 asm emit size: @src.imm asm load @src.imm:size from 0 asm end virtual compute @src.imm, +@src.imm mov_reg_imm_optimize: check size = 8 & @src.imm relativeto 0 & @src.imm < 80000000h & @src.imm >= -80000000h & x86.immsize < 8 jyes mov_reg_simm check size = 8 & @src.imm relativeto 0 & @src.imm - 1 shl 64 < 80000000h & @src.imm - 1 shl 64 >= -80000000h & x86.immsize < 8 jyes mov_reg_simm_wrap call x86.store_operand_prefix, size,@dest.rm emit 1, 0B8h + @dest.rm and 111b check size = 2 jyes src_imm_16bit check size = 4 jyes src_imm_32bit call qword, @src.imm exit src_imm_32bit: call dword, @src.imm exit src_imm_16bit: call word, @src.imm exit mov_reg_imm_8bit: xcall x86.store_operand_prefix, (0),@dest.rm emit 1, 0B0h + @dest.rm and 111b emit 1, @src.imm exit mov_reg_simm_wrap: compute @src.imm, @src.imm - 1 shl 64 mov_reg_simm: call x86.select_operand_prefix@dest, size xcall x86.store_instruction@dest, (0C7h),(0),size,@src.imm exit mov_mem_imm: check size > 1 jno mov_mem_imm_8bit call x86.select_operand_prefix@dest, size xcall x86.store_instruction@dest, (0C7h),(0),size,@src.imm exit mov_mem_imm_8bit: xcall x86.store_instruction@dest, (0C6h),(0),byte,@src.imm exit mov_reg_creg: check (x86.mode <> 64 & @dest.size = 4) | (x86.mode = 64 & @dest.size = 8) jno invalid_operand_size compute ext, 20h + 1 metadataof (1 metadataof @src.imm) - x86.creg compute rm, 1 metadataof @src.imm - 1 elementof (1 metadataof @src.imm) xcall x86.store_instruction@dest, <0Fh,ext>,rm check ext = 4 jyes only386 call x86.require.80386 exit only386: call x86.requireexact.80386 exit mov_creg_reg: check 1 metadataof (1 metadataof @dest.imm) relativeto x86.creg & @dest.imm relativeto 1 elementof @dest.imm jno invalid_combination_of_operands check (x86.mode <> 64 & @src.size = 4) | (x86.mode = 64 & @src.size = 8) jno invalid_operand_size compute ext, 22h + 1 metadataof (1 metadataof @dest.imm) - x86.creg compute rm, 1 metadataof @dest.imm - 1 elementof (1 metadataof @dest.imm) xcall x86.store_instruction@src, <0Fh,ext>,rm check ext = 4 jyes only386 call x86.require.80386 exit mov_rm_sreg: check @dest.type = 'mem' jyes mov_mem_sreg mov_reg_sreg: check size > 1 jno invalid_operand_size call x86.select_operand_prefix@dest, size jump mov_rm_sreg_store mov_mem_sreg: check size and not 2 jyes invalid_operand_size mov_rm_sreg_store: xcall x86.store_instruction@dest, (8Ch),@src.rm exit mov_sreg_rm: check size = 1 jyes invalid_operand_size xcall x86.store_instruction@src, (8Eh),@dest.rm exit invalid_operand_size: err 'invalid operand size' exit illegal_addressing_mode: err 'illegal addressing mode' exit end calminstruction calminstruction test? dest*,src* call x86.parse_operand@dest, dest call x86.parse_operand@src, src local ext, rm, size check @dest.size = 0 & @src.size = 0 jyes operand_size_not_specified check @dest.size <> 0 & @src.size <> 0 & @dest.size <> @src.size jyes operand_sizes_do_not_match compute size, @dest.size or @src.size main: check @src.type = 'reg' & ( (@dest.type = 'reg' & x86.rmposition <> x86.rmsrc.rmposition) | @dest.type = 'mem' ) jyes test_reg_rm check (@src.type = 'mem' | @src.type = 'reg') & @dest.type = 'reg' jyes test_mem_reg check @src.type = 'imm' & ( @dest.type = 'reg' | @dest.type = 'mem' ) jyes test_rm_imm invalid_combination_of_operands: err 'invalid combination of operands' exit operand_size_not_specified: err 'operand size not specified' compute size, 0 jump main operand_sizes_do_not_match: err 'operand sizes do not match' compute size, 0 jump main test_reg_rm: check size > 1 jno test_reg_rm_8bit call x86.select_operand_prefix@dest, size xcall x86.store_instruction@dest, (85h),@src.rm exit test_reg_rm_8bit: xcall x86.store_instruction@dest, (84h),@src.rm exit test_mem_reg: check size > 1 jno test_mem_reg_8bit call x86.select_operand_prefix@src, size xcall x86.store_instruction@src, (85h),@dest.rm exit test_mem_reg_8bit: xcall x86.store_instruction@src, (84h),@dest.rm exit test_rm_imm: check size > 1 jno test_rm_imm_8bit check @dest.type = 'reg' & @dest.rm = 0 jyes test_ax_imm call x86.select_operand_prefix@dest, size xcall x86.store_instruction@dest, (0F7h),(0),size,@src.imm exit test_ax_imm: call x86.store_operand_prefix, size emit 1, 0A9h check size = 2 jyes src_imm_16bit check size = 4 jyes src_imm_32bit call x86.simm32, @src.imm exit src_imm_16bit: call word, @src.imm exit src_imm_32bit: call dword, @src.imm exit test_rm_imm_8bit: check @dest.type = 'reg' & @dest.rm = 0 jyes test_al_imm xcall x86.store_instruction@dest, (0F6h),(0),byte,@src.imm exit test_al_imm: emit 1, 0A8h emit 1, @src.imm exit end calminstruction calminstruction xchg? dest*,src* call x86.parse_operand@dest, dest call x86.parse_operand@src, src local ext, rm, size check @dest.size = 0 & @src.size = 0 jyes operand_size_not_specified check @dest.size <> 0 & @src.size <> 0 & @dest.size <> @src.size jyes operand_sizes_do_not_match compute size, @dest.size or @src.size main: check @src.type = 'reg' & @dest.type = 'reg' jyes xchg_reg_reg check @src.type = 'reg' & @dest.type = 'mem' jyes xchg_reg_rm check @src.type = 'mem' & @dest.type = 'reg' jyes xchg_rm_reg invalid_combination_of_operands: err 'invalid combination of operands' exit operand_size_not_specified: err 'operand size not specified' compute size, 0 jump main operand_sizes_do_not_match: err 'operand sizes do not match' compute size, 0 jump main xchg_reg_reg: check (@src.rm & @dest.rm) | (size = 4 & @src.rm or @dest.rm = 0) | x86.rmposition = x86.rmdst.rmposition jyes xchg_rm_reg check x86.rmposition = x86.rmsrc.rmposition jyes xchg_reg_rm check size > 1 jno xchg_rm_reg_8bit compute @src.rm, @src.rm or @dest.rm call x86.store_operand_prefix, size,@src.rm emit 1, 90h + @src.rm and 111b exit xchg_reg_rm: check size > 1 jno xchg_reg_rm_8bit call x86.select_operand_prefix@dest, size xcall x86.store_instruction@dest, (87h),@src.rm exit xchg_reg_rm_8bit: xcall x86.store_instruction@dest, (86h),@src.rm exit xchg_rm_reg: check size > 1 jno xchg_rm_reg_8bit call x86.select_operand_prefix@src, size xcall x86.store_instruction@src, (87h),@dest.rm exit xchg_rm_reg_8bit: xcall x86.store_instruction@src, (86h),@dest.rm exit end calminstruction iterate , inc,0 ,dec,1 calminstruction instr? dest* call x86.parse_operand@dest, dest check @dest.size jyes main err 'operand size not specified' main: check @dest.type = 'mem' | (x86.mode = 64 & @dest.type = 'reg') jyes inc_rm check @dest.type = 'reg' jyes inc_reg err 'invalid operand' exit inc_reg: check @dest.size > 1 jno inc_rm_8bit call x86.store_operand_prefix, @dest.size emit 1, 40h + @dest.rm + postbyte shl 3 exit inc_rm: check @dest.size > 1 jno inc_rm_8bit xcall x86.select_operand_prefix@dest, @dest.size xcall x86.store_instruction@dest, (0FFh),(postbyte) exit inc_rm_8bit: xcall x86.store_instruction@dest, (0FEh),(postbyte) end calminstruction end iterate calminstruction imul? dest*,src& local size call x86.parse_operand@dest, dest match , src jyes imul_rm call x86.require.80186 local src1, src2 match src1 =, src2, src jyes imul_second_source call x86.parse_operand@src, src check @dest.size = 0 & @src.size = 0 jyes operand_size_not_specified check @dest.size <> 0 & @src.size <> 0 & @dest.size <> @src.size jyes operand_sizes_do_not_match compute size, @dest.size or @src.size check @dest.type = 'reg' & (@src.type = 'reg' | @src.type = 'mem') jyes imul_reg_rm check @src.type = 'imm' & @dest.type = 'reg' jno invalid_combination_of_operands compute @aux.type, @src.type compute @aux.imm, @src.imm compute @src.type, @dest.type compute @src.mod, @dest.mod compute @src.rm, @dest.rm jump main imul_second_source: call x86.parse_operand@src, src1 call x86.parse_operand@aux, src2 check @dest.size = 0 & @src.size = 0 & @aux.size = 0 jyes operand_size_not_specified compute size, @dest.size or @src.size or @aux.size check (@dest.size & @dest.size <> size) | (@src.size & @src.size <> size) | (@aux.size & @aux.size <> size) jyes operand_sizes_do_not_match jump main operand_size_not_specified: err 'operand size not specified' compute size, 0 jump main operand_sizes_do_not_match: err 'operand sizes do not match' compute size, 0 jump main main: check @aux.type = 'imm' & ( @src.type = 'mem' | @src.type = 'reg' ) & @dest.type = 'reg' jyes imul_reg_rm_imm invalid_combination_of_operands: err 'invalid combination of operands' exit imul_rm: check @dest.size jyes imul_rm_size_ok err 'operand size not specified' imul_rm_size_ok: check @dest.type = 'mem' | @dest.type = 'reg' jno invalid_combination_of_operands check @dest.size > 1 jno imul_rm_8bit xcall x86.select_operand_prefix@dest, @dest.size xcall x86.store_instruction@dest, (0F7h),(5) exit imul_rm_8bit: xcall x86.store_instruction@dest, (0F6h),(5) exit imul_reg_rm: call x86.select_operand_prefix@src, size xcall x86.store_instruction@src, <0Fh,0AFh>,@dest.rm exit imul_reg_rm_imm: call x86.select_operand_prefix@src, size check @aux.imm eqtype 0.0 jno imul_reg_rm_imm_optimize asm virtual at 0 asm emit size: @aux.imm asm load @aux.imm:size from 0 asm end virtual compute @aux.imm, +@aux.imm imul_reg_rm_imm_optimize: check @aux.imm relativeto 0 & @aux.imm < 80h & @aux.imm >= -80h jyes imul_reg_rm_simm check @aux.imm relativeto 0 & @aux.imm - 1 shl (size shl 3) >= -80h & @aux.imm < 1 shl (size shl 3) jyes imul_reg_rm_simm_wrap xcall x86.store_instruction@src, (69h),@dest.rm,size,@aux.imm exit imul_reg_rm_simm_wrap: compute @aux.imm, @aux.imm - 1 shl (size shl 3) imul_reg_rm_simm: xcall x86.store_instruction@src, (6Bh),@dest.rm,byte,@aux.imm exit end calminstruction calminstruction x86.push_instruction size:0,src* call x86.parse_operand@src, src check size <> 0 & @src.size and not size jyes invalid_operand_size compute size, size or @src.size check size = 0 | size = 2 | (size = 4 & x86.mode < 64) | (size = 8 & x86.mode = 64) jyes main invalid_operand_size: err 'invalid operand size' main: check (x86.mode <> 16 & size = 2) | (x86.mode = 16 & size = 4) jno prefix_ready call x86.require.80386 compute @src.prefix, 66h prefix_ready: check @src.type = 'mem' jyes push_mem check @src.prefix jno prefix_stored emit 1, @src.prefix prefix_stored: check @src.type = 'reg' jyes push_reg check @src.type = 'sreg' jyes push_sreg check @src.type = 'imm' jyes push_imm invalid_operand: err 'invalid operand' exit push_mem: xcall x86.store_instruction@src, (0FFh),(110b) exit push_reg: check @src.rm and 1000b jyes push_new_reg emit 1, 50h + @src.rm exit push_new_reg: emit 1, 41h emit 1, 50h + @src.rm and 111b exit push_sreg: check @src.rm >= 4 jyes push_sreg_386 check x86.mode = 64 jyes invalid_operand emit 1, 6 + @src.rm shl 3 exit push_sreg_386: emit 1, 0Fh emit 1, 0A0h + (@src.rm-4) shl 3 exit push_imm: call x86.require.80186 check size jyes push_imm_size_ok check x86.mode = 16 jyes push_imm_16bit check x86.mode = 32 jyes push_imm_32bit compute size, 8 jump push_imm_size_ok push_imm_32bit: compute size, 4 jump push_imm_size_ok push_imm_16bit: compute size, 2 push_imm_size_ok: check @src.imm eqtype 0.0 jno push_imm_check asm virtual at 0 asm emit size: @src.imm asm load @src.imm:size from 0 asm end virtual compute @src.imm, +@src.imm push_imm_check: check size = 8 & @src.imm relativeto 0 jno push_imm_optimize check @src.imm - 10000000000000000h >= -80000000h & @src.imm < 10000000000000000h jyes push_imm_wrap check @src.imm >= 80000000h | @src.imm < -80000000h jno push_imm_optimize err 'immediate value out of signed range' exit push_imm_wrap: compute @src.imm, @src.imm - 10000000000000000h push_imm_optimize: check x86.immsize < 2 & @src.imm relativeto 0 & @src.imm < 80h & @src.imm >= -80h jyes push_simm check x86.immsize < 2 & size = 2 & @src.imm relativeto 0 & @src.imm - 10000h >= -80h & @src.imm < 10000h jyes push_simm_wrap check x86.immsize < 2 & size = 4 & @src.imm relativeto 0 & @src.imm - 100000000h >= -80h & @src.imm < 100000000h jyes push_simm_wrap emit 1, 68h check size = 2 jyes src_imm_16bit call dword, @src.imm exit src_imm_16bit: call word, @src.imm exit push_simm_wrap: compute @src.imm, @src.imm - 1 shl (size shl 3) push_simm: emit 1, 6Ah emit 1, @src.imm exit end calminstruction calminstruction x86.pop_instruction size:0,dest* call x86.parse_operand@dest, dest check size <> 0 & @dest.size and not size jyes invalid_operand_size compute size, size or @dest.size check size = 0 | size = 2 | (size = 4 & x86.mode < 64) | (size = 8 & x86.mode = 64) jyes main invalid_operand_size: err 'invalid operand size' main: check (x86.mode <> 16 & size = 2) | (x86.mode = 16 & size = 4) jno prefix_ready call x86.require.80386 compute @dest.prefix, 66h prefix_ready: check @dest.type = 'mem' jyes pop_mem check @dest.prefix jno prefix_stored emit 1, @dest.prefix prefix_stored: check @dest.type = 'reg' jyes pop_reg check @dest.type = 'sreg' jyes pop_sreg invalid_operand: err 'invalid operand' exit pop_mem: xcall x86.store_instruction@dest, (8Fh),(0) exit pop_reg: check @dest.rm and 1000b jyes pop_new_reg emit 1, 58h + @dest.rm exit pop_new_reg: emit 1, 41h emit 1, 58h + @dest.rm and 111b exit pop_sreg: check @dest.rm = 1 jyes invalid_operand check @dest.rm >= 4 jyes pop_sreg_386 check x86.mode = 64 jyes invalid_operand emit 1, 7 + @dest.rm shl 3 exit pop_sreg_386: emit 1, 0Fh emit 1, 0A1h + (@dest.rm-4) shl 3 exit end calminstruction iterate reg, ax,cx,dx,bx,sp,bp,si,di,r8w,r9w,r10w,r11w,r12w,r13w,r14w,r15w, \ eax,ecx,edx,ebx,esp,ebp,esi,edi,r8d,r9d,r10d,r11d,r12d,r13d,r14d,r15d, \ rax,rcx,rdx,rbx,rsp,rbp,rsi,rdi,r8,r9,r10,r11,r12,r13,r14,r15, \ es,cs,ss,ds,fs,gs define x86.compact.reg? {reg} end iterate iterate , push,push_instruction,0, pushw,push_instruction,2, pushd,push_instruction,4, pushq,push_instruction,8, \ pop,pop_instruction,0, popw,pop_instruction,2, popd,pop_instruction,4, popq,pop_instruction,8 calminstruction instr? operand local head, tail match head tail, operand jno plain transform head, x86.compact jno plain match {head}, head jno plain loop: xcall x86.handler, (size),head match head tail, tail jno final transform head, x86.compact jno error match {head}, head jyes loop error: err 'only register operands allowed in compact syntax' exit final: transform tail, x86.compact jno error match {operand}, tail jno error plain: xcall x86.handler, (size),operand end calminstruction end iterate iterate , ret,0C2h, retn,0C2h, retf,0CAh calminstruction instr? operand match , operand jyes ret_short check operand jno ret_short emit 1, opcode call word, operand exit ret_short: emit 1, opcode + 1 end calminstruction end iterate iterate , retw,2,0C2h, retnw,2,0C2h, retd,4,0C2h, retnd,4,0C2h, retfw,2,0CAh, retfd,4,0CAh calminstruction instr? operand check x86.mode = 64 jyes illegal_instruction xcall x86.store_operand_prefix, (size) match , operand jyes ret_short emit 1, opcode call word, operand exit ret_short: emit 1, opcode + 1 exit illegal_instruction: err 'illegal instruction' end calminstruction end iterate iterate , retq,0C2h, retnq,0C2h, retfq,0CAh calminstruction instr? operand call x86.require.bits64 match , operand jyes ret_short emit 1, opcode call word, operand exit ret_short: emit 1, opcode + 1 exit end calminstruction end iterate calminstruction lea? dest*,src* call x86.parse_operand@dest, dest call x86.parse_operand@src, src check @src.type = 'mem' & @dest.type = 'reg' jno invalid_combination_of_operands xcall x86.select_operand_prefix@src, @dest.size xcall x86.store_instruction@src, (8Dh),@dest.rm exit invalid_combination_of_operands: err 'invalid combination of operands' end calminstruction iterate , les,0C4h, lds,0C5h calminstruction instr? dest*,src* check x86.mode = 64 jyes illegal_instruction call x86.parse_operand@dest, dest call x86.parse_operand@src, src check (@dest.size = 2 & (@src.size <> 0 & @src.size <> 4)) | (@dest.size = 4 & (@src.size <> 0 & @src.size <> 6)) jyes invalid_operand_size check @src.type = 'mem' & @dest.type = 'reg' jno invalid_combination_of_operands xcall x86.select_operand_prefix@src, @dest.size xcall x86.store_instruction@src, (opcode),@dest.rm exit illegal_instruction: err 'illegal instruction' exit invalid_operand_size: err 'invalid operand size' exit invalid_combination_of_operands: err 'invalid combination of operands' end calminstruction end iterate iterate , lss,<0Fh,0B2h>, lfs,<0Fh,0B4h>, lgs,<0Fh,0B5h> calminstruction instr? dest*,src* call x86.require.80386 call x86.parse_operand@dest, dest call x86.parse_operand@src, src check (@dest.size = 2 & (@src.size <> 0 & @src.size <> 4)) | (@dest.size = 4 & (@src.size <> 0 & @src.size <> 6)) | (@dest.size = 8 & (@src.size <> 0 & @src.size <> 10)) jyes invalid_operand_size check @src.type = 'mem' & @dest.type = 'reg' jno invalid_combination_of_operands xcall x86.select_operand_prefix@src, @dest.size xcall x86.store_instruction@src, ,@dest.rm exit invalid_operand_size: err 'invalid operand size' invalid_combination_of_operands: err 'invalid combination of operands' end calminstruction end iterate iterate , rol,0, ror,1, rcl,2, rcr,3, shl,4, sal, 4, shr,5, sar,7 calminstruction instr? dest*,cnt* call x86.parse_operand@dest, dest call x86.parse_operand@src, cnt check @dest.size = 0 jyes operand_size_not_specified check @src.size and not 1 jyes invalid_operand_size main: check @src.type = 'reg' & @src.size = 1 & @src.rm = 1 & ( @dest.type = 'reg' | @dest.type = 'mem' ) jyes shift_rm_cl check @src.type = 'imm' & ( @dest.type = 'reg' | @dest.type = 'mem' ) jyes shift_rm_imm err 'invalid combination of operands' exit shift_rm_cl: check @dest.size > 1 jno shift_r8_cl xcall x86.select_operand_prefix@dest, @dest.size xcall x86.store_instruction@dest, (0D3h),(postbyte) exit shift_r8_cl: xcall x86.store_instruction@dest, (0D2h),(postbyte) exit shift_rm_imm: check @dest.size > 1 jno shift_rm8_imm xcall x86.select_operand_prefix@dest, @dest.size check @src.imm = 1 jyes shift_rm_1 call x86.require.80186 xcall x86.store_instruction@dest, (0C1h),(postbyte),byte,@src.imm exit shift_rm_1: xcall x86.store_instruction@dest, (0D1h),(postbyte) exit shift_rm8_imm: check @src.imm = 1 jyes shift_rm8_1 call x86.require.80186 xcall x86.store_instruction@dest, (0C0h),(postbyte),byte,@src.imm exit shift_rm8_1: xcall x86.store_instruction@dest, (0D0h),(postbyte) exit operand_size_not_specified: err 'operand size not specified' jump main invalid_operand_size: err 'invalid operand size' jump main end calminstruction end iterate iterate , shld,0A4h, shrd,0ACh calminstruction instr? dest*,src*,cnt* call x86.require.80386 call x86.parse_operand@dest, dest call x86.parse_operand@src, src call x86.parse_operand@aux, cnt check @aux.size and not 1 jyes invalid_operand_size check @dest.size and not @src.size jno main err 'operand sizes do not match' main: check @aux.type = 'reg' & @aux.size = 1 & @aux.rm = 1 & @src.type = 'reg' & ( @dest.type = 'reg' | @dest.type = 'mem' ) jyes shld_cl check @aux.type = 'imm' & @src.type = 'reg' & ( @dest.type = 'reg' | @dest.type = 'mem' ) jyes shld_imm err 'invalid combination of operands' exit shld_cl: xcall x86.select_operand_prefix@dest, @src.size xcall x86.store_instruction@dest, <0Fh,ext+1>,@src.rm exit shld_imm: xcall x86.select_operand_prefix@dest, @src.size xcall x86.store_instruction@dest, <0Fh,ext>,@src.rm,byte,@aux.imm exit invalid_operand_size: err 'invalid operand size' end calminstruction end iterate iterate , bt,4, bts,5, btr,6, btc,7 calminstruction instr? dest*,src* call x86.require.80386 call x86.parse_operand@dest, dest call x86.parse_operand@src, src check @src.type = 'reg' & (@dest.type = 'mem' | @dest.type = 'reg') jyes bt_rm_reg check @src.type = 'imm' & (@dest.type = 'mem' | @dest.type = 'reg') jyes bt_rm_imm err 'invalid combination of operands' exit bt_rm_reg: local opcode check @dest.size and not @src.size jno bt_rm_reg_ok err 'operand sizes do not match' bt_rm_reg_ok: compute opcode, 0A3h+(postbyte-4) shl 3 xcall x86.select_operand_prefix@dest, @src.size xcall x86.store_instruction@dest, <0Fh,opcode>,@src.rm exit bt_rm_imm: check @src.size and not 1 jno bt_rm_imm_ok err 'invalid operand size' bt_rm_imm_ok: check @dest.size jno operand_size_not_specified xcall x86.select_operand_prefix@dest, @dest.size xcall x86.store_instruction@dest, <0Fh,0BAh>,(postbyte),byte,@src.imm exit operand_size_not_specified: err 'operand size not specified' end calminstruction end iterate iterate , bsf,0BCh, bsr,0BDh calminstruction instr? dest*,src* call x86.require.80386 call x86.parse_operand@dest, dest call x86.parse_operand@src, src check @dest.type = 'reg' & (@src.type = 'mem' | @src.type = 'reg') jyes bsf_rm_reg err 'invalid combination of operands' exit bsf_rm_reg: check @src.size and not @dest.size jno bsf_rm_reg_ok err 'operand sizes do not match' bsf_rm_reg_ok: xcall x86.select_operand_prefix@src, @dest.size xcall x86.store_instruction@src, <0Fh,ext>,@dest.rm end calminstruction end iterate iterate , movzx,0B6h, movsx,0BEh calminstruction instr? dest*,src* call x86.require.80386 call x86.parse_operand@dest, dest call x86.parse_operand@src, src check @dest.size > @src.size jyes size_ok err 'operand sizes do not match' size_ok: check @dest.type = 'reg' & (@src.type = 'mem' | @src.type = 'reg') jyes operands_ok err 'invalid combination of operands' exit operands_ok: check @src.size = 2 jyes movzx_word check @src.size = 1 | (@src.size = 0 & @dest.size = 2) jyes movzx_byte check @src.size jyes invalid_operand_size err 'operand size not specified' movzx_word: xcall x86.select_operand_prefix@src, @dest.size xcall x86.store_instruction@src, <0Fh,ext+1>,@dest.rm exit movzx_byte: xcall x86.select_operand_prefix@src, @dest.size xcall x86.store_instruction@src, <0Fh,ext>,@dest.rm exit invalid_operand_size: err 'invalid operand size' end calminstruction end iterate calminstruction movsxd? dest*,src* call x86.require.x64 call x86.parse_operand@dest, dest call x86.parse_operand@src, src check @dest.size > @src.size jyes size_ok err 'operand sizes do not match' size_ok: check @dest.type = 'reg' & (@src.type = 'mem' | @src.type = 'reg') jyes operands_ok err 'invalid combination of operands' exit operands_ok: check @src.size and not 4 jyes invalid_operand_size xcall x86.select_operand_prefix@src, @dest.size xcall x86.store_instruction@src, (63h),@dest.rm exit invalid_operand_size: err 'invalid operand size' end calminstruction iterate , o,0, no,1, c,2, b,2, nae,2, nc,3, nb,3, ae,3, z,4, e,4, nz,5, ne,5, na,6, be,6, a,7, nbe,7, \ s,8, ns,9, p,0Ah, pe,0Ah, np,0Bh, po,0Bh, l,0Ch, nge,0Ch, nl,0Dh, ge,0Dh, ng,0Eh, le,0Eh, g,0Fh, nle,0Fh calminstruction set#cond? dest* call x86.require.80386 call x86.parse_operand@dest, dest check @dest.size > 1 jno size_ok err 'invalid operand size' size_ok: check @dest.type = 'reg' | @dest.type = 'mem' jyes operand_ok err 'invalid operand' exit operand_ok: xcall x86.store_instruction@dest, <0Fh,90h+code>,(0) end calminstruction calminstruction cmov#cond? dest*,src* call x86.require.P6 call x86.parse_operand@dest, dest call x86.parse_operand@src, src check @dest.type = 'reg' & (@src.type = 'mem' | @src.type = 'reg') jyes cmov_rm_reg err 'invalid combination of operands' exit cmov_rm_reg: check @src.size and not @dest.size jno cmov_rm_reg_ok err 'operand sizes do not match' cmov_rm_reg_ok: xcall x86.select_operand_prefix@src, @dest.size xcall x86.store_instruction@src, <0Fh,40h+code>,@dest.rm end calminstruction end iterate calminstruction call? dest* call x86.parse_jump_operand@dest, dest check @dest.type = 'imm' jyes call_imm check @dest.type = 'mem' | @dest.type = 'reg' jyes call_rm check @dest.type = 'far' jyes call_direct_far invalid_operand: err 'invalid operand' exit illegal_instruction: err 'illegal instruction' exit call_direct_far: check @dest.jump_type & @dest.jump_type <> 'far' jyes invalid_operand check x86.mode = 64 jyes illegal_instruction check @dest.size = 0 jyes prefix_ok local size compute size, @dest.size - 2 call x86.store_operand_prefix, size prefix_ok: check @dest.size and not 4 & @dest.size and not 6 jyes invalid_operand emit 1, 9Ah check (@dest.size = 0 & x86.mode = 16) | @dest.size = 4 jyes far_dword call dword, @dest.offset call word, @dest.segment exit far_dword: call word, @dest.offset call word, @dest.segment exit call_rm: check @dest.size = 6 | @dest.size = 10 jyes call_rm_pword check @dest.size = 8 & x86.mode = 64 jyes call_rm_qword check @dest.size = 4 & x86.mode < 64 jyes call_rm_dword check @dest.size = 2 & x86.mode < 64 jyes call_rm_word check @dest.size jyes invalid_operand check x86.mode = 64 jno rex_prefix_ok compute @dest.prefix, 48h rex_prefix_ok: check @dest.jump_type = 'far' jyes call_rm_far check @dest.jump_type = 'near' jyes call_rm_near err 'operand size not specified' exit call_rm_pword: check @dest.jump_type & @dest.jump_type <> 'far' jyes invalid_operand local size compute size, @dest.size - 2 call x86.select_operand_prefix@dest, size call_rm_far: xcall x86.store_instruction@dest, (0FFh),(11b) exit call_rm_qword: check @dest.jump_type & @dest.jump_type <> 'near' jyes invalid_operand jump call_rm_near call_rm_dword: check @dest.jump_type | @dest.type = 'reg' jno call_rm_dword_auto check @dest.jump_type = 'far' jyes call_rm_dword_far call_rm_dword_near: xcall x86.select_operand_prefix@dest, (4) jump call_rm_near call_rm_dword_auto: check x86.mode = 16 jno call_rm_dword_near call_rm_dword_far: xcall x86.select_operand_prefix@dest, (2) jump call_rm_far call_rm_word: check @dest.jump_type & @dest.jump_type <> 'near' jyes invalid_operand xcall x86.select_operand_prefix@dest, (2) call_rm_near: xcall x86.store_instruction@dest, (0FFh),(10b) exit call_imm: check @dest.jump_type & @dest.jump_type <> 'near' jyes invalid_operand check @dest.size = 8 & x86.mode = 64 jyes call_imm_qword check @dest.size = 2 & x86.mode < 64 jyes call_imm_word check @dest.size = 4 & x86.mode < 64 jno invalid_operand xcall x86.store_operand_prefix, (4) emit 1, 0E8h compute @dest.imm, @dest.imm-($+4) call dword, @dest.imm exit call_imm_word: xcall x86.store_operand_prefix, (2) emit 1, 0E8h compute @dest.imm, @dest.imm-($+2) check @dest.imm relativeto 0 jno store_word compute @dest.imm, @dest.imm and 0FFFFh store_word: call word, @dest.imm exit call_imm_qword: emit 1, 0E8h compute @dest.imm, @dest.imm-($+4) check @dest.imm relativeto 0 & (@dest.imm < -80000000h | @dest.imm >= 80000000h) jno store_dword err 'relative jump out of range' store_dword: call dword, @dest.imm exit end calminstruction calminstruction jmp? dest* call x86.parse_jump_operand@dest, dest check @dest.type = 'imm' jyes jmp_imm check @dest.type = 'mem' | @dest.type = 'reg' jyes jmp_rm check @dest.type = 'far' jyes jmp_direct_far invalid_operand: err 'invalid operand' exit illegal_instruction: err 'illegal instruction' exit jmp_direct_far: check @dest.jump_type & @dest.jump_type <> 'far' jyes invalid_operand check x86.mode = 64 jyes illegal_instruction check @dest.size = 0 jyes prefix_ok local size compute size, @dest.size - 2 call x86.store_operand_prefix, size prefix_ok: check @dest.size and not 4 & @dest.size and not 6 jyes invalid_operand emit 1, 0EAh check (@dest.size = 0 & x86.mode = 16) | @dest.size = 4 jyes far_dword call dword, @dest.offset call word, @dest.segment exit far_dword: call word, @dest.offset call word, @dest.segment exit jmp_rm: check @dest.size = 6 | @dest.size = 10 jyes jmp_rm_pword check @dest.size = 8 & x86.mode = 64 jyes jmp_rm_qword check @dest.size = 4 & x86.mode < 64 jyes jmp_rm_dword check @dest.size = 2 & x86.mode < 64 jyes jmp_rm_word check @dest.size jyes invalid_operand check x86.mode = 64 jno rex_prefix_ok compute @dest.prefix, 48h rex_prefix_ok: check @dest.jump_type = 'far' jyes jmp_rm_far check @dest.jump_type = 'near' jyes jmp_rm_near err 'operand size not specified' exit jmp_rm_pword: check @dest.jump_type & @dest.jump_type <> 'far' jyes invalid_operand local size compute size, @dest.size - 2 call x86.select_operand_prefix@dest, size jmp_rm_far: xcall x86.store_instruction@dest, (0FFh),(101b) exit jmp_rm_qword: check @dest.jump_type & @dest.jump_type <> 'near' jyes invalid_operand jump jmp_rm_near jmp_rm_dword: check @dest.jump_type | @dest.type = 'reg' jno jmp_rm_dword_auto check @dest.jump_type = 'far' jyes jmp_rm_dword_far jmp_rm_dword_near: xcall x86.select_operand_prefix@dest, (4) jump jmp_rm_near jmp_rm_dword_auto: check x86.mode = 16 jno jmp_rm_dword_near jmp_rm_dword_far: xcall x86.select_operand_prefix@dest, (2) jump jmp_rm_far jmp_rm_word: check @dest.jump_type & @dest.jump_type <> 'near' jyes invalid_operand xcall x86.select_operand_prefix@dest, (2) jmp_rm_near: xcall x86.store_instruction@dest, (0FFh),(100b) exit jmp_imm: check @dest.jump_type = 'far' jyes invalid_operand check (@dest.size = 8 & x86.mode < 64) | (@dest.size < 8 & x86.mode = 64) jyes invalid_operand check @dest.size = 8 jyes jmp_imm_prefix_ok call x86.store_operand_prefix, @dest.size jmp_imm_prefix_ok: check @dest.jump_type = 'short' jyes jmp_imm_short_verify check @dest.jump_type = 'near' jyes jmp_imm_near check ~ $ relativeto 0 & @dest.imm relativeto 0 jno jmp_optimize compute @dest.imm, @dest.imm + $ - 0 scaleof $ err 'invalid address' jmp_optimize: check @dest.unresolved jyes jmp_imm_short check @dest.imm relativeto $ jno jmp_imm_near check (@dest.imm-($+2)) < 80h & (@dest.imm-($+2)) >= -80h jyes jmp_imm_short check (@dest.imm-($+2)) and (1 shl (@dest.size*8) - 1) < 80h | (@dest.imm-($+2)) and (1 shl (@dest.size*8) - 1) >= 1 shl (@dest.size*8) - 80h jyes jmp_imm_short jmp_imm_near: check @dest.size = 8 jyes jmp_imm_qword check @dest.size = 2 jyes jmp_imm_word check @dest.size = 4 jno invalid_operand emit 1, 0E9h compute @dest.imm, @dest.imm-($+4) call dword, @dest.imm exit jmp_imm_word: emit 1, 0E9h compute @dest.imm, @dest.imm-($+2) check @dest.imm relativeto 0 jno store_word compute @dest.imm, @dest.imm and 0FFFFh store_word: call word, @dest.imm exit jmp_imm_qword: emit 1, 0E9h compute @dest.imm, @dest.imm-($+4) call dword, @dest.imm check @dest.imm relativeto 0 & (@dest.imm < -80000000h | @dest.imm >= 80000000h) jyes relative_jump_out_of_range exit jmp_imm_short_verify: check (@dest.imm-($+2)) < 80h & (@dest.imm-($+2)) >= -80h jyes jmp_imm_short check (@dest.imm-($+2)) and (1 shl (@dest.size*8) - 1) < 80h | (@dest.imm-($+2)) and (1 shl (@dest.size*8) - 1) >= 1 shl (@dest.size*8) - 80h jyes jmp_imm_short emit 1, 0EBh emit 1 relative_jump_out_of_range: err 'relative jump out of range' exit jmp_imm_short: emit 1, 0EBh compute @dest.imm, (@dest.imm-($+1)) and 0FFh emit 1, @dest.imm exit end calminstruction iterate , jo,70h, jno,71h, jc,72h, jb,72h, jnae,72h, jnc,73h, jnb,73h, jae,73h, jz,74h, je,74h, jnz,75h, jne,75h, jna,76h, jbe,76h, ja,77h, jnbe,77h, \ js,78h, jns,79h, jp,7Ah, jpe,7Ah, jnp,7Bh, jpo,7Bh, jl,7Ch, jnge,7Ch, jnl,7Dh, jge,7Dh, jng,7Eh, jle,7Eh, jg,7Fh, jnle,7Fh calminstruction instr? dest* call x86.parse_jump_operand@dest, dest check @dest.type <> 'imm' | @dest.jump_type = 'far' jyes invalid_operand check x86.mode = 64 | @dest.size = 8 jyes long call x86.store_operand_prefix, @dest.size jump prefix_ok long: check x86.mode < 64 | @dest.size <> 8 jyes invalid_operand prefix_ok: check ~ $ relativeto 0 & @dest.imm relativeto 0 jno optimize compute @dest.imm, @dest.imm + $ - 0 scaleof $ err 'invalid address' optimize: check @dest.jump_type = 'near' jyes explicit_near check @dest.unresolved | ( @dest.imm relativeto $ & @dest.imm-($+2) < 80h & @dest.imm-($+2) >= -80h ) jyes short check @dest.imm relativeto $ & ( (@dest.imm-($+2)) and (1 shl (@dest.size*8) - 1) < 80h | (@dest.imm-($+2)) and (1 shl (@dest.size*8) - 1) >= 1 shl (@dest.size*8) - 80h ) jyes short check @dest.jump_type = 'short' | x86.cpu < x86.80386.cpu jno near emit 2 err 'relative jump out of range' exit explicit_near: call x86.require.80386 near: emit 1, 0Fh emit 1, 10h+opcode check @dest.size = 2 jyes relative_word compute @dest.imm, @dest.imm-($+4) call dword, @dest.imm exit relative_word: compute @dest.imm, @dest.imm-($+2) check @dest.imm relativeto 0 jno store_word compute @dest.imm, @dest.imm and 0FFFFh store_word: call word, @dest.imm exit short: compute @dest.imm, (@dest.imm-($+2)) and 0FFh emit 1, opcode emit 1, @dest.imm exit invalid_operand: err 'invalid operand' exit end calminstruction end iterate iterate , loopnz,0E0h,0, loopne,0E0h,0, loopz,0E1h,0, loope,0E1h,0, loop,0E2h,0, \ loopnzw,0E0h,2, loopnew,0E0h,2, loopzw,0E1h,2, loopew,0E1h,2, loopw,0E2h,2, \ loopnzd,0E0h,4, loopned,0E0h,4, loopzd,0E1h,4, looped,0E1h,4, loopd,0E2h,4, \ loopnzq,0E0h,8, loopneq,0E0h,8, loopzq,0E1h,8, loopeq,0E1h,8, loopq,0E2h,8, \ jcxz,0E3h,2, jecxz,0E3h,4, jrcxz,0E3h,8 calminstruction instr? dest* call x86.parse_jump_operand@dest, dest check @dest.type = 'imm' & ( @dest.jump_type = 'short' | ~ @dest.jump_type ) jno invalid_operand check len shl 3 and not x86.mode jno address_prefix_ok check len = 8 | (len = 2 & x86.mode = 64) jyes illegal_instruction call x86.require.80386 emit 1, 67h address_prefix_ok: check @dest.size shl 3 <> x86.mode jno operand_prefix_ok check @dest.size = 8 | x86.mode = 64 jyes invalid_operand call x86.require.80386 emit 1, 66h operand_prefix_ok: emit 1, opcode check @dest.imm-($+1) < 80h & @dest.imm-($+1) >= -80h jyes relative_offset_ok check (@dest.imm-($+2)) and (1 shl (@dest.size*8) - 1) < 80h | (@dest.imm-($+2)) and (1 shl (@dest.size*8) - 1) >= 1 shl (@dest.size*8) - 80h jyes relative_offset_ok emit 1 err 'relative jump out of range' exit relative_offset_ok: compute @dest.imm, (@dest.imm-($+1)) and 0FFh emit 1, @dest.imm exit illegal_instruction: err 'illegal instruction' exit invalid_operand: err 'invalid operand' exit end calminstruction end iterate iterate , nop,90h, int3,0CCh, into,0CEh, int1,0F1h, salc,0D6h, \ hlt,0F4h, cmc,0F5h, clc,0F8h, stc,0F9h, cli,0FAh, sti,0FBh, cld,0FCh, std,0FDh, \ pushf,9Ch, popf,9Dh, sahf,9Eh, lahf,9Fh, \ movsb,0A4h, cmpsb,0A6h, stosb,0AAh, lodsb,0ACh, scasb,0AEh, xlatb,0D7h calminstruction instr? emit 1, opcode end calminstruction end iterate iterate , leave,0C9h, insb,6Ch, outsb,6Eh calminstruction instr? call x86.require.80186 emit 1, opcode end calminstruction end iterate iterate , clts,<0Fh,6>,80286, invd,<0Fh,8>,80486, wbinvd,<0Fh,9>,80486, \ wrmsr,<0Fh,30h>,P5, rdtsc,<0Fh,31h>,P5, rdmsr,<0Fh,32h>,P5, rdpmc,<0Fh,33h>,P5, \ cpuid,<0Fh,0A2h>,P5, rsm,<0Fh,0AAh>,P5, sysenter,<0Fh,34h>,P6, sysexit,<0Fh,35h>,P6 match byte1=,byte2, opcode calminstruction instr? call x86.require.cpu emit 1, byte1 emit 1, byte2 end calminstruction end match end iterate iterate , cbw,98h, cwd,99h, iretw,0CFh, movsw,0A5h, cmpsw,0A7h, stosw,0ABh, lodsw,0ADh, scasw,0AFh calminstruction instr? xcall x86.store_operand_prefix, (2) emit 1, opcode end calminstruction end iterate iterate , cwde,98h, cdq,99h, iretd,0CFh, movsd,0A5h, cmpsd,0A7h, stosd,0ABh, lodsd,0ADh, scasd,0AFh calminstruction instr? xcall x86.store_operand_prefix, (4) emit 1, opcode end calminstruction end iterate iterate , insw,6Dh, outsw,6Fh calminstruction instr? call x86.require.80186 xcall x86.store_operand_prefix, (2) emit 1, opcode end calminstruction end iterate iterate , insd,6Dh, outsd,6Fh calminstruction instr? call x86.require.80186 xcall x86.store_operand_prefix, (4) emit 1, opcode end calminstruction end iterate iterate , cdqe,98h, cqo,99h, iretq,0CFh, \ movsq,0A5h, cmpsq,0A7h, stosq,0ABh, lodsq,0ADh, scasq,0AFh, \ sysretq,<0Fh,7>, wrmsrq,<0Fh,30h>, rdmsrq,<0Fh,32h>, sysexitq,<0Fh,35h> match byte1=,byte2, opcode calminstruction instr? xcall x86.store_operand_prefix, (8) emit 1, byte1 emit 1, byte2 end calminstruction else calminstruction instr? xcall x86.store_operand_prefix, (8) emit 1, opcode end calminstruction end match end iterate iterate , swapgs,<0Fh,1,0F8h>, syscall,<0Fh,5>, sysret,<0Fh,7> calminstruction instr? call x86.require.bits64 asm db opcode end calminstruction end iterate iterate , lock,0F0h, repnz,0F2h, repne,0F2h, rep,0F3h, repz,0F3h, repe,0F3h calminstruction prefix? instr& emit 1, opcode assemble instr end calminstruction end iterate calminstruction int? number* emit 1, 0CDh emit 1, number end calminstruction calminstruction iret? check x86.mode < 64 jyes prefix_ok emit 1, 48h prefix_ok: emit 1, 0CFh end calminstruction iterate , daa,27h, das,2Fh, aaa,37h, aas,3Fh, pusha,60h, popa,61h calminstruction instr? check x86.mode < 64 jyes allowed err 'illegal instruction' exit allowed: emit 1, opcode end calminstruction end iterate calminstruction aam? number:10 check x86.mode < 64 jyes allowed err 'illegal instruction' exit allowed: emit 1, 0D4h emit 1, number end calminstruction calminstruction aad? number:10 check x86.mode < 64 jyes allowed err 'illegal instruction' exit allowed: emit 1, 0D5h emit 1, number end calminstruction iterate , pushfw,9Ch, popfw,9Dh calminstruction instr? check x86.mode < 64 jyes allowed err 'illegal instruction' exit allowed: xcall x86.store_operand_prefix, (2) emit 1, opcode end calminstruction end iterate iterate , pushfd,9Ch, popfd,9Dh calminstruction instr? check x86.mode < 64 jyes allowed err 'illegal instruction' exit allowed: xcall x86.store_operand_prefix, (4) emit 1, opcode end calminstruction end iterate iterate , pushfq,9Ch, popfq,9Dh calminstruction instr? call x86.require.bits64 emit 1, opcode end calminstruction end iterate iterate , pushaw,60h, popaw,61h calminstruction instr? check x86.mode < 64 jyes allowed err 'illegal instruction' exit allowed: call x86.require.80186 xcall x86.store_operand_prefix, (2) emit 1, opcode end calminstruction end iterate iterate , pushad,60h, popad,61h calminstruction instr? check x86.mode < 64 jyes allowed err 'illegal instruction' exit allowed: call x86.require.80186 xcall x86.store_operand_prefix, (4) emit 1, opcode end calminstruction end iterate calminstruction movs? dest*,src* call x86.parse_operand@dest, dest call x86.parse_operand@src, src local size check @dest.size = 0 & @src.size = 0 jyes operand_size_not_specified check @dest.size <> 0 & @src.size <> 0 & @dest.size <> @src.size jyes operand_sizes_do_not_match compute size, @dest.size or @src.size size_ok: check @src.type = 'mem' & @src.mod = 0 & @dest.type = 'mem' & @dest.mod = 0 & ( (x86.mode < 64 & @src.mode = 16 & @src.rm = 4 & @dest.mode = 16 & @dest.rm = 5) | (@src.mode > 16 & @src.rm = 6 & @dest.mode = @src.mode & @dest.rm = 7) ) & ( @dest.segment_prefix = 0 | @dest.segment_prefix = 26h | (x86.mode = 64 & @dest.segment_prefix < 64h)) jno invalid_combination_of_operands check @src.segment_prefix = 0 | @src.segment_prefix = 3Eh | (x86.mode = 64 & @src.segment_prefix < 64h) jyes segment_prefix_ok emit 1, @src.segment_prefix segment_prefix_ok: check @dest.mode = x86.mode jyes address_prefix_ok emit 1, 67h address_prefix_ok: check size > 1 jyes movs_word emit 1, 0A4h exit movs_word: call x86.store_operand_prefix, size emit 1, 0A5h exit operand_size_not_specified: err 'operand size not specified' compute size, 0 jump size_ok operand_sizes_do_not_match: err 'operand sizes do not match' compute size, 0 jump size_ok invalid_combination_of_operands: err 'invalid combination of operands' exit end calminstruction calminstruction cmps? src*,dest* call x86.parse_operand@dest, dest call x86.parse_operand@src, src local size check @dest.size = 0 & @src.size = 0 jyes operand_size_not_specified check @dest.size <> 0 & @src.size <> 0 & @dest.size <> @src.size jyes operand_sizes_do_not_match compute size, @dest.size or @src.size size_ok: check @src.type = 'mem' & @src.mod = 0 & @dest.type = 'mem' & @dest.mod = 0 & ( (x86.mode < 64 & @src.mode = 16 & @src.rm = 4 & @dest.mode = 16 & @dest.rm = 5) | (@src.mode > 16 & @src.rm = 6 & @dest.mode = @src.mode & @dest.rm = 7) ) & ( @dest.segment_prefix = 0 | @dest.segment_prefix = 26h | (x86.mode = 64 & @dest.segment_prefix < 64h)) jno invalid_combination_of_operands check @src.segment_prefix = 0 | @src.segment_prefix = 3Eh | (x86.mode = 64 & @src.segment_prefix < 64h) jyes segment_prefix_ok emit 1, @src.segment_prefix segment_prefix_ok: check @dest.mode = x86.mode jyes address_prefix_ok emit 1, 67h address_prefix_ok: check size > 1 jyes cmps_word emit 1, 0A6h exit cmps_word: call x86.store_operand_prefix, size emit 1, 0A7h exit operand_size_not_specified: err 'operand size not specified' compute size, 0 jump size_ok operand_sizes_do_not_match: err 'operand sizes do not match' compute size, 0 jump size_ok invalid_combination_of_operands: err 'invalid combination of operands' exit end calminstruction calminstruction stos? dest* call x86.parse_operand@dest, dest check @dest.size jyes size_ok err 'operand size not specified' size_ok: check @dest.type = 'mem' & @dest.mod = 0 & ( (x86.mode < 64 & @dest.mode = 16 & @dest.rm = 5) | (@dest.mode > 16 & @dest.rm = 7) ) & ( @dest.segment_prefix = 0 | @dest.segment_prefix = 26h | (x86.mode = 64 & @dest.segment_prefix < 64h)) jno invalid_operand check @dest.mode = x86.mode jyes address_prefix_ok emit 1, 67h address_prefix_ok: check @dest.size > 1 jyes stos_word emit 1, 0AAh exit stos_word: call x86.store_operand_prefix, @dest.size emit 1, 0ABh exit invalid_operand: err 'invalid operand' exit end calminstruction calminstruction lods? src* call x86.parse_operand@src, src check @src.size jyes size_ok err 'operand size not specified' size_ok: check @src.type = 'mem' & @src.mod = 0 & ( (x86.mode < 64 & @src.mode = 16 & @src.rm = 4) | (@src.mode > 16 & @src.rm = 6) ) jno invalid_operand check @src.segment_prefix = 0 | @src.segment_prefix = 3Eh | (x86.mode = 64 & @src.segment_prefix < 64h) jyes segment_prefix_ok emit 1, @src.segment_prefix segment_prefix_ok: check @src.mode = x86.mode jyes address_prefix_ok emit 1, 67h address_prefix_ok: check @src.size > 1 jyes lods_word emit 1, 0ACh exit lods_word: call x86.store_operand_prefix, @src.size emit 1, 0ADh exit invalid_operand: err 'invalid operand' exit end calminstruction calminstruction scas? dest* call x86.parse_operand@dest, dest check @dest.size jyes size_ok err 'operand size not specified' size_ok: check @dest.type = 'mem' & @dest.mod = 0 & ( (x86.mode < 64 & @dest.mode = 16 & @dest.rm = 5) | (@dest.mode > 16 & @dest.rm = 7) ) & ( @dest.segment_prefix = 0 | @dest.segment_prefix = 26h | (x86.mode = 64 & @dest.segment_prefix < 64h)) jno invalid_operand check @dest.mode = x86.mode jyes address_prefix_ok emit 1, 67h address_prefix_ok: check @dest.size > 1 jyes scas_word emit 1, 0AEh exit scas_word: call x86.store_operand_prefix, @dest.size emit 1, 0AFh exit invalid_operand: err 'invalid operand' exit end calminstruction calminstruction ins? dest*,src* call x86.require.80186 call x86.parse_operand@dest, dest call x86.parse_operand@src, src check @dest.size jyes size_ok err 'operand size not specified' compute size, 0 size_ok: check @src.type = 'reg' & @src.size = 2 & @src.rm = 2 & @dest.type = 'mem' & @dest.mod = 0 & ( (x86.mode < 64 & @dest.mode = 16 & @dest.rm = 5) | (@dest.mode > 16 & @dest.rm = 7) ) & ( @dest.segment_prefix = 0 | @dest.segment_prefix = 26h | (x86.mode = 64 & @dest.segment_prefix < 64h)) jno invalid_combination_of_operands check @dest.mode = x86.mode jyes address_prefix_ok emit 1, 67h address_prefix_ok: check @dest.size > 1 jyes ins_word emit 1, 6Ch exit ins_word: call x86.store_operand_prefix, @dest.size emit 1, 6Dh exit invalid_combination_of_operands: err 'invalid combination of operands' exit end calminstruction calminstruction outs? dest*,src* call x86.require.80186 call x86.parse_operand@dest, dest call x86.parse_operand@src, src check @src.size jyes size_ok err 'operand size not specified' size_ok: check @dest.type = 'reg' & @dest.size = 2 & @dest.rm = 2 & @src.type = 'mem' & @src.mod = 0 & ( (x86.mode < 64 & @src.mode = 16 & @src.rm = 4) | (@src.mode > 16 & @src.rm = 6) ) jno invalid_combination_of_operands check @src.segment_prefix = 0 | @src.segment_prefix = 3Eh | (x86.mode = 64 & @src.segment_prefix < 64h) jyes segment_prefix_ok emit 1, @src.segment_prefix segment_prefix_ok: check @src.mode = x86.mode jyes address_prefix_ok emit 1, 67h address_prefix_ok: check @src.size > 1 jyes outs_word emit 1, 6Eh exit outs_word: call x86.store_operand_prefix, @src.size emit 1, 6Fh exit operand_size_not_specified: err 'operand size not specified' compute size, 0 jump size_ok operand_sizes_do_not_match: err 'operand sizes do not match' compute size, 0 jump size_ok invalid_combination_of_operands: err 'invalid combination of operands' exit end calminstruction calminstruction xlat? src* call x86.parse_operand@src, src check @src.size > 1 jno size_ok err 'invalid operand size' size_ok: check @src.type = 'mem' & @src.mod = 0 & ( (x86.mode < 64 & @src.mode = 16 & @src.rm = 7) | (@src.mode > 16 & @src.rm = 3) ) jno invalid_operand check @src.segment_prefix = 0 | @src.segment_prefix = 3Eh | (x86.mode = 64 & @src.segment_prefix < 64h) jyes segment_prefix_ok emit 1, @src.segment_prefix segment_prefix_ok: check @src.mode = x86.mode jyes address_prefix_ok emit 1, 67h address_prefix_ok: emit 1, 0D7h exit invalid_operand: err 'invalid operand' exit end calminstruction calminstruction in? dest*,src* call x86.parse_operand@dest, dest call x86.parse_operand@src, src check @dest.size = 8 jyes invalid_size check @dest.size jyes size_ok err 'operand size not specified' jump size_ok invalid_size: err 'invalid_operand_size' size_ok: check @src.type = 'reg' & @src.size = 2 & @src.rm = 2 & @dest.type = 'reg' & @dest.rm = 0 jyes in_ax_dx check @src.type = 'imm' & @dest.type = 'reg' & @dest.rm = 0 jyes in_ax_imm err 'invalid combination of operands' exit in_ax_dx: check @dest.size > 1 jno in_al_dx call x86.store_operand_prefix, @dest.size emit 1, 0EDh exit in_al_dx: emit 1, 0ECh exit in_ax_imm: check @dest.size > 1 jno in_al_imm call x86.store_operand_prefix, @dest.size emit 1, 0E5h emit 1, @src.imm exit in_al_imm: emit 1, 0E4h emit 1, @src.imm exit end calminstruction calminstruction out? dest*,src* call x86.parse_operand@dest, dest call x86.parse_operand@src, src check @src.size = 8 jyes invalid_size check @src.size jyes size_ok err 'operand size not specified' jump size_ok invalid_size: err 'invalid_operand_size' size_ok: check @dest.type = 'reg' & @dest.size = 2 & @dest.rm = 2 & @src.type = 'reg' & @src.rm = 0 jyes out_dx_ax check @dest.type = 'imm' & @src.type = 'reg' & @src.rm = 0 jyes out_imm_ax err 'invalid combination of operands' exit out_dx_ax: check @src.size > 1 jno out_dx_al call x86.store_operand_prefix, @src.size emit 1, 0EFh exit out_dx_al: emit 1, 0EEh exit out_imm_ax: check @src.size > 1 jno out_imm_al call x86.store_operand_prefix, @src.size emit 1, 0E7h emit 1, @dest.imm exit out_imm_al: emit 1, 0E6h emit 1, @dest.imm exit end calminstruction calminstruction enter? alloc*,nesting* call x86.require.80186 call x86.parse_operand@src, alloc call x86.parse_operand@aux, nesting check (@src.size and not 2) | (@aux.size and not 1) jno size_ok err 'invalid operand size' size_ok: check @src.type = 'imm' & @aux.type = 'imm' jyes operand_ok err 'invalid operand' exit operand_ok: emit 1, 0C8h call word, @src.imm emit 1, @aux.imm end calminstruction calminstruction bound? dest*,src* call x86.require.80186 check x86.mode < 64 jyes allowed err 'illegal instruction' exit allowed: call x86.parse_operand@dest, dest call x86.parse_operand@src, src check @src.type = 'mem' & @dest.type = 'reg' jno invalid_combination_of_operands check @src.size and not @dest.size jno size_ok err 'operand sizes do not match' size_ok: xcall x86.select_operand_prefix@src, @dest.size xcall x86.store_instruction@src, (62h),@dest.rm exit invalid_combination_of_operands: err 'invalid combination of operands' exit end calminstruction calminstruction arpl? dest*,src* check x86.mode < 64 jyes allowed err 'illegal instruction' exit allowed: call x86.require.80286 call x86.parse_operand@dest, dest call x86.parse_operand@src, src check @src.type = 'reg' & (@dest.type = 'mem' | @dest.type = 'reg') jno invalid_combination_of_operands check @src.size = 2 jno invalid_operand_size check @dest.size and not @src.size jno size_ok err 'operand sizes do not match' jump size_ok invalid_operand_size: err 'invalid operand size' size_ok: xcall x86.store_instruction@dest, (63h),@src.rm exit invalid_combination_of_operands: err 'invalid combination of operands' exit exit end calminstruction iterate , lldt,0,2, ltr,0,3, verr,0,4, verw,0,5, lmsw,1,6 calminstruction instr? dest* call x86.require.80286 call x86.parse_operand@dest, dest check @dest.size and not 2 jno size_ok err 'invalid operand size' size_ok: check @dest.type = 'reg' | @dest.type = 'mem' jyes operand_ok err 'invalid operand' exit operand_ok: xcall x86.store_instruction@dest, <0Fh,ext>,(postbyte) end calminstruction end iterate iterate , sldt,0,0, str,0,1, smsw,1,4 calminstruction instr? dest* call x86.require.80286 call x86.parse_operand@dest, dest check @dest.type = 'reg' jyes select_operand_prefix check @dest.size and not 2 jno size_ok err 'invalid operand size' size_ok: check @dest.type = 'mem' jyes store_instruction err 'invalid combination of operands' exit select_operand_prefix: xcall x86.select_operand_prefix@dest, @dest.size store_instruction: xcall x86.store_instruction@dest, <0Fh,ext>,(postbyte) end calminstruction end iterate iterate , lgdt,2, lidt,3, sgdt,0, sidt,1 calminstruction instr? dest* call x86.require.80286 call x86.parse_operand@dest, dest check @dest.type = 'mem' jyes operand_ok err 'invalid operand' exit operand_ok: check x86.mode = 64 & @dest.size = 10 jyes store_instruction check x86.mode < 64 & @dest.size = 6 jyes o32 check x86.mode < 64 & @dest.size = 5 jyes o16 check @dest.size jno store_instruction err 'invalid operand size' jump store_instruction o16: xcall x86.select_operand_prefix@dest, (2) jump store_instruction o32: xcall x86.select_operand_prefix@dest, (4) store_instruction: xcall x86.store_instruction@dest, <0Fh,1>,(postbyte) end calminstruction end iterate iterate , lar,2, lsl,3 calminstruction instr? dest*,src* call x86.require.80286 call x86.parse_operand@dest, dest call x86.parse_operand@src, src check @dest.type = 'reg' & (@src.type = 'mem' | @src.type = 'reg') jno invalid_combination_of_operands check @src.size and not 2 jno size_ok err 'invalid operand size' size_ok: xcall x86.select_operand_prefix@src, @dest.size xcall x86.store_instruction@src, <0Fh,ext>,@dest.rm exit invalid_combination_of_operands: err 'invalid combination of operands' end calminstruction end iterate iterate , cmpxchg,0B0h, xadd,0C0h calminstruction instr? dest*,src* call x86.require.80486 call x86.parse_operand@dest, dest call x86.parse_operand@src, src check @src.type = 'reg' & ( @dest.type = 'reg' | @dest.type = 'mem' ) jyes xadd_rm_reg err 'invalid combination of operands' exit xadd_rm_reg: check @dest.size and not @src.size jno size_ok err 'operand sizes do not match' size_ok: check @src.size > 1 jno xadd_rm_reg_8bit xcall x86.select_operand_prefix@dest, @src.size xcall x86.store_instruction@dest, <0Fh,ext+1>,@src.rm exit xadd_rm_reg_8bit: xcall x86.store_instruction@dest, <0Fh,ext>,@src.rm end calminstruction end iterate calminstruction cmpxchg8b? dest* call x86.require.P5 call x86.parse_operand@dest, dest check @dest.type = 'mem' jyes operand_ok err 'invalid operand' exit operand_ok: check @dest.size and not 8 jno size_ok err 'invalid operand size' size_ok: xcall x86.store_instruction@dest, <0Fh,0C7h>,(1) end calminstruction calminstruction cmpxchg16b? dest* call x86.require.CMPXCHG16B call x86.parse_operand@dest, dest check @dest.type = 'mem' jyes operand_ok err 'invalid operand' exit operand_ok: check @dest.size and not 16 jno size_ok err 'invalid operand size' size_ok: xcall x86.store_operand_prefix, (8) xcall x86.store_instruction@dest, <0Fh,0C7h>,(1) end calminstruction calminstruction bswap? dest* call x86.require.80486 call x86.parse_operand@dest, dest check @dest.type = 'reg' & @dest.size > 2 jyes operand_ok err 'invalid operand' exit operand_ok: call x86.store_operand_prefix, @dest.size,@dest.rm emit 1, 0Fh emit 1, 0C8h + @dest.rm and 111b end calminstruction calminstruction invlpg? dest* call x86.require.80486 call x86.parse_operand@dest, dest check @dest.type = 'mem' jyes operand_ok err 'invalid operand' exit operand_ok: xcall x86.store_instruction@dest, <0Fh,1>,(7) end calminstruction calminstruction loadall? check x86.cpu = x86.80286.cpu jyes loadall286 check x86.cpu = x86.80386.cpu jyes loadall386 err 'illegal instruction' exit loadall286: emit 1, 0Fh emit 1, 05h exit loadall386: emit 1, 0Fh emit 1, 07h end calminstruction calminstruction xbts? dest*,src*,offs*,len* call x86.requireexact.80386 call x86.parse_operand@dest, dest call x86.parse_operand@src, src call x86.parse_operand@src2, offs call x86.parse_operand@aux, len check @dest.type = 'reg' & (@src.type = 'mem' | @src.type = 'reg') & \ @src2.type = 'reg' & @src2.rm = 0 & @aux.type = 'reg' & @aux.size = 1 & @aux.rm = 1 jno invalid_combination_of_operands check @src.size and not @dest.size | @src2.size <> @dest.size jyes operand_sizes_no_not_match check @dest.size > 1 jyes size_ok err 'invalid operand size' jump size_ok operand_sizes_no_not_match: err 'operand sizes do not match' size_ok: call x86.select_operand_prefix@src, @dest.size xcall x86.store_instruction@src, <0Fh,0A6h>,@dest.rm exit invalid_combination_of_operands: err 'invalid combination of operands' end calminstruction calminstruction ibts? dest*,offs*,len*,src* call x86.requireexact.80386 call x86.parse_operand@dest, dest call x86.parse_operand@src, src call x86.parse_operand@src2, offs call x86.parse_operand@aux, len check @src.type = 'reg' & (@dest.type = 'mem' | @dest.type = 'reg') & \ @src2.type = 'reg' & @src2.rm = 0 & @aux.type = 'reg' & @aux.size = 1 & @aux.rm = 1 jno invalid_combination_of_operands check @dest.size and not @src.size | @src2.size <> @src.size jyes operand_sizes_no_not_match check @src.size > 1 jyes size_ok err 'invalid operand size' jump size_ok operand_sizes_no_not_match: err 'operand sizes do not match' size_ok: call x86.select_operand_prefix@dest, @src.size xcall x86.store_instruction@dest, <0Fh,0A7h>,@src.rm exit invalid_combination_of_operands: err 'invalid combination of operands' end calminstruction calminstruction pause? emit 1, 0F3h emit 1, 90h end calminstruction include 'iset/fpu.inc' iterate , fcmovb,0DAh,0C0h, fcmove,0DAh,0C8h, fcmovbe,0DAh,0D0h, fcmovu,0DAh,0D8h, \ fcmovnb,0DBh,0C0h, fcmovne,0DBh,0C8h, fcmovnbe,0DBh,0D0h, fcmovnu,0DBh,0D8h calminstruction instr? dest*,src* call x86.require.P6 call x87.parse_operand@dest, dest call x87.parse_operand@src, src check @dest.type = 'streg' & @dest.rm = 0 & @src.type = 'streg' jyes ok err 'invalid operand' exit ok: emit 1, opcode emit 1, postbyte + @src.rm end calminstruction end iterate iterate , fucomi,0DBh,5, fucomip,0DFh,5, fcomi,0DBh,6, fcomip,0DFh,6 calminstruction instr? src:st1 call x86.require.P6 call x87.parse_operand@src, src check @src.type = 'streg' jyes ok err 'invalid operand' exit ok: emit 1, opcode emit 1, 11b shl 6 + postbyte shl 3 + @src.rm end calminstruction end iterate calminstruction nop? src match , src jno multibyte emit 1, 90h exit multibyte: call x86.require.P68 call x86.parse_operand@src, src check @src.type = 'mem' | @src.type = 'reg' jyes nop_rm_reg err 'invalid operand' exit nop_rm_reg: xcall x86.select_operand_prefix@src, @src.size xcall x86.store_instruction@src, <0Fh,1Fh>,(0) end calminstruction calminstruction ud2? emit 2, 0B0Fh end calminstruction iterate , fxsave64,0, fxrstor64,1 calminstruction instr? src* call x86.require.x64 call x86.require.bits64 call x86.parse_operand@src, src check @src.type = 'mem' jno invalid_operand check @src.size and not 512 jno size_ok err 'invalid operand size' size_ok: xcall x86.select_operand_prefix@src, (8) xcall x86.store_instruction@src, <0Fh,0AEh>,(postbyte) exit invalid_operand: err 'invalid operand' end calminstruction end iterate iterate , xsave,4, xrstor,5 macro instr? src* require XSAVE x86.parse_operand@src src if @src.type = 'mem' x86.store_instruction@src <0Fh,0AEh>,postbyte else err 'invalid operand' end if end macro macro instr#64? src* require XSAVE require bits64 x86.parse_operand@src src if @src.type = 'mem' x86.select_operand_prefix@src 8 x86.store_instruction@src <0Fh,0AEh>,postbyte else err 'invalid operand' end if end macro end iterate macro xgetbv? require XSAVE db 0Fh,1,0D0h end macro macro xsetbv? require XSAVE db 0Fh,1,0D1h end macro macro getsec? require SMX db 0Fh,37h end macro macro monitor? arg1,arg2,arg3 require MONITOR match any, arg1 arg2 arg3 if ~ arg1 eq eax | ~ arg2 eq ecx | ~ arg3 eq edx err 'invalid combination of operands' end if end match db 0Fh,01h,0C8h end macro macro mwait? arg1,arg2 require MONITOR match any, arg1 arg2 if ~ arg1 eq eax | ~ arg2 eq ecx err 'invalid combination of operands' end if end match db 0Fh,01h,0C9h end macro iterate , rdfsbase,0, rdgsbase,1, wrfsbase,2, wrgsbase,3 macro instr? dest* require FSGSBASE require bits64 x86.parse_operand@dest dest if @dest.type = 'reg' if @dest.size >= 4 @dest.opcode_prefix = 0F3h x86.select_operand_prefix@dest @dest.size x86.store_instruction@dest <0Fh,0AEh>,postbyte else err 'invalid operand size' end if else err 'invalid operand' end if end macro end iterate macro rdrand? dest* require RDRAND x86.parse_operand@dest dest if @dest.type = 'reg' x86.select_operand_prefix@dest @dest.size x86.store_instruction@dest <0Fh,0C7h>,6 else err 'invalid operand' end if end macro macro rdseed? dest* require RDSEED x86.parse_operand@dest dest if @dest.type = 'reg' x86.select_operand_prefix@dest @dest.size x86.store_instruction@dest <0Fh,0C7h>,7 else err 'invalid operand' end if end macro include 'iset/vmx.inc' include 'iset/mpx.inc' include 'iset/cet.inc' macro xacquire? instr& require HLE db 0F2h instr end macro macro xrelease? instr& require HLE db 0F3h instr end macro macro xtest? require HLE db 0Fh,1,0D6h end macro macro xbegin? dest* require RTM x86.parse_jump_operand@dest dest if @dest.type = 'imm' & ~ @dest.jump_type if x86.mode shr 3 <> @dest.size err 'invalid operand size' end if if x86.mode = 16 db 0C7h,0F8h dw @dest.imm-($+2) else if ~ $ relativeto 0 & @dest.imm relativeto 0 @dest.imm = @dest.imm + $ - 0 scaleof $ err 'invalid address' end if if @dest.unresolved | ( @dest.imm relativeto $ & @dest.imm-($+5) < 8000h & @dest.imm-($+5) >= -8000h ) db 66h,0C7h,0F8h dw @dest.imm-($+2) else db 0C7h,0F8h dd @dest.imm-($+4) end if end if else err 'invalid operand' end if end macro macro xabort? imm* require RTM db 0C6h,0F8h,imm end macro macro xend? require RTM db 0Fh,1,0D5h end macro macro xtest? require RTM db 0Fh,1,0D6h end macro iterate , adcx,66h, adox,0F3h macro instr? dest*,src* require ADX x86.parse_operand@dest dest x86.parse_operand@src src if @dest.type = 'reg' & (@src.type = 'mem' | @src.type = 'reg') if @src.size <> 0 & @src.size <> @dest.size err 'operand sizes do not match' end if if @dest.size = 8 & x86.mode = 64 @src.prefix = 48h else if @dest.size <> 4 err 'invalid operand size' end if @src.opcode_prefix = pfx x86.store_instruction@src <0Fh,38h,0F6h>,@dest.rm else err 'invalid combination of operands' end if end macro end iterate macro movbe? dest*,src* require MOVBE x86.parse_operand@dest dest x86.parse_operand@src src if @dest.size & @src.size & @src.size <> @dest.size err 'operand sizes do not match' end if if @dest.type = 'reg' & @src.type = 'mem' & @dest.size > 1 x86.select_operand_prefix@src @dest.size x86.store_instruction@src <0Fh,38h,0F0h>,@dest.rm else if @dest.type = 'mem' & @src.type = 'reg' & @src.size > 1 x86.select_operand_prefix@dest @src.size x86.store_instruction@dest <0Fh,38h,0F1h>,@src.rm else err 'invalid combination of operands' end if end macro macro movdiri? dest*,src* require MOVDIRI x86.parse_operand@dest dest x86.parse_operand@src src if @src.type = 'reg' & @dest.type = 'mem' if @dest.size <> 0 & @src.size <> @dest.size err 'operand sizes do not match' end if if @src.size = 8 & x86.mode = 64 @dest.prefix = 48h else if @src.size <> 4 err 'invalid operand size' end if x86.store_instruction@dest <0Fh,38h,0F9h>,@src.rm else err 'invalid combination of operands' end if end macro macro movdir64b? dest*,src* require MOVDIR64B x86.parse_operand@dest dest x86.parse_operand@src src if @dest.type = 'reg' & @src.type = 'mem' if @src.size and not 64 err 'invalid operand size' end if if (@src.mode = 16 & @dest.size <> 2) | (@src.mode = 32 & @dest.size <> 4) | (@src.mode = 64 & @dest.size <> 8) err 'invalid operand size' end if @src.opcode_prefix = 66h x86.store_instruction@src <0Fh,38h,0F8h>,@dest.rm else err 'invalid combination of operands' end if end macro include 'iset/mmx.inc' include 'iset/sse.inc' include 'iset/sse2.inc' include 'iset/sse3.inc' include 'iset/sse4.inc' include 'iset/avx.inc' include 'iset/bmi.inc' include 'iset/aes.inc' include 'iset/gfni.inc' include 'iset/pclmulqdq.inc' include 'iset/3dnow.inc'