define x86 x86 element x86.reg element x86.r8 : x86.reg + 1 element x86.r16 : x86.reg + 2 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 x86.sreg element es? : x86.sreg + 0 element cs? : x86.sreg + 1 element ss? : x86.sreg + 2 element ds? : x86.sreg + 3 define x86.byte? :1 define x86.word? :2 define x86.dword? :4 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 @aux @aux iterate context, @dest,@src,@src2,@aux namespace context iterate name, size, type, segment_prefix, \ imm, unresolved, displacement, displacement_size, \ address, address_registers, segment, offset, jump_type, \ mod, rm, define name end iterate calminstruction x86.parse_operand#context operand local i, pre, suf, sym compute segment_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 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 mod, 11b compute rm, 1 metadataof imm - x86.sreg check size and not 2 jyes operand_sizes_do_not_match compute size, 2 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 compute segment_prefix, 26h + segment shl 3 segment_prefix_ok: 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 address_registers eq 0 jyes direct_address 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 direct_address: compute mod, 0 compute rm, 6 compute displacement_size, 2 exit 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 far_operand: compute type, 'far' check size and not 4 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 end calminstruction calminstruction x86.store_instruction#context opcode*,reg*,imm_size:0,immediate check segment_prefix jno segment_prefix_ok check rm = 2 | rm = 3 | ( mod > 0 & rm = 6 ) 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: emit 1, opcode emit 1, mod shl 6 + reg shl 3 + rm check displacement_size = 1 jyes displacement_8bit check displacement_size = 2 jno 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 jno immediate_ok immediate_16bit: compute imm, +immediate asm dw imm jump immediate_ok immediate_8bit: compute imm, +immediate emit 1, imm immediate_ok: end calminstruction end namespace end iterate 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 check size > 2 jyes invalid_operand_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 invalid_operand_size: err 'invalid operand size' compute size, 0 jump main reg_rm: check size = 2 jno reg_rm_store compute opcode, opcode + 1 reg_rm_store: call x86.store_instruction@dest, opcode,@src.rm exit rm_reg: compute opcode, opcode + 2 check size = 2 jno rm_reg_store compute opcode, opcode + 1 rm_reg_store: call x86.store_instruction@src, opcode,@dest.rm exit rm_imm: check size = 2 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: check @src.imm relativeto 0 & @src.imm<80h & @src.imm>=-80h jyes rm_simm check @src.imm relativeto 0 & @src.imm-10000h>=-80h & @src.imm<10000h 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: emit 1, opcode+5 asm dw @src.imm exit rm_simm_wrap: compute @src.imm, @src.imm - 10000h 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, imul,5, div,6, idiv,7 calminstruction instr? src* call x86.parse_operand@src, src check @src.size = 0 jyes operand_size_not_specified check @src.size > 2 jyes invalid_operand_size main: check @src.type = 'mem' | @src.type = 'reg' jno invalid_operand check @src.size = 2 jyes rm_word xcall x86.store_instruction@src, (0F6h),(postbyte) exit rm_word: xcall x86.store_instruction@src, (0F7h),(postbyte) exit operand_size_not_specified: err 'operand size not specified' jump main invalid_operand_size: err 'invalid operand size' 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 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 size > 2 jyes invalid_operand_size main: check @src.type = 'reg' & ( @dest.type = 'reg' | @dest.type = 'mem' ) jyes mov_reg_rm check @src.type = 'mem' & @dest.type = 'reg' jyes mov_mem_reg check @src.type = 'imm' & ( @dest.type = 'reg' | @dest.type = 'mem' ) jyes mov_rm_imm 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 invalid_operand_size: err 'invalid operand size' compute size, 0 jump main mov_reg_rm: check @src.type = 'reg' & @dest.type = 'mem' & @src.rm = 0 & @dest.address_registers eq 0 jyes mov_ax_dirmem check size < 2 jyes mov_reg_rm_8bit xcall x86.store_instruction@dest, (89h),@src.rm exit mov_reg_rm_8bit: xcall x86.store_instruction@dest, (88h),@src.rm exit mov_mem_reg: check @src.type = 'mem' & @dest.type = 'reg' & @dest.rm = 0 & @src.address_registers eq 0 jyes mov_dirmem_ax check size < 2 jyes mov_mem_reg_8bit xcall x86.store_instruction@src, (8Bh),@dest.rm exit mov_mem_reg_8bit: xcall x86.store_instruction@src, (8Ah),@dest.rm exit mov_ax_dirmem: check @dest.segment_prefix = 0 | @dest.segment_prefix = 3Eh jyes dest_seg_ok emit 1, @dest.segment_prefix dest_seg_ok: check size < 2 jyes mov_al_dirmem emit 1, 0A3h asm dw @dest.address exit mov_al_dirmem: emit 1, 0A2h asm dw @dest.address exit mov_dirmem_ax: check @src.segment_prefix = 0 | @src.segment_prefix = 3Eh jyes src_seg_ok emit 1, @src.segment_prefix src_seg_ok: check size < 2 jyes mov_dirmem_al emit 1, 0A1h asm dw @src.address exit mov_dirmem_al: emit 1, 0A0h asm dw @src.address exit mov_rm_imm: check @dest.type = 'mem' jyes mov_mem_imm mov_reg_imm: check size < 2 jyes mov_reg_imm_8bit emit 1, 0B8h + @dest.rm asm dw @src.imm exit mov_reg_imm_8bit: emit 1, 0B0h + @dest.rm emit 1, @src.imm exit mov_mem_imm: check size < 2 jyes mov_mem_imm_8bit 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_rm_sreg: check size < 2 jyes invalid_operand_size xcall x86.store_instruction@dest, (8Ch),@src.rm exit mov_sreg_rm: check size < 2 jyes invalid_operand_size xcall x86.store_instruction@src, (8Eh),@dest.rm 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 check size > 2 jyes invalid_operand_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 invalid_operand_size: err 'invalid operand size' compute size, 0 jump main test_reg_rm: check size < 2 jyes test_reg_rm_8bit 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 < 2 jyes test_mem_reg_8bit 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 < 2 jyes test_rm_imm_8bit check @dest.type = 'reg' & @dest.rm = 0 jyes test_ax_imm xcall x86.store_instruction@dest, (0F7h),(0),size,@src.imm exit test_ax_imm: emit 1, 0A9h 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 check size > 2 jyes invalid_operand_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 invalid_operand_size: err 'invalid operand size' compute size, 0 jump main xchg_reg_reg: check @src.rm = 0 | @dest.rm = 0 jno xchg_rm_reg check size < 2 jyes xchg_rm_reg_8bit emit 1, 90h + @src.rm + @dest.rm exit xchg_reg_rm: check size < 2 jyes xchg_reg_rm_8bit 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 < 2 jyes xchg_rm_reg_8bit 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 > 2 jyes invalid_operand_size check @dest.size jyes main err 'operand size not specified' jump main invalid_operand_size: err 'invalid operand size' jump main main: check @dest.type = 'reg' jyes inc_reg check @dest.type = 'mem' jyes inc_rm err 'invalid operand' exit inc_reg: check @dest.size < 2 jyes inc_rm_8bit emit 1, 40h + @dest.rm + postbyte shl 3 exit inc_rm: check @dest.size < 2 jyes inc_rm_8bit xcall x86.store_instruction@dest, (0FFh),(postbyte) exit inc_rm_8bit: xcall x86.store_instruction@dest, (0FEh),(postbyte) end calminstruction end iterate calminstruction push? src* call x86.parse_operand@src, src check @src.size and not 2 jno main 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 err 'invalid operand' exit push_mem: xcall x86.store_instruction@src, (0FFh),(110b) exit push_reg: emit 1, 50h + @src.rm exit push_sreg: emit 1, 6 + @src.rm shl 3 exit end calminstruction calminstruction pop? dest* call x86.parse_operand@dest, dest check @dest.size and not 2 jno main 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: xcall x86.store_instruction@dest, (8Fh),(0) exit pop_reg: emit 1, 58h + @dest.rm exit pop_sreg: emit 1, 7 + @dest.rm shl 3 exit end calminstruction iterate reg, ax,cx,dx,bx,sp,bp,si,di, es,cs,ss,ds define x86.compact.reg? {reg} end iterate iterate , push,pop calminstruction instr? operand local head, tail match head tail, operand jno plain transform head, x86.compact jno plain match {head}, head jno plain loop: arrange operand, =instr head assemble operand 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: arrange operand, =instr operand assemble 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 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 check @dest.size = 2 jyes ok err 'invalid operand size' ok: 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* call x86.parse_operand@dest, dest call x86.parse_operand@src, src check @dest.size and not 2 | @src.size and not 4 jyes invalid_operand_size check @src.type = 'mem' & @dest.type = 'reg' jno invalid_combination_of_operands xcall x86.store_instruction@src, (opcode),@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 @dest.size > 2 jyes invalid_operand_size 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 < 2 jyes shift_r8_cl xcall x86.store_instruction@dest, (0D3h),(postbyte) exit shift_r8_cl: xcall x86.store_instruction@dest, (0D2h),(postbyte) exit shift_rm_imm: compute @src.imm, @src.imm and (1 shl (@dest.size shl 3) - 1) check @dest.size < 2 jyes shift_rm8_imm shift_rm16_imm: check @src.imm jno done xcall x86.store_instruction@dest, (0D1h),(postbyte) compute @src.imm, @src.imm - 1 jump shift_rm16_imm shift_rm8_imm: check @src.imm jno done xcall x86.store_instruction@dest, (0D0h),(postbyte) compute @src.imm, @src.imm - 1 jump shift_rm8_imm done: 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 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 and not 4 jyes invalid_operand emit 1, 9Ah asm dw @dest.offset,@dest.segment exit call_rm: 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_dword: check @dest.jump_type & @dest.jump_type <> 'far' jyes invalid_operand call_rm_far: xcall x86.store_instruction@dest, (0FFh),(11b) exit call_rm_word: check @dest.jump_type & @dest.jump_type <> 'near' jyes invalid_operand 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.imm relativeto 0 & (@dest.imm < 0 | @dest.imm >= 10000h) jyes value_out_of_range emit 1, 0E8h compute @dest.imm, @dest.imm-($+2) asm dw @dest.imm exit value_out_of_range: err 'value out of range' 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 and not 4 jyes invalid_operand emit 1, 0EAh asm dw @dest.offset,@dest.segment exit jmp_rm: 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_dword: check @dest.jump_type & @dest.jump_type <> 'far' jyes invalid_operand jmp_rm_far: xcall x86.store_instruction@dest, (0FFh),(101b) exit jmp_rm_word: check @dest.jump_type & @dest.jump_type <> 'near' jyes invalid_operand jmp_rm_near: xcall x86.store_instruction@dest, (0FFh),(100b) exit jmp_imm: check @dest.imm relativeto 0 & (@dest.imm < 0 | @dest.imm >= 10000h) jyes value_out_of_range 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)) and 0FFFFh < 80h | (@dest.imm-($+2)) and 0FFFFh >= 0FF80h jyes jmp_imm_short jmp_imm_near: emit 1, 0E9h compute @dest.imm, @dest.imm-($+2) asm dw @dest.imm exit jmp_imm_short_verify: check (@dest.imm-($+2)) and 0FFFFh < 80h | (@dest.imm-($+2)) and 0FFFFh >= 0FF80h jno 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: emit 2 err 'relative jump out of range' exit value_out_of_range: err 'value out of range' end calminstruction x86.jumps = 0 calminstruction jumps? compute x86.jumps, 1 end calminstruction calminstruction nojumps? compute x86.jumps, 0 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 & @dest.jump_type <> 'short' ) jyes invalid_operand check @dest.imm relativeto 0 & (@dest.imm < 0 | @dest.imm >= 10000h) jyes value_out_of_range check @dest.unresolved | ( @dest.imm-($+2) < 80h & @dest.imm-($+2) >= -80h ) jyes in_range check (@dest.imm-($+2)) and 0FFFFh < 80h | (@dest.imm-($+2)) and 0FFFFh >= 0FF80h jyes in_range check x86.jumps & ~ @dest.jump_type jyes trampoline emit 1 emit 1 err 'relative jump out of range' exit in_range: compute @dest.imm, (@dest.imm-($+2)) and 0FFh emit 1, opcode emit 1, @dest.imm exit trampoline: emit 1, opcode xor 1 emit 1, 3 emit 1, 0E9h compute @dest.imm, @dest.imm-($+2) asm dw @dest.imm exit invalid_operand: err 'invalid operand' exit value_out_of_range: err 'value out of range' end calminstruction end iterate iterate , loopnz,0E0h, loopne,0E0h, loopz,0E1h, loope,0E1h, loop,0E2h, jcxz,0E3h calminstruction instr? dest* call x86.parse_jump_operand@dest, dest check @dest.type = 'imm' & ( @dest.jump_type = 'short' | ~ @dest.jump_type ) jno invalid_operand emit 1, opcode check @dest.imm-($+1) < 80h & @dest.imm-($+1) >= -80h jyes relative_offset_ok check (@dest.imm-($+2)) and 0FFFFh < 80h | (@dest.imm-($+2)) and 0FFFFh >= 0FF80h 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, cbw,98h, cwd,99h, \ int3,0CCh, into,0CEh, iret,0CFh, 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, \ movsw,0A5h, cmpsw,0A7h, stosw,0ABh, lodsw,0ADh, scasw,0AFh calminstruction instr? 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 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 & @src.rm = 4 & @dest.type = 'mem' & @dest.mod = 0 & @dest.rm = 5 & ( @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 size = 2 jyes movs_word emit 1, 0A4h exit movs_word: 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 & @src.rm = 4 & @dest.type = 'mem' & @dest.mod = 0 & @dest.rm = 5 & ( @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 size = 2 jyes cmps_word emit 1, 0A6h exit cmps_word: 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.rm = 5 & ( @dest.segment_prefix = 0 | @dest.segment_prefix = 26h ) jno invalid_operand check @dest.size = 2 jyes stos_word emit 1, 0AAh exit stos_word: 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.rm = 4 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.size = 2 jyes lods_word emit 1, 0ACh exit lods_word: 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.rm = 5 & ( @dest.segment_prefix = 0 | @dest.segment_prefix = 26h ) jno invalid_operand check @dest.size = 2 jyes scas_word emit 1, 0AEh exit scas_word: emit 1, 0AFh exit invalid_operand: err 'invalid operand' 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.rm = 7 jno invalid_operand check @src.segment_prefix = 0 | @src.segment_prefix = 3Eh jyes segment_prefix_ok emit 1, @src.segment_prefix segment_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 = 2 jno in_al_dx emit 1, 0EDh exit in_al_dx: emit 1, 0ECh exit in_ax_imm: check @dest.size = 2 jno in_al_imm 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 = 2 jno out_dx_al emit 1, 0EFh exit out_dx_al: emit 1, 0EEh exit out_imm_ax: check @src.size = 2 jno out_imm_al emit 1, 0E7h emit 1, @dest.imm exit out_imm_al: emit 1, 0E6h emit 1, @dest.imm exit end calminstruction