define x86 x86 element x86.reg element x86.r8 : x86.reg + 1 element x86.r16 : x86.reg + 2 element x86.r32 : x86.reg + 4 element al? : x86.r8 + 0 element cl? : x86.r8 + 1 element dl? : x86.r8 + 2 element bl? : x86.r8 + 3 element ah? : x86.r8 + 4 element ch? : x86.r8 + 5 element dh? : x86.r8 + 6 element bh? : x86.r8 + 7 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 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 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 element x86.trx : x86.creg + 4 repeat 8, i:0 element cr#i? : x86.crx + i element dr#i? : x86.drx + i element tr#i? : x86.trx + 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 x86.mode = 16 macro use16? x86.mode = 16 end macro macro use32? x86.mode = 32 end macro calminstruction calminstruction?.initsym? var*, val& publish var, val end calminstruction calminstruction calminstruction?.asm? line& local name, i initsym name, name.0 match name.i, name compute i, i+1 arrange name, name.i publish name, line arrange line, =assemble name assemble line end calminstruction calminstruction calminstruction?.xcall? instruction*, arguments& arrange instruction, =call instruction convert: match , arguments jyes ready local v match v=,arguments, arguments, <> jyes recognize arrange v, arguments arrange arguments, recognize: match (v), v jyes numeric match , v jyes symbolic append: arrange instruction, instruction=,v jump convert numeric: compute v, v symbolic: local proxy, base, i initsym base, proxy initsym i, 0 compute i, i+1 arrange proxy, base.i publish proxy, v arrange instruction, instruction=,proxy jump convert ready: assemble instruction end calminstruction 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, \ imm, unresolved, displacement, displacement_size, \ 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 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 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 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: 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 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 check mode jyes verify_mode compute mode, x86.mode check mode = 16 & displacement relativeto 0 & displacement >= 10000h & address_registers eq 0 jno mode_ok compute mode, 32 jump mode_ok verify_mode: check (mode = 16 & 1 metadataof address_registers relativeto x86.r32) | (mode = 32 & 1 metadataof address_registers relativeto x86.r16) jyes invalid_address mode_ok: check address_registers eq 0 jyes direct_address check 1 metadataof address_registers relativeto x86.r32 jyes address_32bit check 1 metadataof address_registers relativeto x86.r16 jyes address_16bit jump invalid_address direct_address: compute mod, 0 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 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: compute mode,32 check 2 scaleof address_registers = 0 jyes one_register check 3 scaleof address_registers = 0 & 2 metadataof address_registers relativeto x86.r32 jyes two_registers jump invalid_address one_register: compute scale, 1 scaleof address_registers compute base, 1 metadataof address_registers - x86.r32 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: compute rm, base check rm = 4 jno setup_displacement 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 - x86.r32 compute index, 2 metadataof address_registers - x86.r32 compute scale, 2 scaleof address_registers jump process_sib base_second: compute base, 2 metadataof address_registers - x86.r32 compute index, 1 metadataof address_registers - x86.r32 compute scale, 1 scaleof address_registers process_sib: check index = 4 jyes forbidden_index check segment_prefix = 36h & index = 5 & scale = 1 jyes switch_to_index check 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 <> 5 & (rm <> 4 | base <> 5) jyes displacement_empty check displacement < 80h & displacement >= -80h jyes displacement_8bit check displacement-100000000h >= -80h & displacement < 100000000h jyes displacement_8bit_wrap_32bit check 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_32bit: compute displacement, displacement-100000000h jump displacement_8bit index_only: compute displacement_size, 4 compute mod, 0 exit far_operand: compute type, 'far' check size & size <> 4 & size <> 6 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 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 = 2 & x86.mode = 32) | (size = 4 & x86.mode = 16) jno no_prefix compute prefix, 66h no_prefix: check size <> 0 & size <> 2 & size <> 4 jno done err 'invalid operand size' done: end calminstruction calminstruction x86.store_instruction#context opcode*,reg*,imm_size:0,immediate check segment_prefix jno segment_prefix_ok 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 store_segment_prefix: emit 1, segment_prefix segment_prefix_ok: check mod <> 11b & mode <> x86.mode jno addressing_prefix_ok emit 1, 67h addressing_prefix_ok: 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: asm db opcode emit 1, mod shl 6 + (reg and 111b) shl 3 + rm and 111b check mod <> 11b & rm = 4 & mode = 32 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 jno displacement_ok displacement_32bit: asm dd displacement jump displacement_ok displacement_16bit: asm dw 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 jno immediate_ok immediate_32bit: compute imm, +immediate asm dd imm jump immediate_ok immediate_16bit: compute imm, +immediate asm dw imm jump immediate_ok immediate_8bit: compute imm, +immediate emit 1, imm jump immediate_ok immediate_ok: end calminstruction end namespace end iterate calminstruction x86.store_operand_prefix size* check (size = 2 & x86.mode = 32) | (size = 4 & x86.mode = 16) jno no_prefix emit 1, 66h exit no_prefix: check size <> 0 & size <> 2 & size <> 4 jno done err 'invalid operand size' done: 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' | @dest.type = 'mem' ) jyes reg_rm check @src.type = 'mem' & @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 @src.imm relativeto 0 & @src.imm<80h & @src.imm>=-80h jyes rm_simm check size = 2 & @src.imm relativeto 0 & @src.imm-10000h>=-80h & @src.imm<10000h jyes rm_simm_wrap check size = 4 & @src.imm relativeto 0 & @src.imm-100000000h>=-80h & @src.imm<100000000h 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 asm dw @src.imm exit imm32: asm dd @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' | @dest.type = 'mem' ) jyes mov_rm_reg check @src.type = 'mem' & @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 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 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 @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 asm dd @dest.address exit dest_displacement_16bit: asm dw @dest.address exit mov_ax_dirmem: 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 asm dd @src.address exit src_displacement_16bit: asm dw @src.address exit 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 call x86.store_operand_prefix, size emit 1, 0B8h + @dest.rm check size = 2 jyes src_imm_16bit asm dd @src.imm exit src_imm_16bit: asm dw @src.imm exit mov_reg_imm_8bit: emit 1, 0B0h + @dest.rm emit 1, @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 @dest.size = 4 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 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 @src.size = 4 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 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 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' | @dest.type = 'mem' ) jyes test_reg_rm check @src.type = 'mem' & @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 asm dd @src.imm exit src_imm_16bit: asm dw @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 = 0 | @dest.rm = 0 jno xchg_rm_reg check size > 1 jno xchg_rm_reg_8bit call x86.store_operand_prefix, size emit 1, 90h + @src.rm + @dest.rm 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,00 ,dec,01 calminstruction instr? dest* call x86.parse_operand@dest, dest check @dest.size jyes main err 'operand size not specified' main: check @dest.type = 'reg' jyes inc_reg check @dest.type = 'mem' jyes inc_rm 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 + 0x#postbyte shl 3 exit inc_rm: check @dest.size > 1 jno inc_rm_8bit call 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 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 call 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 size = 2 & @aux.imm relativeto 0 & @aux.imm - 10000h >= -80h & @aux.imm < 10000h jyes imul_reg_rm_simm_wrap check size = 4 & @aux.imm relativeto 0 & @aux.imm - 100000000h >= -80h & @aux.imm < 100000000h 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 jyes main invalid_operand_size: err 'invalid operand size' main: check @src.type = 'mem' jyes push_mem check @src.type = 'reg' jyes push_reg check @src.type = 'sreg' jyes push_sreg check @src.type = 'imm' jyes push_imm err 'invalid operand' exit push_mem: call x86.select_operand_prefix@src, size xcall x86.store_instruction@src, (0FFh),(110b) exit push_reg: call x86.store_operand_prefix, size emit 1, 50h + @src.rm exit push_sreg: call x86.store_operand_prefix, size check @src.rm >= 4 jyes push_sreg_386 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: check size jyes push_imm_size_ok check x86.mode = 16 jyes push_imm_16bit compute size, 4 jump push_imm_size_ok push_imm_16bit: compute size, 2 push_imm_size_ok: call x86.store_operand_prefix, size check @src.imm eqtype 0.0 jno push_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 push_imm_optimize: check @src.imm relativeto 0 & @src.imm < 80h & @src.imm >= -80h jyes push_simm check size = 2 & @src.imm relativeto 0 & @src.imm - 10000h >= -80h & @src.imm < 10000h jyes push_simm_wrap check 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 asm dd @src.imm exit src_imm_16bit: asm dw @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 jyes main invalid_operand_size: err 'invalid operand size' main: check @dest.type = 'mem' jyes pop_mem check @dest.type = 'reg' jyes pop_reg check @dest.type = 'sreg' jyes pop_sreg invalid_operand: err 'invalid operand' exit pop_mem: call x86.select_operand_prefix@dest, size xcall x86.store_instruction@dest, (8Fh),(0) exit pop_reg: call x86.store_operand_prefix, size emit 1, 58h + @dest.rm exit pop_sreg: check @dest.rm = 1 jyes invalid_operand call x86.store_operand_prefix, size check @dest.rm >= 4 jyes pop_sreg_386 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, eax,ecx,edx,ebx,esp,ebp,esi,edi, 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, \ pop,pop_instruction,0, popw,pop_instruction,2, popd,pop_instruction,4 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 asm dw 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 xcall x86.store_operand_prefix, (size) match , operand jyes ret_short emit 1, opcode asm dw operand exit ret_short: emit 1, opcode + 1 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 call 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, lss,<0Fh,0B2h>, lfs,<0Fh,0B4h>, lgs,<0Fh,0B5h> calminstruction instr? dest*,src* 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 call x86.select_operand_prefix@src, @dest.size xcall x86.store_instruction@src, ,@dest.rm exit invalid_operand_size: err 'invalid operand size' exit 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 call 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 call x86.select_operand_prefix@dest, @dest.size check @src.imm = 1 jyes shift_rm_1 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 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.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: call x86.select_operand_prefix@dest, @src.size xcall x86.store_instruction@dest, <0Fh,ext+1>,@src.rm exit shld_imm: call 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.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 call 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 bt_rm_imm_prefix_ok call x86.select_operand_prefix@dest, @dest.size bt_rm_imm_prefix_ok: xcall x86.store_instruction@dest, <0Fh,0BAh>,(postbyte),byte,@src.imm end calminstruction end iterate iterate , bsf,0BCh, bsr,0BDh calminstruction instr? dest*,src* call x86.parse_operand@dest, dest call x86.parse_operand@src, src check @dest.type = 'reg' & (@src.type = 'mem' | @src.type = 'reg') jyes bsf_reg_rm err 'invalid combination of operands' exit bsf_reg_rm: check @src.size and not @dest.size jno bsf_reg_rm_ok err 'operand sizes do not match' bsf_reg_rm_ok: call 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.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: call x86.select_operand_prefix@src, @dest.size xcall x86.store_instruction@src, <0Fh,ext+1>,@dest.rm exit movzx_byte: call 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 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.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 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 call_direct_far: check @dest.jump_type & @dest.jump_type <> 'far' jyes invalid_operand 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 asm dd @dest.offset asm dw @dest.segment exit far_dword: asm dw @dest.offset,@dest.segment exit call_rm: check @dest.size = 6 jyes call_rm_pword check @dest.size = 4 jyes call_rm_dword check @dest.size = 2 jyes call_rm_word check @dest.size jyes invalid_operand 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 xcall x86.select_operand_prefix@dest, (4) call_rm_far: xcall x86.store_instruction@dest, (0FFh),(11b) exit 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 = 2 jyes call_imm_word check @dest.size = 4 jno invalid_operand xcall x86.store_operand_prefix, (4) emit 1, 0E8h compute @dest.imm, @dest.imm-($+4) asm dd @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: asm dw @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 jmp_direct_far: check @dest.jump_type & @dest.jump_type <> 'far' jyes invalid_operand 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 asm dd @dest.offset asm dw @dest.segment exit far_dword: asm dw @dest.offset,@dest.segment exit jmp_rm: check @dest.size = 6 jyes jmp_rm_pword check @dest.size = 4 jyes jmp_rm_dword check @dest.size = 2 jyes jmp_rm_word check @dest.size jyes invalid_operand 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 xcall x86.select_operand_prefix@dest, (4) jmp_rm_far: xcall x86.store_instruction@dest, (0FFh),(101b) exit 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: call x86.store_operand_prefix, @dest.size check @dest.jump_type = 'near' jyes jmp_imm_near check @dest.jump_type = 'short' jyes jmp_imm_short_verify check @dest.jump_type jyes invalid_operand 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 = 2 jyes jmp_imm_word check @dest.size = 4 jno invalid_operand emit 1, 0E9h compute @dest.imm, @dest.imm-($+4) asm dd @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: asm dw @dest.imm 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 jump relative_jump_out_of_range jmp_imm_short: emit 1, 0EBh compute @dest.imm, (@dest.imm-($+1)) and 0FFh emit 1, @dest.imm exit relative_jump_out_of_range: err 'relative jump out of range' 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 call x86.store_operand_prefix, @dest.size 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' & ( @dest.unresolved | ( @dest.imm relativeto $ & @dest.imm-($+2) < 80h & @dest.imm-($+2) >= -80h ) ) jyes short check @dest.jump_type <> 'near' & @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' jyes relative_jump_out_of_range emit 1, 0Fh emit 1, 10h+opcode check @dest.size = 2 jyes relative_word compute @dest.imm, @dest.imm-($+4) asm dd @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: asm dw @dest.imm exit short: compute @dest.imm, (@dest.imm-($+2)) and 0FFh emit 1, opcode emit 1, @dest.imm exit relative_jump_out_of_range: emit 2 err 'relative jump out of range' 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, \ jcxz,0E3h,2, jecxz,0E3h,4 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 emit 1, 67h address_prefix_ok: check @dest.size shl 3 <> x86.mode jno operand_prefix_ok 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 invalid_operand: err 'invalid operand' exit end calminstruction end iterate iterate , daa,27h, das,2Fh, aaa,37h, aas,3Fh, nop,90h, int3,0CCh, into,0CEh, int1,0F1h, iret,0CFh, salc,0D6h, \ hlt,0F4h, cmc,0F5h, clc,0F8h, stc,0F9h, cli,0FAh, sti,0FBh, cld,0FCh, std,0FDh, \ pusha,60h, popa,61h, pushf,9Ch, popf,9Dh, sahf,9Eh, lahf,9Fh, leave,0C9h, \ insb,6Ch, outsb,6Eh, movsb,0A4h, cmpsb,0A6h, stosb,0AAh, lodsb,0ACh, scasb,0AEh, xlatb,0D7h, \ clts,<0Fh,06h>, loadall,<0Fh,07h> match byte1=,byte2, opcode calminstruction instr? emit 1, byte1 emit 1, byte2 end calminstruction else calminstruction instr? emit 1, opcode end calminstruction end match end iterate iterate , cbw,98h, cwd,99h, iretw,0CFh, pushaw,60h, popaw,61h, pushfw,9Ch, popfw,9Dh, \ insw,6Dh, outsw,6Fh, 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, pushad,60h, popad,61h, pushfd,9Ch, popfd,9Ch, \ insd,6Dh, outsd,6Fh, 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 , 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 aam? number:10 emit 1, 0D4h emit 1, number end calminstruction calminstruction aad? number:10 emit 1, 0D5h emit 1, number end calminstruction if defined SSE2 purge movsd?, cmpsd? end if 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 & ( (@src.mode = 16 & @src.rm = 4 & @dest.mode = 16 & @dest.rm = 5) | (@src.mode = 32 & @src.rm = 6 & @dest.mode = 32 & @dest.rm = 7) ) & ( @dest.segment_prefix = 0 | @dest.segment_prefix = 26h ) jno invalid_combination_of_operands check @src.segment_prefix = 0 | @src.segment_prefix = 3Eh 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 & ( (@src.mode = 16 & @src.rm = 4 & @dest.mode = 16 & @dest.rm = 5) | (@src.mode = 32 & @src.rm = 6 & @dest.mode = 32 & @dest.rm = 7) ) & ( @dest.segment_prefix = 0 | @dest.segment_prefix = 26h ) jno invalid_combination_of_operands check @src.segment_prefix = 0 | @src.segment_prefix = 3Eh 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 & ( (@dest.mode = 16 & @dest.rm = 5) | (@dest.mode = 32 & @dest.rm = 7) ) & ( @dest.segment_prefix = 0 | @dest.segment_prefix = 26h ) 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 & ( (@src.mode = 16 & @src.rm = 4) | (@src.mode = 32 & @src.rm = 6) ) jno invalid_operand check @src.segment_prefix = 0 | @src.segment_prefix = 3Eh 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 & ( (@dest.mode = 16 & @dest.rm = 5) | (@dest.mode = 32 & @dest.rm = 7) ) & ( @dest.segment_prefix = 0 | @dest.segment_prefix = 26h ) 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.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 & ( (@dest.mode = 16 & @dest.rm = 5) | (@dest.mode = 32 & @dest.rm = 7) ) & ( @dest.segment_prefix = 0 | @dest.segment_prefix = 26h ) 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.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 & ( (@src.mode = 16 & @src.rm = 4) | (@src.mode = 32 & @src.rm = 6) ) jno invalid_combination_of_operands check @src.segment_prefix = 0 | @src.segment_prefix = 3Eh 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 & ( (@src.mode = 16 & @src.rm = 7) | (@src.mode = 32 & @src.rm = 3) ) jno invalid_operand check @src.segment_prefix = 0 | @src.segment_prefix = 3Eh 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 jyes size_ok err 'operand size not specified' 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 jyes size_ok err 'operand size not specified' 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.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 asm dw @src.imm emit 1, @aux.imm end calminstruction calminstruction bound? 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 check @src.size and not @dest.size jno size_ok err 'operand sizes do not match' size_ok: call 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' end calminstruction calminstruction arpl? dest*,src* 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' end calminstruction iterate , lldt,0,2, ltr,0,3, verr,0,4, verw,0,5, lmsw,1,6 calminstruction instr? dest* 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.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: call 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.parse_operand@dest, dest check @dest.type = 'mem' jyes operand_ok err 'invalid operand' exit operand_ok: check @dest.size = 6 jyes o32 check @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.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: call 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 calminstruction xbts? dest*,src*,offs*,len* 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.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