asm_dip/toolchain/fasm2/include/x86-2.inc

4169 lines
99 KiB
PHP
Raw Normal View History

2024-11-24 21:04:53 -08:00
; 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 <instr,basecode>, 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 <instr,postbyte>, 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 <instr,postbyte>, 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 <instr,handler,size>, 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 <instr,opcode>, 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 <instr,size,opcode>, 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 <instr,opcode>, 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 <instr,opcode>, 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 <instr,opcode>, 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, <opcode>,@dest.rm
exit
invalid_operand_size:
err 'invalid operand size'
invalid_combination_of_operands:
err 'invalid combination of operands'
end calminstruction
end iterate
iterate <instr,postbyte>, 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 <instr,ext>, 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 <instr,postbyte>, 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 <instr,ext>, 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 <instr,ext>, 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 <cond,code>, 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 <instr,opcode>, 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 <instr,opcode,len>, 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 <instr,opcode>, 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 <instr,opcode>, leave,0C9h, insb,6Ch, outsb,6Eh
calminstruction instr?
call x86.require.80186
emit 1, opcode
end calminstruction
end iterate
iterate <instr,opcode,cpu>, 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 <instr,opcode>, 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 <instr,opcode>, 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 <instr,opcode>, insw,6Dh, outsw,6Fh
calminstruction instr?
call x86.require.80186
xcall x86.store_operand_prefix, (2)
emit 1, opcode
end calminstruction
end iterate
iterate <instr,opcode>, insd,6Dh, outsd,6Fh
calminstruction instr?
call x86.require.80186
xcall x86.store_operand_prefix, (4)
emit 1, opcode
end calminstruction
end iterate
iterate <instr,opcode>, 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 <instr,opcode>, swapgs,<0Fh,1,0F8h>, syscall,<0Fh,5>, sysret,<0Fh,7>
calminstruction instr?
call x86.require.bits64
asm db opcode
end calminstruction
end iterate
iterate <prefix,opcode>, 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 <instr,opcode>, 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 <instr,opcode>, 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 <instr,opcode>, 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 <instr,opcode>, pushfq,9Ch, popfq,9Dh
calminstruction instr?
call x86.require.bits64
emit 1, opcode
end calminstruction
end iterate
iterate <instr,opcode>, 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 <instr,opcode>, 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 <instr,ext,postbyte>, 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 <instr,ext,postbyte>, 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 <instr,postbyte>, 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 <instr,ext>, 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 <instr,ext>, 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 <instr,opcode,postbyte>, 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 <instr,opcode,postbyte>, 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 <instr,postbyte>, 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 <instr,postbyte>, 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 <instr,postbyte>, 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 <instr,pfx>, 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'