# This file is part of Metasm, the Ruby assembly manipulation suite # Copyright (C) 2006-2009 Yoann GUILLOT # # Licence is LGPL, see LICENCE in the top-level directory require 'metasm/cpu/ia32/main' module Metasm class Ia32 def init_cpu_constants @opcode_list ||= [] @fields_mask.update :w => 1, :s => 1, :d => 1, :modrm => 0xC7, :reg => 7, :eeec => 7, :eeed => 7, :eeet => 7, :seg2 => 3, :seg3 => 7, :regfp => 7, :regmmx => 7, :regxmm => 7, :regymm => 7, :vex_r => 1, :vex_b => 1, :vex_x => 1, :vex_w => 1, :vex_vvvv => 0xF @fields_mask[:seg2A] = @fields_mask[:seg2] @fields_mask[:seg3A] = @fields_mask[:seg3] [:i, :i8, :u8, :u16, :reg, :seg2, :seg2A, :seg3, :seg3A, :eeec, :eeed, :eeet, :modrm, :mrm_imm, :farptr, :imm_val1, :imm_val3, :reg_cl, :reg_eax, :reg_dx, :regfp, :regfp0, :modrmmmx, :regmmx, :modrmxmm, :regxmm, :modrmymm, :regymm, :vexvxmm, :vexvymm, :vexvreg, :i4xmm, :i4ymm ].each { |a| @valid_args[a] = true } [:strop, :stropz, :opsz, :adsz, :argsz, :setip, :stopexec, :saveip, :unsigned_imm, :random, :needpfx, :xmmx, :modrmR, :modrmA, :mrmvex ].each { |a| @valid_props[a] = true } end # only most common instructions from the 386 instruction set # inexhaustive list : # no aaa, arpl, mov crX, call/jmp/ret far, in/out, bts, xchg... def init_386_common_only init_cpu_constants addop_macro1 'adc', 2 addop_macro1 'add', 0 addop_macro1 'and', 4, :unsigned_imm addop 'bswap', [0x0F, 0xC8], :reg addop 'call', [0xE8], nil, :stopexec, :setip, :i, :saveip addop 'call', [0xFF], 2, :stopexec, :setip, :saveip addop('cbw', [0x98]) { |o| o.props[:opsz] = 16 } addop('cwde', [0x98]) { |o| o.props[:opsz] = 32 } addop('cwd', [0x99]) { |o| o.props[:opsz] = 16 } addop('cdq', [0x99]) { |o| o.props[:opsz] = 32 } addop_macro1 'cmp', 7 addop_macrostr 'cmps', [0xA6], :stropz addop 'dec', [0x48], :reg addop 'dec', [0xFE], 1, {:w => [0, 0]} addop 'div', [0xF6], 6, {:w => [0, 0]} addop 'enter', [0xC8], nil, :u16, :u8 addop 'idiv', [0xF6], 7, {:w => [0, 0]} addop 'imul', [0xF6], 5, {:w => [0, 0]} # implicit eax, but different semantic from imul eax, ebx (the implicit version updates edx:eax) addop 'imul', [0x0F, 0xAF], :mrm addop 'imul', [0x69], :mrm, {:s => [0, 1]}, :i addop 'inc', [0x40], :reg addop 'inc', [0xFE], 0, {:w => [0, 0]} addop 'int', [0xCC], nil, :imm_val3, :stopexec addop 'int', [0xCD], nil, :u8 addop_macrotttn 'j', [0x70], nil, :setip, :i8 addop_macrotttn('j', [0x70], nil, :setip, :i8) { |o| o.name << '.i8' } addop_macrotttn 'j', [0x0F, 0x80], nil, :setip, :i addop_macrotttn('j', [0x0F, 0x80], nil, :setip, :i) { |o| o.name << '.i' } addop 'jmp', [0xE9], nil, {:s => [0, 1]}, :setip, :i, :stopexec addop 'jmp', [0xFF], 4, :setip, :stopexec addop 'lea', [0x8D], :mrmA addop 'leave', [0xC9] addop_macrostr 'lods', [0xAC], :strop addop 'loop', [0xE2], nil, :setip, :i8 addop 'loopz', [0xE1], nil, :setip, :i8 addop 'loope', [0xE1], nil, :setip, :i8 addop 'loopnz',[0xE0], nil, :setip, :i8 addop 'loopne',[0xE0], nil, :setip, :i8 addop 'mov', [0xA0], nil, {:w => [0, 0], :d => [0, 1]}, :reg_eax, :mrm_imm addop('mov', [0x88], :mrmw,{:d => [0, 1]}) { |o| o.args.reverse! } addop 'mov', [0xB0], :reg, {:w => [0, 3]}, :i, :unsigned_imm addop 'mov', [0xC6], 0, {:w => [0, 0]}, :i, :unsigned_imm addop_macrostr 'movs', [0xA4], :strop addop 'movsx', [0x0F, 0xBE], :mrmw addop 'movzx', [0x0F, 0xB6], :mrmw addop 'mul', [0xF6], 4, {:w => [0, 0]} addop 'neg', [0xF6], 3, {:w => [0, 0]} addop 'nop', [0x90] addop 'not', [0xF6], 2, {:w => [0, 0]} addop_macro1 'or', 1, :unsigned_imm addop 'pop', [0x58], :reg addop 'pop', [0x8F], 0 addop 'push', [0x50], :reg addop 'push', [0xFF], 6 addop 'push', [0x68], nil, {:s => [0, 1]}, :i, :unsigned_imm addop 'ret', [0xC3], nil, :stopexec, :setip addop 'ret', [0xC2], nil, :stopexec, :u16, :setip addop_macro3 'rol', 0 addop_macro3 'ror', 1 addop_macro3 'sar', 7 addop_macro1 'sbb', 3 addop_macrostr 'scas', [0xAE], :stropz addop_macrotttn('set', [0x0F, 0x90], 0) { |o| o.props[:argsz] = 8 } addop_macrotttn('set', [0x0F, 0x90], :mrm) { |o| o.props[:argsz] = 8 ; o.args.reverse! } # :reg field is unused addop_macro3 'shl', 4 addop_macro3 'sal', 6 addop('shld', [0x0F, 0xA4], :mrm, :u8) { |o| o.args[0], o.args[1] = o.args[1], o.args[0] } addop('shld', [0x0F, 0xA5], :mrm, :reg_cl) { |o| o.args[0], o.args[1] = o.args[1], o.args[0] } addop_macro3 'shr', 5 addop('shrd', [0x0F, 0xAC], :mrm, :u8) { |o| o.args[0], o.args[1] = o.args[1], o.args[0] } addop('shrd', [0x0F, 0xAD], :mrm, :reg_cl) { |o| o.args[0], o.args[1] = o.args[1], o.args[0] } addop_macrostr 'stos', [0xAA], :strop addop_macro1 'sub', 5 addop 'test', [0x84], :mrmw addop 'test', [0xA8], nil, {:w => [0, 0]}, :reg_eax, :i, :unsigned_imm addop 'test', [0xF6], 0, {:w => [0, 0]}, :i, :unsigned_imm addop 'xchg', [0x90], :reg, :reg_eax addop('xchg', [0x90], :reg, :reg_eax) { |o| o.args.reverse! } # xchg eax, ebx == xchg ebx, eax) addop 'xchg', [0x86], :mrmw addop('xchg', [0x86], :mrmw) { |o| o.args.reverse! } addop_macro1 'xor', 6, :unsigned_imm end def init_386_only init_cpu_constants addop 'aaa', [0x37] addop 'aad', [0xD5, 0x0A] addop 'aam', [0xD4, 0x0A] addop 'aas', [0x3F] addop('arpl', [0x63], :mrm) { |o| o.props[:argsz] = 16 ; o.args.reverse! } addop 'bound', [0x62], :mrmA addop 'bsf', [0x0F, 0xBC], :mrm addop 'bsr', [0x0F, 0xBD], :mrm addop_macro2 'bt' , 0 addop_macro2 'btc', 3 addop_macro2 'btr', 2 addop_macro2 'bts', 1 addop 'call', [0x9A], nil, :stopexec, :setip, :farptr, :saveip addop 'callf', [0x9A], nil, :stopexec, :setip, :farptr, :saveip addop 'callf', [0xFF], 3, :stopexec, :setip, :saveip addop 'clc', [0xF8] addop 'cld', [0xFC] addop 'cli', [0xFA] addop 'clts', [0x0F, 0x06] addop 'cmc', [0xF5] addop('cmpxchg',[0x0F, 0xB0], :mrmw) { |o| o.args.reverse! } addop 'cpuid', [0x0F, 0xA2] addop 'daa', [0x27] addop 'das', [0x2F] addop 'hlt', [0xF4], nil, :stopexec addop 'in', [0xE4], nil, {:w => [0, 0]}, :reg_eax, :u8 addop 'in', [0xE4], nil, {:w => [0, 0]}, :u8 addop 'in', [0xEC], nil, {:w => [0, 0]}, :reg_eax, :reg_dx addop 'in', [0xEC], nil, {:w => [0, 0]}, :reg_eax addop 'in', [0xEC], nil, {:w => [0, 0]} addop_macrostr 'ins', [0x6C], :strop addop 'into', [0xCE] addop 'invd', [0x0F, 0x08] addop 'invlpg', [0x0F, 0x01, 7<<3], :modrmA addop('iretd', [0xCF], nil, :stopexec, :setip) { |o| o.props[:opsz] = 32 } addop_macroret 'iret', [0xCF] addop('jcxz', [0xE3], nil, :setip, :i8) { |o| o.props[:adsz] = 16 } addop('jecxz', [0xE3], nil, :setip, :i8) { |o| o.props[:adsz] = 32 } addop 'jmp', [0xEA], nil, :farptr, :setip, :stopexec addop 'jmpf', [0xEA], nil, :farptr, :setip, :stopexec addop 'jmpf', [0xFF], 5, :stopexec, :setip # reg ? addop 'lahf', [0x9F] addop 'lar', [0x0F, 0x02], :mrm addop 'lds', [0xC5], :mrmA addop 'les', [0xC4], :mrmA addop 'lfs', [0x0F, 0xB4], :mrmA addop 'lgs', [0x0F, 0xB5], :mrmA addop 'lgdt', [0x0F, 0x01], 2, :modrmA addop 'lidt', [0x0F, 0x01, 3<<3], :modrmA addop 'lldt', [0x0F, 0x00], 2, :modrmA addop 'lmsw', [0x0F, 0x01], 6 # prefix addop 'lock', [0xF0] addop 'lsl', [0x0F, 0x03], :mrm addop 'lss', [0x0F, 0xB2], :mrmA addop 'ltr', [0x0F, 0x00], 3 addop 'mov', [0x0F, 0x20, 0xC0], :reg, {:d => [1, 1], :eeec => [2, 3]}, :eeec addop 'mov', [0x0F, 0x21, 0xC0], :reg, {:d => [1, 1], :eeed => [2, 3]}, :eeed addop 'mov', [0x0F, 0x24, 0xC0], :reg, {:d => [1, 1], :eeet => [2, 3]}, :eeet addop 'mov', [0x8C], 0, {:d => [0, 1], :seg3 => [1, 3]}, :seg3 addop 'movbe', [0x0F, 0x38, 0xF0], :mrm, { :d => [2, 0] } addop 'out', [0xE6], nil, {:w => [0, 0]}, :u8, :reg_eax addop 'out', [0xE6], nil, {:w => [0, 0]}, :reg_eax, :u8 addop 'out', [0xE6], nil, {:w => [0, 0]}, :u8 addop 'out', [0xEE], nil, {:w => [0, 0]}, :reg_dx, :reg_eax addop 'out', [0xEE], nil, {:w => [0, 0]}, :reg_eax, :reg_dx addop 'out', [0xEE], nil, {:w => [0, 0]}, :reg_eax # implicit arguments addop 'out', [0xEE], nil, {:w => [0, 0]} addop_macrostr 'outs', [0x6E], :strop addop 'pop', [0x07], nil, {:seg2A => [0, 3]}, :seg2A addop 'pop', [0x0F, 0x81], nil, {:seg3A => [1, 3]}, :seg3A addop('popa', [0x61]) { |o| o.props[:opsz] = 16 } addop('popad', [0x61]) { |o| o.props[:opsz] = 32 } addop('popf', [0x9D]) { |o| o.props[:opsz] = 16 } addop('popfd', [0x9D]) { |o| o.props[:opsz] = 32 } addop 'push', [0x06], nil, {:seg2 => [0, 3]}, :seg2 addop 'push', [0x0F, 0x80], nil, {:seg3A => [1, 3]}, :seg3A addop('pusha', [0x60]) { |o| o.props[:opsz] = 16 } addop('pushad',[0x60]) { |o| o.props[:opsz] = 32 } addop('pushf', [0x9C]) { |o| o.props[:opsz] = 16 } addop('pushfd',[0x9C]) { |o| o.props[:opsz] = 32 } addop_macro3 'rcl', 2 addop_macro3 'rcr', 3 addop 'rdmsr', [0x0F, 0x32] addop 'rdpmc', [0x0F, 0x33] addop 'rdtsc', [0x0F, 0x31], nil, :random addop_macroret 'retf', [0xCB] addop_macroret 'retf', [0xCA], :u16 addop 'rsm', [0x0F, 0xAA], nil, :stopexec addop 'sahf', [0x9E] addop 'sgdt', [0x0F, 0x01, 0<<3], :modrmA addop 'sidt', [0x0F, 0x01, 1<<3], :modrmA addop 'sldt', [0x0F, 0x00], 0 addop 'smsw', [0x0F, 0x01], 4 addop 'stc', [0xF9] addop 'std', [0xFD] addop 'sti', [0xFB] addop 'str', [0x0F, 0x00], 1 addop 'test', [0xF6], 1, {:w => [0, 0]}, :i, :unsigned_imm # undocumented alias to F6/0 addop 'ud2', [0x0F, 0x0B] addop 'verr', [0x0F, 0x00], 4 addop 'verw', [0x0F, 0x00], 5 addop 'wait', [0x9B] addop 'wbinvd',[0x0F, 0x09] addop 'wrmsr', [0x0F, 0x30] addop('xadd', [0x0F, 0xC0], :mrmw) { |o| o.args.reverse! } addop 'xlat', [0xD7] # pfx: addrsz = 0x67, lock = 0xF0, opsz = 0x66, repnz = 0xF2, rep/repz = 0xF3 # cs/nojmp = 0x2E, ds/jmp = 0x3E, es = 0x26, fs = 0x64, gs = 0x65, ss = 0x36 # undocumented opcodes addop 'aam', [0xD4], nil, :u8 addop 'aad', [0xD5], nil, :u8 addop 'setalc',[0xD6] addop 'salc', [0xD6] addop 'icebp', [0xF1] #addop 'loadall',[0x0F, 0x07] # conflict with syscall addop 'ud0', [0x0F, 0xFF] # amd addop 'ud2', [0x0F, 0xB9], :mrm #addop 'umov', [0x0F, 0x10], :mrmw, {:d => [1, 1]} # conflicts with movups/movhlps end def init_387_only init_cpu_constants addop 'f2xm1', [0xD9, 0xF0] addop 'fabs', [0xD9, 0xE1] addop_macrofpu1 'fadd', 0 addop 'faddp', [0xDE, 0xC0], :regfp addop 'faddp', [0xDE, 0xC1] addop('fbld', [0xDF, 4<<3], :modrmA, :regfp0) { |o| o.props[:argsz] = 80 } addop('fbstp', [0xDF, 6<<3], :modrmA, :regfp0) { |o| o.props[:argsz] = 80 } addop 'fchs', [0xD9, 0xE0], nil, :regfp0 addop 'fnclex', [0xDB, 0xE2] addop_macrofpu1 'fcom', 2 addop_macrofpu1 'fcomp', 3 addop 'fcompp',[0xDE, 0xD9] addop 'fcomip',[0xDF, 0xF0], :regfp addop 'fcos', [0xD9, 0xFF], nil, :regfp0 addop 'fdecstp', [0xD9, 0xF6] addop_macrofpu1 'fdiv', 6 addop_macrofpu1 'fdivr', 7 addop 'fdivp', [0xDE, 0xF8], :regfp addop 'fdivp', [0xDE, 0xF9] addop 'fdivrp',[0xDE, 0xF0], :regfp addop 'fdivrp',[0xDE, 0xF1] addop 'ffree', [0xDD, 0xC0], nil, {:regfp => [1, 0]}, :regfp addop_macrofpu2 'fiadd', 0 addop_macrofpu2 'fimul', 1 addop_macrofpu2 'ficom', 2 addop_macrofpu2 'ficomp',3 addop_macrofpu2 'fisub', 4 addop_macrofpu2 'fisubr',5 addop_macrofpu2 'fidiv', 6 addop_macrofpu2 'fidivr',7 addop 'fincstp', [0xD9, 0xF7] addop 'fninit', [0xDB, 0xE3] addop_macrofpu2 'fist', 2, 1 addop_macrofpu3 'fild', 0 addop_macrofpu3 'fistp',3 addop('fld', [0xD9, 0<<3], :modrmA, :regfp0) { |o| o.props[:argsz] = 32 } addop('fld', [0xDD, 0<<3], :modrmA, :regfp0) { |o| o.props[:argsz] = 64 } addop('fld', [0xDB, 5<<3], :modrmA, :regfp0) { |o| o.props[:argsz] = 80 } addop 'fld', [0xD9, 0xC0], :regfp addop('fldcw', [0xD9, 5<<3], :modrmA) { |o| o.props[:argsz] = 16 } addop 'fldenv', [0xD9, 4<<3], :modrmA addop 'fld1', [0xD9, 0xE8] addop 'fldl2t', [0xD9, 0xE9] addop 'fldl2e', [0xD9, 0xEA] addop 'fldpi', [0xD9, 0xEB] addop 'fldlg2', [0xD9, 0xEC] addop 'fldln2', [0xD9, 0xED] addop 'fldz', [0xD9, 0xEE] addop_macrofpu1 'fmul', 1 addop 'fmulp', [0xDE, 0xC8], :regfp addop 'fmulp', [0xDE, 0xC9] addop 'fnop', [0xD9, 0xD0] addop 'fpatan', [0xD9, 0xF3] addop 'fprem', [0xD9, 0xF8] addop 'fprem1', [0xD9, 0xF5] addop 'fptan', [0xD9, 0xF2] addop 'frndint',[0xD9, 0xFC] addop 'frstor', [0xDD, 4<<3], :modrmA addop 'fnsave', [0xDD, 6<<3], :modrmA addop('fnstcw', [0xD9, 7<<3], :modrmA) { |o| o.props[:argsz] = 16 } addop 'fnstenv',[0xD9, 6<<3], :modrmA addop 'fnstsw', [0xDF, 0xE0] addop('fnstsw', [0xDD, 7<<3], :modrmA) { |o| o.props[:argsz] = 16 } addop 'fscale', [0xD9, 0xFD] addop 'fsin', [0xD9, 0xFE] addop 'fsincos',[0xD9, 0xFB] addop 'fsqrt', [0xD9, 0xFA] addop('fst', [0xD9, 2<<3], :modrmA, :regfp0) { |o| o.props[:argsz] = 32 } addop('fst', [0xDD, 2<<3], :modrmA, :regfp0) { |o| o.props[:argsz] = 64 } addop 'fst', [0xD9, 0xD0], :regfp addop('fstp', [0xD9, 3<<3], :modrmA, :regfp0) { |o| o.props[:argsz] = 32 } addop('fstp', [0xDD, 3<<3], :modrmA, :regfp0) { |o| o.props[:argsz] = 64 } addop('fstp', [0xDB, 7<<3], :modrmA, :regfp0) { |o| o.props[:argsz] = 80 } addop 'fstp', [0xDD, 0xD8], :regfp addop_macrofpu1 'fsub', 4 addop 'fsubp', [0xDE, 0xE8], :regfp addop 'fsubp', [0xDE, 0xE9] addop_macrofpu1 'fsubp', 5 addop 'fsubrp', [0xDE, 0xE0], :regfp addop 'fsubrp', [0xDE, 0xE1] addop 'ftst', [0xD9, 0xE4] addop 'fucom', [0xDD, 0xE0], :regfp addop 'fucomp', [0xDD, 0xE8], :regfp addop 'fucompp',[0xDA, 0xE9] addop 'fucomi', [0xDB, 0xE8], :regfp addop 'fxam', [0xD9, 0xE5] addop 'fxch', [0xD9, 0xC8], :regfp addop 'fxtract',[0xD9, 0xF4] addop 'fyl2x', [0xD9, 0xF1] addop 'fyl2xp1',[0xD9, 0xF9] # fwait prefix addop 'fclex', [0x9B, 0xDB, 0xE2] addop 'finit', [0x9B, 0xDB, 0xE3] addop 'fsave', [0x9B, 0xDD, 6<<3], :modrmA addop('fstcw', [0x9B, 0xD9, 7<<3], :modrmA) { |o| o.props[:argsz] = 16 } addop 'fstenv', [0x9B, 0xD9, 6<<3], :modrmA addop 'fstsw', [0x9B, 0xDF, 0xE0] addop('fstsw', [0x9B, 0xDD, 7<<3], :modrmA) { |o| o.props[:argsz] = 16 } addop 'fwait', [0x9B] end def init_486_only init_cpu_constants end def init_pentium_only init_cpu_constants addop('cmpxchg8b', [0x0F, 0xC7], 1) { |o| o.props[:opsz] = 32 ; o.props[:argsz] = 64 } # lock cmpxchg8b eax #addop 'f00fbug', [0xF0, 0x0F, 0xC7, 0xC8] # mmx addop 'emms', [0x0F, 0x77] addop('movd', [0x0F, 0x6E], :mrmmmx, {:d => [1, 4]}) { |o| o.args = [:modrm, :regmmx] ; o.props[:opsz] = o.props[:argsz] = 32 } addop('movq', [0x0F, 0x6F], :mrmmmx, {:d => [1, 4]}) { |o| o.props[:argsz] = 64 } addop 'packssdw', [0x0F, 0x6B], :mrmmmx addop 'packsswb', [0x0F, 0x63], :mrmmmx addop 'packuswb', [0x0F, 0x67], :mrmmmx addop_macrogg 0..2, 'padd', [0x0F, 0xFC], :mrmmmx addop_macrogg 0..1, 'padds', [0x0F, 0xEC], :mrmmmx addop_macrogg 0..1, 'paddus',[0x0F, 0xDC], :mrmmmx addop 'pand', [0x0F, 0xDB], :mrmmmx addop 'pandn', [0x0F, 0xDF], :mrmmmx addop_macrogg 0..2, 'pcmpeq',[0x0F, 0x74], :mrmmmx addop_macrogg 0..2, 'pcmpgt',[0x0F, 0x64], :mrmmmx addop 'pmaddwd', [0x0F, 0xF5], :mrmmmx addop 'pmulhuw', [0x0F, 0xE4], :mrmmmx addop 'pmulhw',[0x0F, 0xE5], :mrmmmx addop 'pmullw',[0x0F, 0xD5], :mrmmmx addop 'por', [0x0F, 0xEB], :mrmmmx [[1..3, 'psll', 3], [1..2, 'psra', 2], [1..3, 'psrl', 1]].each { |ggrng, name, val| addop_macrogg ggrng, name, [0x0F, 0xC0 | (val << 4)], :mrmmmx addop_macrogg ggrng, name, [0x0F, 0x70, 0xC0 | (val << 4)], nil, {:regmmx => [2, 0]}, :regmmx, :u8 } addop_macrogg 0..2, 'psub', [0x0F, 0xF8], :mrmmmx addop_macrogg 0..1, 'psubs', [0x0F, 0xE8], :mrmmmx addop_macrogg 0..1, 'psubus',[0x0F, 0xD8], :mrmmmx addop_macrogg 1..3, 'punpckh', [0x0F, 0x68], :mrmmmx addop_macrogg 1..3, 'punpckl', [0x0F, 0x60], :mrmmmx addop 'pxor', [0x0F, 0xEF], :mrmmmx end def init_p6_only addop_macrotttn 'cmov', [0x0F, 0x40], :mrm %w{b e be u}.each_with_index { |tt, i| addop 'fcmov' + tt, [0xDA, 0xC0 | (i << 3)], :regfp addop 'fcmovn'+ tt, [0xDB, 0xC0 | (i << 3)], :regfp } addop 'fcomi', [0xDB, 0xF0], :regfp addop('fxrstor', [0x0F, 0xAE, 1<<3], :modrmA) { |o| o.props[:argsz] = 512*8 } addop('fxsave', [0x0F, 0xAE, 0<<3], :modrmA) { |o| o.props[:argsz] = 512*8 } addop 'sysenter',[0x0F, 0x34] addop 'sysexit', [0x0F, 0x35] addop 'syscall', [0x0F, 0x05] # AMD addop_macroret 'sysret', [0x0F, 0x07] # AMD end def init_3dnow_only init_cpu_constants [['pavgusb', 0xBF], ['pfadd', 0x9E], ['pfsub', 0x9A], ['pfsubr', 0xAA], ['pfacc', 0xAE], ['pfcmpge', 0x90], ['pfcmpgt', 0xA0], ['fpcmpeq', 0xB0], ['pfmin', 0x94], ['pfmax', 0xA4], ['pi2fd', 0x0D], ['pf2id', 0x1D], ['pfrcp', 0x96], ['pfrsqrt', 0x97], ['pfmul', 0xB4], ['pfrcpit1', 0xA6], ['pfrsqit1', 0xA7], ['pfrcpit2', 0xB6], ['pmulhrw', 0xB7]].each { |str, bin| addop str, [0x0F, 0x0F, bin], :mrmmmx } # 3dnow prefix fallback addop '3dnow', [0x0F, 0x0F], :mrmmmx, :u8 addop 'femms', [0x0F, 0x0E] addop 'prefetch', [0x0F, 0x0D, 0<<3], :modrmA addop 'prefetchw', [0x0F, 0x0D, 1<<3], :modrmA end def init_sse_only init_cpu_constants addop_macrossps 'addps', [0x0F, 0x58], :mrmxmm addop 'andnps', [0x0F, 0x55], :mrmxmm addop 'andps', [0x0F, 0x54], :mrmxmm addop_macrossps 'cmpps', [0x0F, 0xC2], :mrmxmm, :u8 addop 'comiss', [0x0F, 0x2F], :mrmxmm addop('cvtpi2ps', [0x0F, 0x2A], :mrmxmm) { |o| o.args[o.args.index(:modrmxmm)] = :modrmmmx } addop('cvtps2pi', [0x0F, 0x2D], :mrmmmx) { |o| o.args[o.args.index(:modrmmmx)] = :modrmxmm } addop('cvtsi2ss', [0x0F, 0x2A], :mrmxmm) { |o| o.args[o.args.index(:modrmxmm)] = :modrm ; o.props[:needpfx] = 0xF3 } addop('cvtss2si', [0x0F, 0x2D], :mrm) { |o| o.args[o.args.index(:modrm)] = :modrmxmm ; o.props[:needpfx] = 0xF3 } addop('cvttps2pi',[0x0F, 0x2C], :mrmmmx) { |o| o.args[o.args.index(:modrmmmx)] = :modrmxmm } addop('cvttss2si',[0x0F, 0x2C], :mrm) { |o| o.args[o.args.index(:modrm)] = :modrmxmm ; o.props[:needpfx] = 0xF3 } addop_macrossps 'divps', [0x0F, 0x5E], :mrmxmm addop 'ldmxcsr', [0x0F, 0xAE, 2<<3], :modrmA addop_macrossps 'maxps', [0x0F, 0x5F], :mrmxmm addop_macrossps 'minps', [0x0F, 0x5D], :mrmxmm addop 'movaps', [0x0F, 0x28], :mrmxmm, {:d => [1, 0]} addop 'movhlps', [0x0F, 0x12], :mrmxmm, :modrmR addop 'movlps', [0x0F, 0x12], :mrmxmm, {:d => [1, 0]}, :modrmA addop 'movlhps', [0x0F, 0x16], :mrmxmm, :modrmR addop 'movhps', [0x0F, 0x16], :mrmxmm, {:d => [1, 0]}, :modrmA addop 'movmskps',[0x0F, 0x50, 0xC0], nil, {:reg => [2, 3], :regxmm => [2, 0]}, :regxmm, :reg addop('movss', [0x0F, 0x10], :mrmxmm, {:d => [1, 0]}) { |o| o.props[:needpfx] = 0xF3 } addop 'movups', [0x0F, 0x10], :mrmxmm, {:d => [1, 0]} addop_macrossps 'mulps', [0x0F, 0x59], :mrmxmm addop 'orps', [0x0F, 0x56], :mrmxmm addop_macrossps 'rcpps', [0x0F, 0x53], :mrmxmm addop_macrossps 'rsqrtps',[0x0F, 0x52], :mrmxmm addop 'shufps', [0x0F, 0xC6], :mrmxmm, :u8 addop_macrossps 'sqrtps', [0x0F, 0x51], :mrmxmm addop 'stmxcsr', [0x0F, 0xAE, 3<<3], :modrmA addop_macrossps 'subps', [0x0F, 0x5C], :mrmxmm addop 'ucomiss', [0x0F, 0x2E], :mrmxmm addop 'unpckhps',[0x0F, 0x15], :mrmxmm addop 'unpcklps',[0x0F, 0x14], :mrmxmm addop 'xorps', [0x0F, 0x57], :mrmxmm # integer instrs, mmx only addop 'pavgb', [0x0F, 0xE0], :mrmmmx addop 'pavgw', [0x0F, 0xE3], :mrmmmx addop 'pextrw', [0x0F, 0xC5, 0xC0], nil, {:reg => [2, 3], :regmmx => [2, 0]}, :reg, :regmmx, :u8 addop 'pinsrw', [0x0F, 0xC4, 0x00], nil, {:modrm => [2, 0], :regmmx => [2, 3]}, :regmmx, :modrm, :u8 addop 'pmaxsw', [0x0F, 0xEE], :mrmmmx addop 'pmaxub', [0x0F, 0xDE], :mrmmmx addop 'pminsw', [0x0F, 0xEA], :mrmmmx addop 'pminub', [0x0F, 0xDA], :mrmmmx addop 'pmovmskb',[0x0F, 0xD7, 0xC0], nil, {:reg => [2, 3], :regmmx => [2, 0]}, :reg, :regmmx addop 'psadbw', [0x0F, 0xF6], :mrmmmx addop 'pshufw', [0x0F, 0x70], :mrmmmx, :u8 addop 'maskmovq',[0x0F, 0xF7], :mrmmmx, :modrmR addop('movntq', [0x0F, 0xE7], :mrmmmx) { |o| o.args.reverse! } addop('movntps', [0x0F, 0x2B], :mrmxmm) { |o| o.args.reverse! } addop 'prefetcht0', [0x0F, 0x18, 1<<3], :modrmA addop 'prefetcht1', [0x0F, 0x18, 2<<3], :modrmA addop 'prefetcht2', [0x0F, 0x18, 3<<3], :modrmA addop 'prefetchnta',[0x0F, 0x18, 0<<3], :modrmA addop 'sfence', [0x0F, 0xAE, 0xF8] # the whole row of prefetch is actually nops addop 'nop', [0x0F, 0x1C], :mrmw, :d => [1, 1] # incl. official version = 0f1f mrm addop 'nop_8', [0x0F, 0x18], :mrmw, :d => [1, 1] addop 'nop_d', [0x0F, 0x0D], :mrm addop 'nop', [0x0F, 0x1C], 0 # official asm syntax is 'nop [eax]' end def init_sse2_only init_cpu_constants @opcode_list.each { |o| o.props[:xmmx] = true if o.fields[:regmmx] and o.name !~ /^(?:mov(?:nt)?q|pshufw|cvt.*)$/ } # mirror of the init_sse part addop_macrosdpd 'addpd', [0x0F, 0x58], :mrmxmm addop('andnpd', [0x0F, 0x55], :mrmxmm) { |o| o.props[:needpfx] = 0x66 } addop('andpd', [0x0F, 0x54], :mrmxmm) { |o| o.props[:needpfx] = 0x66 } addop_macrosdpd 'cmppd', [0x0F, 0xC2], :mrmxmm, :u8 addop('comisd', [0x0F, 0x2F], :mrmxmm) { |o| o.props[:needpfx] = 0x66 } addop('cvtpi2pd', [0x0F, 0x2A], :mrmxmm) { |o| o.args[o.args.index(:modrmxmm)] = :modrmmmx ; o.props[:needpfx] = 0x66 } addop('cvtpd2pi', [0x0F, 0x2D], :mrmmmx) { |o| o.args[o.args.index(:modrmmmx)] = :modrmxmm ; o.props[:needpfx] = 0x66 } addop('cvtsi2sd', [0x0F, 0x2A], :mrmxmm) { |o| o.args[o.args.index(:modrmxmm)] = :modrm ; o.props[:needpfx] = 0xF2 } addop('cvtsd2si', [0x0F, 0x2D], :mrm ) { |o| o.args[o.args.index(:modrm )] = :modrmxmm ; o.props[:needpfx] = 0xF2 } addop('cvttpd2pi',[0x0F, 0x2C], :mrmmmx) { |o| o.args[o.args.index(:modrmmmx)] = :modrmxmm ; o.props[:needpfx] = 0x66 } addop('cvttsd2si',[0x0F, 0x2C], :mrm ) { |o| o.args[o.args.index(:modrm )] = :modrmxmm ; o.props[:needpfx] = 0xF2 } addop('cvtpd2ps', [0x0F, 0x5A], :mrmxmm) { |o| o.props[:needpfx] = 0x66 } addop('cvtps2pd', [0x0F, 0x5A], :mrmxmm) addop('cvtsd2ss', [0x0F, 0x5A], :mrmxmm) { |o| o.props[:needpfx] = 0xF2 } addop('cvtss2sd', [0x0F, 0x5A], :mrmxmm) { |o| o.props[:needpfx] = 0xF3 } addop('cvtpd2dq', [0x0F, 0xE6], :mrmxmm) { |o| o.props[:needpfx] = 0xF2 } addop('cvttpd2dq',[0x0F, 0xE6], :mrmxmm) { |o| o.props[:needpfx] = 0x66 } addop('cvtdq2pd', [0x0F, 0xE6], :mrmxmm) { |o| o.props[:needpfx] = 0xF3 } addop('cvtps2dq', [0x0F, 0x5B], :mrmxmm) { |o| o.props[:needpfx] = 0x66 } addop('cvttps2dq',[0x0F, 0x5B], :mrmxmm) { |o| o.props[:needpfx] = 0xF3 } addop('cvtdq2ps', [0x0F, 0x5B], :mrmxmm) addop_macrosdpd 'divpd', [0x0F, 0x5E], :mrmxmm addop_macrosdpd 'maxpd', [0x0F, 0x5F], :mrmxmm addop_macrosdpd 'minpd', [0x0F, 0x5D], :mrmxmm addop('movapd', [0x0F, 0x28], :mrmxmm, {:d => [1, 0]}) { |o| o.props[:needpfx] = 0x66 } addop('movlpd', [0x0F, 0x12], :mrmxmm, {:d => [1, 0]}) { |o| o.props[:needpfx] = 0x66 } addop('movhpd', [0x0F, 0x16], :mrmxmm, {:d => [1, 0]}) { |o| o.props[:needpfx] = 0x66 } addop('movmskpd',[0x0F, 0x50, 0xC0], nil, {:reg => [2, 3], :regxmm => [2, 0]}, :regxmm, :reg) { |o| o.props[:needpfx] = 0x66 } addop('movsd', [0x0F, 0x10], :mrmxmm, {:d => [1, 0]}) { |o| o.props[:needpfx] = 0xF2 } addop('movupd', [0x0F, 0x10], :mrmxmm, {:d => [1, 0]}) { |o| o.props[:needpfx] = 0x66 } addop_macrosdpd 'mulpd', [0x0F, 0x59], :mrmxmm addop('orpd', [0x0F, 0x56], :mrmxmm) { |o| o.props[:needpfx] = 0x66 } addop('shufpd', [0x0F, 0xC6], :mrmxmm, :u8) { |o| o.props[:needpfx] = 0x66 } addop_macrosdpd 'sqrtpd', [0x0F, 0x51], :mrmxmm addop_macrosdpd 'subpd', [0x0F, 0x5C], :mrmxmm addop('ucomisd', [0x0F, 0x2E], :mrmxmm) { |o| o.props[:needpfx] = 0x66 } addop('unpckhpd',[0x0F, 0x15], :mrmxmm) { |o| o.props[:needpfx] = 0x66 } addop('unpcklpd',[0x0F, 0x14], :mrmxmm) { |o| o.props[:needpfx] = 0x66 } addop('xorpd', [0x0F, 0x57], :mrmxmm) { |o| o.props[:needpfx] = 0x66 } addop('movdqa', [0x0F, 0x6F], :mrmxmm, {:d => [1, 4]}) { |o| o.props[:needpfx] = 0x66 } addop('movdqu', [0x0F, 0x6F], :mrmxmm, {:d => [1, 4]}) { |o| o.props[:needpfx] = 0xF3 } addop('movq2dq', [0x0F, 0xD6], :mrmxmm, :modrmR) { |o| o.args[o.args.index(:modrmxmm)] = :modrmmmx ; o.props[:needpfx] = 0xF3 } addop('movdq2q', [0x0F, 0xD6], :mrmmmx, :modrmR) { |o| o.args[o.args.index(:modrmmmx)] = :modrmxmm ; o.props[:needpfx] = 0xF2 } addop('movq', [0x0F, 0x7E], :mrmxmm) { |o| o.props[:needpfx] = 0xF3 ; o.props[:argsz] = 128 } addop('movq', [0x0F, 0xD6], :mrmxmm) { |o| o.args.reverse! ; o.props[:needpfx] = 0x66 ; o.props[:argsz] = 128 } addop 'paddq', [0x0F, 0xD4], :mrmmmx, :xmmx addop 'pmuludq', [0x0F, 0xF4], :mrmmmx, :xmmx addop('pshuflw', [0x0F, 0x70], :mrmxmm, :u8) { |o| o.props[:needpfx] = 0xF2 } addop('pshufhw', [0x0F, 0x70], :mrmxmm, :u8) { |o| o.props[:needpfx] = 0xF3 } addop('pshufd', [0x0F, 0x70], :mrmxmm, :u8) { |o| o.props[:needpfx] = 0x66 } addop('pslldq', [0x0F, 0x73, 0xF8], nil, {:regxmm => [2, 0]}, :regxmm, :u8) { |o| o.props[:needpfx] = 0x66 } addop('psrldq', [0x0F, 0x73, 0xD8], nil, {:regxmm => [2, 0]}, :regxmm, :u8) { |o| o.props[:needpfx] = 0x66 } addop 'psubq', [0x0F, 0xFB], :mrmmmx, :xmmx addop('punpckhqdq', [0x0F, 0x6D], :mrmxmm) { |o| o.props[:needpfx] = 0x66 } addop('punpcklqdq', [0x0F, 0x6C], :mrmxmm) { |o| o.props[:needpfx] = 0x66 } addop('clflush', [0x0F, 0xAE, 7<<3], :modrmA) { |o| o.props[:argsz] = 8 } addop('maskmovdqu', [0x0F, 0xF7], :mrmxmm) { |o| o.props[:needpfx] = 0x66 } addop('movntpd', [0x0F, 0x2B], :mrmxmm) { |o| o.args.reverse! ; o.props[:needpfx] = 0x66 } addop('movntdq', [0x0F, 0xE7], :mrmxmm) { |o| o.args.reverse! ; o.props[:needpfx] = 0x66 } addop('movnti', [0x0F, 0xC3], :mrm) { |o| o.args.reverse! } addop('pause', [0x90]) { |o| o.props[:needpfx] = 0xF3 } addop 'lfence', [0x0F, 0xAE, 0xE8] addop 'mfence', [0x0F, 0xAE, 0xF0] end def init_sse3_only init_cpu_constants addop('addsubpd', [0x0F, 0xD0], :mrmxmm) { |o| o.props[:needpfx] = 0x66 } addop('addsubps', [0x0F, 0xD0], :mrmxmm) { |o| o.props[:needpfx] = 0xF2 } addop('haddpd', [0x0F, 0x7C], :mrmxmm) { |o| o.props[:needpfx] = 0x66 } addop('haddps', [0x0F, 0x7C], :mrmxmm) { |o| o.props[:needpfx] = 0xF2 } addop('hsubpd', [0x0F, 0x7D], :mrmxmm) { |o| o.props[:needpfx] = 0x66 } addop('hsubps', [0x0F, 0x7D], :mrmxmm) { |o| o.props[:needpfx] = 0xF2 } addop 'monitor', [0x0F, 0x01, 0xC8] addop 'mwait', [0x0F, 0x01, 0xC9] addop('fisttp', [0xDF, 1<<3], :modrmA) { |o| o.props[:argsz] = 16 } addop('fisttp', [0xDB, 1<<3], :modrmA) { |o| o.props[:argsz] = 32 } addop('fisttp', [0xDD, 1<<3], :modrmA) { |o| o.props[:argsz] = 64 } addop('lddqu', [0x0F, 0xF0], :mrmxmm, :modrmA) { |o| o.args[o.args.index(:modrmxmm)] = :modrm ; o.props[:needpfx] = 0xF2 } addop('movddup', [0x0F, 0x12], :mrmxmm) { |o| o.props[:needpfx] = 0xF2 } addop('movshdup', [0x0F, 0x16], :mrmxmm) { |o| o.props[:needpfx] = 0xF3 } addop('movsldup', [0x0F, 0x12], :mrmxmm) { |o| o.props[:needpfx] = 0xF3 } end def init_ssse3_only init_cpu_constants addop_macrogg 0..2, 'pabs', [0x0F, 0x38, 0x1C], :mrmmmx, :xmmx addop 'palignr', [0x0F, 0x3A, 0x0F], :mrmmmx, :u8, :xmmx addop 'phaddd', [0x0F, 0x38, 0x02], :mrmmmx, :xmmx addop 'phaddsw', [0x0F, 0x38, 0x03], :mrmmmx, :xmmx addop 'phaddw', [0x0F, 0x38, 0x01], :mrmmmx, :xmmx addop 'phsubd', [0x0F, 0x38, 0x06], :mrmmmx, :xmmx addop 'phsubsw', [0x0F, 0x38, 0x07], :mrmmmx, :xmmx addop 'phsubw', [0x0F, 0x38, 0x05], :mrmmmx, :xmmx addop 'pmaddubsw',[0x0F, 0x38, 0x04], :mrmmmx, :xmmx addop 'pmulhrsw', [0x0F, 0x38, 0x0B], :mrmmmx, :xmmx addop 'pshufb', [0x0F, 0x38, 0x00], :mrmmmx, :xmmx addop_macrogg 0..2, 'psignb', [0x0F, 0x38, 0x80], :mrmmmx, :xmmx end def init_aesni_only init_cpu_constants addop('aesdec', [0x0F, 0x38, 0xDE], :mrmxmm) { |o| o.props[:needpfx] = 0x66 } addop('aesdeclast',[0x0F, 0x38, 0xDF], :mrmxmm) { |o| o.props[:needpfx] = 0x66 } addop('aesenc', [0x0F, 0x38, 0xDC], :mrmxmm) { |o| o.props[:needpfx] = 0x66 } addop('aesenclast',[0x0F, 0x38, 0xDD], :mrmxmm) { |o| o.props[:needpfx] = 0x66 } addop('aesimc', [0x0F, 0x38, 0xDB], :mrmxmm) { |o| o.props[:needpfx] = 0x66 } addop('aeskeygenassist', [0x0F, 0x3A, 0xDF], :mrmxmm, :u8) { |o| o.props[:needpfx] = 0x66 } addop('pclmulqdq', [0x0F, 0x3A, 0x44], :mrmxmm, :u8) { |o| o.props[:needpfx] = 0x66 } end def init_vmx_only init_cpu_constants addop 'vmcall', [0x0F, 0x01, 0xC1] addop 'vmlaunch', [0x0F, 0x01, 0xC2] addop 'vmresume', [0x0F, 0x01, 0xC3] addop 'vmxoff', [0x0F, 0x01, 0xC4] addop 'vmread', [0x0F, 0x78], :mrm addop 'vmwrite', [0x0F, 0x79], :mrm addop('vmclear', [0x0F, 0xC7, 6<<3], :modrmA) { |o| o.props[:argsz] = 64 ; o.props[:needpfx] = 0x66 } addop('vmxon', [0x0F, 0xC7, 6<<3], :modrmA) { |o| o.props[:argsz] = 64 ; o.props[:needpfx] = 0xF3 } addop('vmptrld', [0x0F, 0xC7, 6<<3], :modrmA) { |o| o.props[:argsz] = 64 } addop('vmptrst', [0x0F, 0xC7, 7<<3], :modrmA) { |o| o.props[:argsz] = 64 } addop('invept', [0x0F, 0x38, 0x80], :mrmA) { |o| o.props[:needpfx] = 0x66 } addop('invvpid', [0x0F, 0x38, 0x81], :mrmA) { |o| o.props[:needpfx] = 0x66 } addop 'getsec', [0x0F, 0x37] addop 'xgetbv', [0x0F, 0x01, 0xD0] addop 'xsetbv', [0x0F, 0x01, 0xD1] addop 'rdtscp', [0x0F, 0x01, 0xF9] addop 'xrstor', [0x0F, 0xAE, 5<<3], :modrmA addop 'xsave', [0x0F, 0xAE, 4<<3], :modrmA end def init_sse41_only init_cpu_constants addop('blendpd', [0x0F, 0x3A, 0x0D], :mrmxmm) { |o| o.props[:needpfx] = 0x66 } addop('blendps', [0x0F, 0x3A, 0x0C], :mrmxmm) { |o| o.props[:needpfx] = 0x66 } addop('blendvpd', [0x0F, 0x38, 0x15], :mrmxmm) { |o| o.props[:needpfx] = 0x66 } addop('blendvps', [0x0F, 0x38, 0x14], :mrmxmm) { |o| o.props[:needpfx] = 0x66 } addop('dppd', [0x0F, 0x3A, 0x41], :mrmxmm, :u8) { |o| o.props[:needpfx] = 0x66 } addop('dpps', [0x0F, 0x3A, 0x40], :mrmxmm, :u8) { |o| o.props[:needpfx] = 0x66 } addop('extractps',[0x0F, 0x3A, 0x17], :mrmxmm, :u8) { |o| o.props[:needpfx] = 0x66 } addop('insertps', [0x0F, 0x3A, 0x21], :mrmxmm, :u8) { |o| o.props[:needpfx] = 0x66 } addop('movntdqa', [0x0F, 0x38, 0x2A], :mrmxmm, :modrmA) { |o| o.props[:needpfx] = 0x66 } addop('mpsadbw', [0x0F, 0x3A, 0x42], :mrmxmm, :u8) { |o| o.props[:needpfx] = 0x66 } addop('packusdw', [0x0F, 0x38, 0x2B], :mrmxmm) { |o| o.props[:needpfx] = 0x66 } addop('pblendvb', [0x0F, 0x38, 0x10], :mrmxmm) { |o| o.props[:needpfx] = 0x66 } addop('pblendw', [0x0F, 0x3A, 0x1E], :mrmxmm, :u8) { |o| o.props[:needpfx] = 0x66 } addop('pcmpeqq', [0x0F, 0x38, 0x29], :mrmxmm) { |o| o.props[:needpfx] = 0x66 } addop('pextrb', [0x0F, 0x3A, 0x14], :mrmxmm, :u8) { |o| o.props[:needpfx] = 0x66; o.args.index(:modrmxmm); o.args.unshift(:modrm); o.props[:argsz] = 8 } addop('pextrw', [0x0F, 0x3A, 0x15], :mrmxmm, :u8) { |o| o.props[:needpfx] = 0x66; o.args.index(:modrmxmm); o.args.unshift(:modrm); o.props[:argsz] = 16 } addop('pextrd', [0x0F, 0x3A, 0x16], :mrmxmm, :u8) { |o| o.props[:needpfx] = 0x66; o.args.index(:modrmxmm); o.args.unshift(:modrm); o.props[:argsz] = 32 } addop('pinsrb', [0x0F, 0x3A, 0x20], :mrmxmm, :u8) { |o| o.props[:needpfx] = 0x66; o.args[o.args.index(:modrmxmm)] = :modrm; o.props[:argsz] = 8 } addop('pinsrw', [0x0F, 0x3A, 0x21], :mrmxmm, :u8) { |o| o.props[:needpfx] = 0x66; o.args[o.args.index(:modrmxmm)] = :modrm; o.props[:argsz] = 16 } addop('pinsrd', [0x0F, 0x3A, 0x22], :mrmxmm, :u8) { |o| o.props[:needpfx] = 0x66; o.args[o.args.index(:modrmxmm)] = :modrm; o.props[:argsz] = 32 } addop('phminposuw', [0x0F, 0x38, 0x41], :mrmxmm) { |o| o.props[:needpfx] = 0x66 } addop('pminsb', [0x0F, 0x38, 0x38], :mrmxmm) { |o| o.props[:needpfx] = 0x66 } addop('pminsd', [0x0F, 0x38, 0x39], :mrmxmm) { |o| o.props[:needpfx] = 0x66 } addop('pminuw', [0x0F, 0x38, 0x3A], :mrmxmm) { |o| o.props[:needpfx] = 0x66 } addop('pminud', [0x0F, 0x38, 0x3B], :mrmxmm) { |o| o.props[:needpfx] = 0x66 } addop('pmaxsb', [0x0F, 0x38, 0x3C], :mrmxmm) { |o| o.props[:needpfx] = 0x66 } addop('pmaxsd', [0x0F, 0x38, 0x3D], :mrmxmm) { |o| o.props[:needpfx] = 0x66 } addop('pmaxuw', [0x0F, 0x38, 0x3E], :mrmxmm) { |o| o.props[:needpfx] = 0x66 } addop('pmaxud', [0x0F, 0x38, 0x3F], :mrmxmm) { |o| o.props[:needpfx] = 0x66 } addop('pmovsxbw', [0x0F, 0x38, 0x20], :mrmxmm) { |o| o.props[:needpfx] = 0x66 } addop('pmovsxbd', [0x0F, 0x38, 0x21], :mrmxmm) { |o| o.props[:needpfx] = 0x66 } addop('pmovsxbq', [0x0F, 0x38, 0x22], :mrmxmm) { |o| o.props[:needpfx] = 0x66 } addop('pmovsxwd', [0x0F, 0x38, 0x23], :mrmxmm) { |o| o.props[:needpfx] = 0x66 } addop('pmovsxwq', [0x0F, 0x38, 0x24], :mrmxmm) { |o| o.props[:needpfx] = 0x66 } addop('pmovsxdq', [0x0F, 0x38, 0x25], :mrmxmm) { |o| o.props[:needpfx] = 0x66 } addop('pmovzxbw', [0x0F, 0x38, 0x30], :mrmxmm) { |o| o.props[:needpfx] = 0x66 } addop('pmovzxbd', [0x0F, 0x38, 0x31], :mrmxmm) { |o| o.props[:needpfx] = 0x66 } addop('pmovzxbq', [0x0F, 0x38, 0x32], :mrmxmm) { |o| o.props[:needpfx] = 0x66 } addop('pmovzxwd', [0x0F, 0x38, 0x33], :mrmxmm) { |o| o.props[:needpfx] = 0x66 } addop('pmovzxwq', [0x0F, 0x38, 0x34], :mrmxmm) { |o| o.props[:needpfx] = 0x66 } addop('pmovzxdq', [0x0F, 0x38, 0x35], :mrmxmm) { |o| o.props[:needpfx] = 0x66 } addop('pmuldq', [0x0F, 0x38, 0x28], :mrmxmm) { |o| o.props[:needpfx] = 0x66 } addop('pmulld', [0x0F, 0x38, 0x40], :mrmxmm) { |o| o.props[:needpfx] = 0x66 } addop('ptest', [0x0F, 0x38, 0x17], :mrmxmm) { |o| o.props[:needpfx] = 0x66 } addop('roundps', [0x0F, 0x3A, 0x08], :mrmxmm, :u8) { |o| o.props[:needpfx] = 0x66 } addop('roundpd', [0x0F, 0x3A, 0x09], :mrmxmm, :u8) { |o| o.props[:needpfx] = 0x66 } addop('roundss', [0x0F, 0x3A, 0x0A], :mrmxmm, :u8) { |o| o.props[:needpfx] = 0x66 } addop('roundsd', [0x0F, 0x3A, 0x0B], :mrmxmm, :u8) { |o| o.props[:needpfx] = 0x66 } end def init_sse42_only init_cpu_constants addop('crc32', [0x0F, 0x38, 0xF0], :mrmw) { |o| o.props[:needpfx] = 0xF2 } addop('pcmpestrm', [0x0F, 0x3A, 0x60], :mrmxmm, :i8) { |o| o.props[:needpfx] = 0x66 } addop('pcmpestri', [0x0F, 0x3A, 0x61], :mrmxmm, :i8) { |o| o.props[:needpfx] = 0x66 } addop('pcmpistrm', [0x0F, 0x3A, 0x62], :mrmxmm, :i8) { |o| o.props[:needpfx] = 0x66 } addop('pcmpistri', [0x0F, 0x3A, 0x63], :mrmxmm, :i8) { |o| o.props[:needpfx] = 0x66 } addop('pcmpgtq', [0x0F, 0x38, 0x37], :mrmxmm) { |o| o.props[:needpfx] = 0x66 } addop('popcnt', [0x0F, 0xB8], :mrm) { |o| o.props[:needpfx] = 0xF3 } end def init_avx_only init_cpu_constants add128 = {} add256 = {} %w[movss movsd movlhps movhpd movhlps cvtsi2ss cvtsi2sd sqrtss sqrtsd rsqrtss rcpss addss addsd mulss mulsd cvtss2sd cvtsd2ss subss subsd minss minsd divss divsd maxss maxsd punpcklb punpcklw punpckld packsswb pcmpgtb pcmpgtw pcmpgtd packuswb punpckhb punpckhw punpckhd packssdw punpcklq punpckhq pcmpeqb pcmpeqw pcmpeqd ldmxcsr stmxcsr cmpss cmpsd paddq pmullw psubusb psubusw pminub pand paddusb paddusw pmaxub pandn pavgb pavgw pmulhuw pmulhw psubsb psubsw pminsw por paddsb paddsw pmaxsw pxor pmuludq pmaddwd psadbw psubb psubw psubd psubq paddb paddw paddd phaddw phaddsw phaddd phsubw phsubsw phsubd pmaddubsw palignr pshufb pmulhrsw psignb psignw psignd dppd insertps mpsadbw packusdw pblendw pcmpeqq pinsrb pinsrw pinsrd pinsrq pmaxsb pmaxsd pmaxud pmaxuw pminsb pminsd pminud pminuw pmuldq pmulld roundsd roundss pcmpgtq aesdec aesdeclast aesenc aesenclast pclmulqdq punpcklbw punpcklwd punpckldq punpckhbw punpckhwd punpckhdq punpcklqdq punpckhqdq].each { |n| add128[n] = true } %w[movups movupd movddup movsldup unpcklps unpcklpd unpckhps unpckhpd movaps movshdup movapd movntps movntpd movmskps movmskpd sqrtps sqrtpd rsqrtps rcpps andps andpd andnps andnpd orps orpd xorps xorpd addps addpd mulps mulpd cvtps2pd cvtpd2ps cvtdq2ps cvtps2dq cvttps2dq subps subpd minps minpd divps divpd maxps maxpd movdqa movdqu haddpd haddps hsubpd hsubps cmpps cmppd shufps shufpd addsubpd addsubps cvtpd2dq cvttpd2dq cvtdq2pd movntdq lddqu blendps blendpd blendvps blendvpd dpps ptest roundpd roundps].each { |n| add128[n] = add256[n] = true } varg = Hash.new(1) %w[pabsb pabsw pabsd pmovmskb pshufd pshufhw pshuflw movntdqa pmovsxbw pmovsxbd pmovsxbq pmovsxwd pmovsxwq pmovsxdq pmovzxbw pmovzxbd pmovzxbq pmovzxwd pmovzxwq pmovzxdq aesimc aeskeygenassist lddqu maskmovdqu movapd movaps pcmpestri pcmpestrm pcmpistri pcmpistrm phminposuw cvtpd2dq cvttpd2dq cvtdq2pd cvtps2pd cvtpd2ps cvtdq2ps cvtps2dq cvttps2dq movd movq movddup movdqa movdqu movmskps movmskpd movntdq movntps movntpd movshdup movsldup movups movupd pextrb pextrw pextrd pextrq ptest rcpps roundps roundpd extractps sqrtps sqrtpd comiss comisd ucomiss ucomisd cvttss2si cvttsd2si cvtss2si cvtsd2si ].each { |n| add128[n] = true ; varg[n] = nil } cvtarg128 = { :regmmx => :regxmm, :modrmmmx => :modrmxmm } cvtarg256 = { :regmmx => :regymm, :modrmmmx => :modrmymm, :regxmm => :regymm, :modrmxmm => :modrmymm } # autopromote old sseX opcodes @opcode_list.each { |o| next if o.bin[0] != 0x0F or not add128[o.name] # rep cmpsd / movsd mm = (o.bin[1] == 0x38 ? 0x0F38 : o.bin[1] == 0x3A ? 0x0F3A : 0x0F) pp = o.props[:needpfx] pp = 0x66 if o.props[:xmmx] fpxlen = (mm == 0x0F ? 1 : 2) addop_vex('v' + o.name, [varg[o.name], 128, pp, mm], o.bin[fpxlen], nil, *o.args.map { |oa| cvtarg128[oa] || oa }) { |oo| oo.bin += [o.bin[fpxlen+1]] if o.bin[fpxlen+1] dbinlen = o.bin.length - oo.bin.length o.fields.each { |k, v| oo.fields[cvtarg128[k] || k] = [v[0]-dbinlen, v[1]] } o.props.each { |k, v| oo.props[k] = v if k != :xmmx and k != :needpfx } } next if not add256[o.name] addop_vex('v' + o.name, [varg[o.name], 256, pp, mm], o.bin[fpxlen], nil, *o.args.map { |oa| cvtarg256[oa] || oa }) { |oo| oo.bin += [o.bin[fpxlen+1]] if o.bin[fpxlen+1] dbinlen = o.bin.length - oo.bin.length o.fields.each { |k, v| oo.fields[cvtarg256[k] || k] = [v[0]-dbinlen, v[1]] } o.props.each { |k, v| oo.props[k] = v if k != :xmmx and k != :needpfx } } } # sse promotion, special cases addop_vex 'vpblendvb', [1, 128, 0x66, 0x0F3A, 0], 0x4C, :mrmxmm, :i4xmm addop_vex 'vpsllw', [1, 128, 0x66, 0x0F], 0xF1, :mrmxmm addop_vex('vpsllw', [0, 128, 0x66, 0x0F], 0x71, 6, :u8, :modrmR) { |o| o.args[o.args.index(:modrm)] = :modrmxmm } addop_vex 'vpslld', [1, 128, 0x66, 0x0F], 0xF2, :mrmxmm addop_vex('vpslld', [0, 128, 0x66, 0x0F], 0x72, 6, :u8, :modrmR) { |o| o.args[o.args.index(:modrm)] = :modrmxmm } addop_vex 'vpsllq', [1, 128, 0x66, 0x0F], 0xF3, :mrmxmm addop_vex('vpsllq', [0, 128, 0x66, 0x0F], 0x73, 6, :u8, :modrmR) { |o| o.args[o.args.index(:modrm)] = :modrmxmm } addop_vex('vpslldq',[0, 128, 0x66, 0x0F], 0x73, 7, :u8, :modrmR) { |o| o.args[o.args.index(:modrm)] = :modrmxmm } addop_vex 'vpsraw', [1, 128, 0x66, 0x0F], 0xE1, :mrmxmm addop_vex('vpsraw', [0, 128, 0x66, 0x0F], 0x71, 4, :u8, :modrmR) { |o| o.args[o.args.index(:modrm)] = :modrmxmm } addop_vex 'vpsrad', [1, 128, 0x66, 0x0F], 0xE2, :mrmxmm addop_vex('vpsrad', [0, 128, 0x66, 0x0F], 0x72, 4, :u8, :modrmR) { |o| o.args[o.args.index(:modrm)] = :modrmxmm } addop_vex 'vpsrlw', [1, 128, 0x66, 0x0F], 0xD1, :mrmxmm addop_vex('vpsrlw', [0, 128, 0x66, 0x0F], 0x71, 2, :u8, :modrmR) { |o| o.args[o.args.index(:modrm)] = :modrmxmm } addop_vex 'vpsrld', [1, 128, 0x66, 0x0F], 0xD2, :mrmxmm addop_vex('vpsrld', [0, 128, 0x66, 0x0F], 0x72, 2, :u8, :modrmR) { |o| o.args[o.args.index(:modrm)] = :modrmxmm } addop_vex 'vpsrlq', [1, 128, 0x66, 0x0F], 0xD3, :mrmxmm addop_vex('vpsrlq', [0, 128, 0x66, 0x0F], 0x73, 2, :u8, :modrmR) { |o| o.args[o.args.index(:modrm)] = :modrmxmm } addop_vex('vpsrldq',[0, 128, 0x66, 0x0F], 0x73, 3, :u8, :modrmR) { |o| o.args[o.args.index(:modrm)] = :modrmxmm } # dst==mem => no vreg addop_vex 'vmovhps', [1, 128, nil, 0x0F], 0x16, :mrmxmm, :modrmA addop_vex('vmovhps', [nil, 128, nil, 0x0F], 0x17, :mrmxmm, :modrmA) { |o| o.args.reverse! } addop_vex 'vmovlpd', [1, 128, 0x66, 0x0F], 0x12, :mrmxmm, :modrmA addop_vex('vmovlpd', [nil, 128, 0x66, 0x0F], 0x13, :mrmxmm, :modrmA) { |o| o.args.reverse! } addop_vex 'vmovlps', [1, 128, nil, 0x0F], 0x12, :mrmxmm, :modrmA addop_vex('vmovlps', [nil, 128, nil, 0x0F], 0x13, :mrmxmm, :modrmA) { |o| o.args.reverse! } addop_vex 'vbroadcastss', [nil, 128, 0x66, 0x0F38, 0], 0x18, :mrmxmm, :modrmA addop_vex 'vbroadcastss', [nil, 256, 0x66, 0x0F38, 0], 0x18, :mrmymm, :modrmA addop_vex 'vbroadcastsd', [nil, 256, 0x66, 0x0F38, 0], 0x19, :mrmymm, :modrmA addop_vex 'vbroadcastf128', [nil, 256, 0x66, 0x0F38, 0], 0x1A, :mrmymm, :modrmA # general-purpose register operations addop_vex 'andn', [1, :vexvreg, 128, nil, 0x0F38], 0xF2, :mrm addop_vex 'bextr', [2, :vexvreg, 128, nil, 0x0F38], 0xF7, :mrm addop_vex 'blsi', [0, :vexvreg, 128, nil, 0x0F38], 0xF3, 3 addop_vex 'blsmsk', [0, :vexvreg, 128, nil, 0x0F38], 0xF3, 2 addop_vex 'blsr', [0, :vexvreg, 128, nil, 0x0F38], 0xF3, 1 addop_vex 'bzhi', [2, :vexvreg, 128, nil, 0x0F38], 0xF5, :mrm addop('lzcnt', [0x0F, 0xBD], :mrm) { |o| o.props[:needpfx] = 0xF3 } addop_vex 'mulx', [1, :vexvreg, 128, 0xF2, 0x0F38], 0xF6, :mrm addop_vex 'pdep', [1, :vexvreg, 128, 0xF2, 0x0F38], 0xF5, :mrm addop_vex 'pext', [1, :vexvreg, 128, 0xF3, 0x0F38], 0xF5, :mrm addop_vex 'rorx', [nil, 128, 0xF2, 0x0F3A], 0xF0, :mrm, :u8 addop_vex 'sarx', [2, :vexvreg, 128, 0xF3, 0x0F38], 0xF7, :mrm addop_vex 'shrx', [2, :vexvreg, 128, 0xF2, 0x0F38], 0xF7, :mrm addop_vex 'shlx', [2, :vexvreg, 128, 0x66, 0x0F38], 0xF7, :mrm addop('tzcnt', [0x0F, 0xBC], :mrm) { |o| o.props[:needpfx] = 0xF3 } addop('invpcid', [0x0F, 0x38, 0x82], :mrm) { |o| o.props[:needpfx] = 0x66 } addop 'rdrand', [0x0F, 0xC7], 6, :modrmR addop 'rdseed', [0x0F, 0xC7], 7, :modrmR addop('adcx', [0x0F, 0x38, 0xF6], :mrm) { |o| o.props[:needpfx] = 0x66 } addop('adox', [0x0F, 0x38, 0xF6], :mrm) { |o| o.props[:needpfx] = 0xF3 } # fp16 addop_vex 'vcvtph2ps', [nil, 128, 0x66, 0x0F38, 0], 0x13, :mrmxmm addop_vex 'vcvtph2ps', [nil, 256, 0x66, 0x0F38, 0], 0x13, :mrmymm addop_vex('vcvtps2ph', [nil, 128, 0x66, 0x0F3A, 0], 0x1D, :mrmxmm, :u8) { |o| o.args.reverse! } addop_vex('vcvtps2ph', [nil, 256, 0x66, 0x0F3A, 0], 0x1D, :mrmymm, :u8) { |o| o.args.reverse! } # TSE addop 'xabort', [0xC6, 0xF8], nil, :i8 # may :stopexec addop 'xbegin', [0xC7, 0xF8], nil, :i # may :setip: xabortreturns to $_(xbegin) + off addop 'xend', [0x0F, 0x01, 0xD5] addop 'xtest', [0x0F, 0x01, 0xD6] # SMAP addop 'clac', [0x0F, 0x01, 0xCA] addop 'stac', [0x0F, 0x01, 0xCB] end def init_avx2_only init_cpu_constants add256 = {} %w[packsswb pcmpgtb pcmpgtw pcmpgtd packuswb packssdw pcmpeqb pcmpeqw pcmpeqd paddq pmullw psubusb psubusw pminub pand paddusb paddusw pmaxub pandn pavgb pavgw pmulhuw pmulhw psubsb psubsw pminsw por paddsb paddsw pmaxsw pxor pmuludq pmaddwd psadbw psubb psubw psubd psubq paddb paddw paddd phaddw phaddsw phaddd phsubw phsubsw phsubd pmaddubsw palignr pshufb pmulhrsw psignb psignw psignd mpsadbw packusdw pblendw pcmpeqq pmaxsb pmaxsd pmaxud pmaxuw pminsb pminsd pminud pminuw pmuldq pmulld pcmpgtq punpcklbw punpcklwd punpckldq punpckhbw punpckhwd punpckhdq punpcklqdq punpckhqdq ].each { |n| add256[n] = true } varg = Hash.new(1) %w[pabsb pabsw pabsd pmovmskb pshufd pshufhw pshuflw movntdqa pmovsxbw pmovsxbd pmovsxbq pmovsxwd pmovsxwq pmovsxdq pmovzxbw pmovzxbd pmovzxbq pmovzxwd pmovzxwq pmovzxdq maskmovdqu].each { |n| add256[n] = true ; varg[n] = nil } cvtarg256 = { :regmmx => :regymm, :modrmmmx => :modrmymm, :regxmm => :regymm, :modrmxmm => :modrmymm } # autopromote old sseX opcodes @opcode_list.each { |o| next if o.bin[0] != 0x0F or not add256[o.name] mm = (o.bin[1] == 0x38 ? 0x0F38 : o.bin[1] == 0x3A ? 0x0F3A : 0x0F) pp = o.props[:needpfx] pp = 0x66 if o.props[:xmmx] fpxlen = (mm == 0x0F ? 1 : 2) addop_vex('v' + o.name, [varg[o.name], 256, pp, mm], o.bin[fpxlen], nil, *o.args.map { |oa| cvtarg256[oa] || oa }) { |oo| oo.bin += [o.bin[fpxlen+1]] if o.bin[fpxlen+1] dbinlen = o.bin.length - oo.bin.length o.fields.each { |k, v| oo.fields[cvtarg256[k] || k] = [v[0]-dbinlen, v[1]] } o.props.each { |k, v| oo.props[k] = v if k != :xmmx and k != :needpfx } } } # promote special cases addop_vex 'vpblendvb', [1, 256, 0x66, 0x0F3A, 0], 0x4C, :mrmymm, :i4ymm addop_vex 'vpsllw', [1, 256, 0x66, 0x0F], 0xF1, :mrmymm addop_vex('vpsllw', [0, 256, 0x66, 0x0F], 0x71, 6, :u8, :modrmR) { |o| o.args[o.args.index(:modrm)] = :modrmymm } addop_vex 'vpslld', [1, 256, 0x66, 0x0F], 0xF2, :mrmymm addop_vex('vpslld', [0, 256, 0x66, 0x0F], 0x72, 6, :u8, :modrmR) { |o| o.args[o.args.index(:modrm)] = :modrmymm } addop_vex 'vpsllq', [1, 256, 0x66, 0x0F], 0xF3, :mrmymm addop_vex('vpsllq', [0, 256, 0x66, 0x0F], 0x73, 6, :u8, :modrmR) { |o| o.args[o.args.index(:modrm)] = :modrmymm } addop_vex('vpslldq',[0, 256, 0x66, 0x0F], 0x73, 7, :u8, :modrmR) { |o| o.args[o.args.index(:modrm)] = :modrmymm } addop_vex 'vpsraw', [1, 256, 0x66, 0x0F], 0xE1, :mrmymm addop_vex('vpsraw', [0, 256, 0x66, 0x0F], 0x71, 4, :u8, :modrmR) { |o| o.args[o.args.index(:modrm)] = :modrmymm } addop_vex 'vpsrad', [1, 256, 0x66, 0x0F], 0xE2, :mrmymm addop_vex('vpsrad', [0, 256, 0x66, 0x0F], 0x72, 4, :u8, :modrmR) { |o| o.args[o.args.index(:modrm)] = :modrmymm } addop_vex 'vpsrlw', [1, 256, 0x66, 0x0F], 0xD1, :mrmymm addop_vex('vpsrlw', [0, 256, 0x66, 0x0F], 0x71, 2, :u8, :modrmR) { |o| o.args[o.args.index(:modrm)] = :modrmymm } addop_vex 'vpsrld', [1, 256, 0x66, 0x0F], 0xD2, :mrmymm addop_vex('vpsrld', [0, 256, 0x66, 0x0F], 0x72, 2, :u8, :modrmR) { |o| o.args[o.args.index(:modrm)] = :modrmymm } addop_vex 'vpsrlq', [1, 256, 0x66, 0x0F], 0xD3, :mrmymm addop_vex('vpsrlq', [0, 256, 0x66, 0x0F], 0x73, 2, :u8, :modrmR) { |o| o.args[o.args.index(:modrm)] = :modrmymm } addop_vex('vpsrldq',[0, 256, 0x66, 0x0F], 0x73, 3, :u8, :modrmR) { |o| o.args[o.args.index(:modrm)] = :modrmymm } addop_vex 'vbroadcastss', [nil, 128, 0x66, 0x0F38, 0], 0x18, :mrmxmm, :modrmR addop_vex 'vbroadcastss', [nil, 256, 0x66, 0x0F38, 0], 0x18, :mrmymm, :modrmR addop_vex 'vbroadcastsd', [nil, 256, 0x66, 0x0F38, 0], 0x19, :mrmymm, :modrmR addop_vex 'vbroadcasti128', [nil, 256, 0x66, 0x0F38, 0], 0x5A, :mrmymm, :modrmA addop_vex 'vpblendd', [1, 128, 0x66, 0x0F3A, 0], 0x02, :mrmxmm, :u8 addop_vex 'vpblendd', [1, 256, 0x66, 0x0F3A, 0], 0x02, :mrmymm, :u8 addop_vex 'vpbroadcastb', [nil, 128, 0x66, 0x0F38, 0], 0x78, :mrmxmm addop_vex 'vpbroadcastb', [nil, 256, 0x66, 0x0F38, 0], 0x78, :mrmymm addop_vex 'vpbroadcastw', [nil, 128, 0x66, 0x0F38, 0], 0x79, :mrmxmm addop_vex 'vpbroadcastw', [nil, 256, 0x66, 0x0F38, 0], 0x79, :mrmymm addop_vex 'vpbroadcastd', [nil, 128, 0x66, 0x0F38, 0], 0x58, :mrmxmm addop_vex 'vpbroadcastd', [nil, 256, 0x66, 0x0F38, 0], 0x58, :mrmymm addop_vex 'vpbroadcastq', [nil, 128, 0x66, 0x0F38, 0], 0x59, :mrmxmm addop_vex 'vpbroadcastq', [nil, 256, 0x66, 0x0F38, 0], 0x59, :mrmymm addop_vex 'vpermd', [1, 256, 0x66, 0x0F38, 0], 0x36, :mrmymm addop_vex 'vpermpd', [nil, 256, 0x66, 0x0F3A, 1], 0x01, :mrmymm, :u8 addop_vex 'vpermps', [1, 256, 0x66, 0x0F38, 0], 0x16, :mrmymm, :u8 addop_vex 'vpermq', [nil, 256, 0x66, 0x0F3A, 1], 0x00, :mrmymm, :u8 addop_vex 'vperm2i128', [1, 256, 0x66, 0x0F3A, 0], 0x46, :mrmymm, :u8 addop_vex 'vextracti128', [nil, 256, 0x66, 0x0F3A, 0], 0x39, :mrmymm, :u8 addop_vex 'vinserti128', [1, 256, 0x66, 0x0F3A, 0], 0x38, :mrmymm, :u8 addop_vex 'vpmaskmovd', [1, 128, 0x66, 0x0F38, 0], 0x8C, :mrmxmm, :modrmA addop_vex 'vpmaskmovd', [1, 256, 0x66, 0x0F38, 0], 0x8C, :mrmymm, :modrmA addop_vex 'vpmaskmovq', [1, 128, 0x66, 0x0F38, 1], 0x8C, :mrmxmm, :modrmA addop_vex 'vpmaskmovq', [1, 256, 0x66, 0x0F38, 1], 0x8C, :mrmymm, :modrmA addop_vex('vpmaskmovd', [1, 128, 0x66, 0x0F38, 0], 0x8E, :mrmxmm, :modrmA) { |o| o.args.reverse! } addop_vex('vpmaskmovd', [1, 256, 0x66, 0x0F38, 0], 0x8E, :mrmymm, :modrmA) { |o| o.args.reverse! } addop_vex('vpmaskmovq', [1, 128, 0x66, 0x0F38, 1], 0x8E, :mrmxmm, :modrmA) { |o| o.args.reverse! } addop_vex('vpmaskmovq', [1, 256, 0x66, 0x0F38, 1], 0x8E, :mrmymm, :modrmA) { |o| o.args.reverse! } addop_vex 'vpsllvd', [1, 128, 0x66, 0x0F38, 0], 0x47, :mrmxmm addop_vex 'vpsllvq', [1, 128, 0x66, 0x0F38, 1], 0x47, :mrmxmm addop_vex 'vpsllvd', [1, 256, 0x66, 0x0F38, 0], 0x47, :mrmymm addop_vex 'vpsllvq', [1, 256, 0x66, 0x0F38, 1], 0x47, :mrmymm addop_vex 'vpsravd', [1, 128, 0x66, 0x0F38, 0], 0x46, :mrmxmm addop_vex 'vpsravd', [1, 256, 0x66, 0x0F38, 0], 0x46, :mrmymm addop_vex 'vpsrlvd', [1, 128, 0x66, 0x0F38, 0], 0x45, :mrmxmm addop_vex 'vpsrlvq', [1, 128, 0x66, 0x0F38, 1], 0x45, :mrmxmm addop_vex 'vpsrlvd', [1, 256, 0x66, 0x0F38, 0], 0x45, :mrmymm addop_vex 'vpsrlvq', [1, 256, 0x66, 0x0F38, 1], 0x45, :mrmymm addop_vex('vpgatherdd', [2, 128, 0x66, 0x0F38, 0], 0x90, :mrmxmm) { |o| o.props[:argsz] = 32 ; o.props[:mrmvex] = 128 } addop_vex('vpgatherdd', [2, 256, 0x66, 0x0F38, 0], 0x90, :mrmymm) { |o| o.props[:argsz] = 32 ; o.props[:mrmvex] = 256 } addop_vex('vpgatherdq', [2, 128, 0x66, 0x0F38, 1], 0x90, :mrmxmm) { |o| o.props[:argsz] = 64 ; o.props[:mrmvex] = 128 } addop_vex('vpgatherdq', [2, 256, 0x66, 0x0F38, 1], 0x90, :mrmymm) { |o| o.props[:argsz] = 64 ; o.props[:mrmvex] = 256 } addop_vex('vpgatherqd', [2, 128, 0x66, 0x0F38, 0], 0x91, :mrmxmm) { |o| o.props[:argsz] = 32 ; o.props[:mrmvex] = 128 } addop_vex('vpgatherqd', [2, 256, 0x66, 0x0F38, 0], 0x91, :mrmymm) { |o| o.props[:argsz] = 32 ; o.props[:mrmvex] = 256 } addop_vex('vpgatherqq', [2, 128, 0x66, 0x0F38, 1], 0x91, :mrmxmm) { |o| o.props[:argsz] = 64 ; o.props[:mrmvex] = 128 } addop_vex('vpgatherqq', [2, 256, 0x66, 0x0F38, 1], 0x91, :mrmymm) { |o| o.props[:argsz] = 64 ; o.props[:mrmvex] = 256 } addop_vex('vgatherdps', [2, 128, 0x66, 0x0F38, 0], 0x92, :mrmxmm) { |o| o.props[:argsz] = 32 ; o.props[:mrmvex] = 128 } addop_vex('vgatherdps', [2, 256, 0x66, 0x0F38, 0], 0x92, :mrmymm) { |o| o.props[:argsz] = 32 ; o.props[:mrmvex] = 256 } addop_vex('vgatherdpd', [2, 128, 0x66, 0x0F38, 1], 0x92, :mrmxmm) { |o| o.props[:argsz] = 64 ; o.props[:mrmvex] = 128 } addop_vex('vgatherdpd', [2, 256, 0x66, 0x0F38, 1], 0x92, :mrmymm) { |o| o.props[:argsz] = 64 ; o.props[:mrmvex] = 256 } addop_vex('vgatherqps', [2, 128, 0x66, 0x0F38, 0], 0x93, :mrmxmm) { |o| o.props[:argsz] = 32 ; o.props[:mrmvex] = 128 } addop_vex('vgatherqps', [2, 256, 0x66, 0x0F38, 0], 0x93, :mrmymm) { |o| o.props[:argsz] = 32 ; o.props[:mrmvex] = 256 } addop_vex('vgatherqpd', [2, 128, 0x66, 0x0F38, 1], 0x93, :mrmxmm) { |o| o.props[:argsz] = 64 ; o.props[:mrmvex] = 128 } addop_vex('vgatherqpd', [2, 256, 0x66, 0x0F38, 1], 0x93, :mrmymm) { |o| o.props[:argsz] = 64 ; o.props[:mrmvex] = 256 } end def init_fma_only init_cpu_constants [['vfmaddsub', 'p', 0x86], ['vfmsubadd', 'p', 0x87], ['vfmadd', 'p', 0x88], ['vfmadd', 's', 0x89], ['vfmsub', 'p', 0x8A], ['vfmsub', 's', 0x8B], ['vfnmadd', 'p', 0x8C], ['vfnmadd', 's', 0x8D], ['vfnmsub', 'p', 0x8E], ['vfnmsub', 's', 0x8F]].each { |n1, n2, bin| addop_vex n1 + '132' + n2 + 's', [1, 128, 0x66, 0x0F38, 0], bin | 0x10, :mrmxmm addop_vex n1 + '132' + n2 + 's', [1, 256, 0x66, 0x0F38, 0], bin | 0x10, :mrmymm addop_vex n1 + '132' + n2 + 'd', [1, 128, 0x66, 0x0F38, 1], bin | 0x10, :mrmxmm addop_vex n1 + '132' + n2 + 'd', [1, 256, 0x66, 0x0F38, 1], bin | 0x10, :mrmymm addop_vex n1 + '213' + n2 + 's', [1, 128, 0x66, 0x0F38, 0], bin | 0x20, :mrmxmm addop_vex n1 + '213' + n2 + 's', [1, 256, 0x66, 0x0F38, 0], bin | 0x20, :mrmymm addop_vex n1 + '213' + n2 + 'd', [1, 128, 0x66, 0x0F38, 1], bin | 0x20, :mrmxmm addop_vex n1 + '213' + n2 + 'd', [1, 256, 0x66, 0x0F38, 1], bin | 0x20, :mrmymm addop_vex n1 + '231' + n2 + 's', [1, 128, 0x66, 0x0F38, 0], bin | 0x30, :mrmxmm addop_vex n1 + '231' + n2 + 's', [1, 256, 0x66, 0x0F38, 0], bin | 0x30, :mrmymm addop_vex n1 + '231' + n2 + 'd', [1, 128, 0x66, 0x0F38, 1], bin | 0x30, :mrmxmm addop_vex n1 + '231' + n2 + 'd', [1, 256, 0x66, 0x0F38, 1], bin | 0x30, :mrmymm # pseudo-opcodes aliases (swap arg0/arg1) addop_vex(n1 + '312' + n2 + 's', [1, 128, 0x66, 0x0F38, 0], bin | 0x10, :mrmxmm) { |o| o.args[0, 2] = o.args[0, 2].reverse } addop_vex(n1 + '312' + n2 + 's', [1, 256, 0x66, 0x0F38, 0], bin | 0x10, :mrmymm) { |o| o.args[0, 2] = o.args[0, 2].reverse } addop_vex(n1 + '312' + n2 + 'd', [1, 128, 0x66, 0x0F38, 1], bin | 0x10, :mrmxmm) { |o| o.args[0, 2] = o.args[0, 2].reverse } addop_vex(n1 + '312' + n2 + 'd', [1, 256, 0x66, 0x0F38, 1], bin | 0x10, :mrmymm) { |o| o.args[0, 2] = o.args[0, 2].reverse } addop_vex(n1 + '123' + n2 + 's', [1, 128, 0x66, 0x0F38, 0], bin | 0x20, :mrmxmm) { |o| o.args[0, 2] = o.args[0, 2].reverse } addop_vex(n1 + '123' + n2 + 's', [1, 256, 0x66, 0x0F38, 0], bin | 0x20, :mrmymm) { |o| o.args[0, 2] = o.args[0, 2].reverse } addop_vex(n1 + '123' + n2 + 'd', [1, 128, 0x66, 0x0F38, 1], bin | 0x20, :mrmxmm) { |o| o.args[0, 2] = o.args[0, 2].reverse } addop_vex(n1 + '123' + n2 + 'd', [1, 256, 0x66, 0x0F38, 1], bin | 0x20, :mrmymm) { |o| o.args[0, 2] = o.args[0, 2].reverse } addop_vex(n1 + '321' + n2 + 's', [1, 128, 0x66, 0x0F38, 0], bin | 0x30, :mrmxmm) { |o| o.args[0, 2] = o.args[0, 2].reverse } addop_vex(n1 + '321' + n2 + 's', [1, 256, 0x66, 0x0F38, 0], bin | 0x30, :mrmymm) { |o| o.args[0, 2] = o.args[0, 2].reverse } addop_vex(n1 + '321' + n2 + 'd', [1, 128, 0x66, 0x0F38, 1], bin | 0x30, :mrmxmm) { |o| o.args[0, 2] = o.args[0, 2].reverse } addop_vex(n1 + '321' + n2 + 'd', [1, 256, 0x66, 0x0F38, 1], bin | 0x30, :mrmymm) { |o| o.args[0, 2] = o.args[0, 2].reverse } } end # # CPU family dependencies # def init_386_common init_386_common_only end def init_386 init_386_common init_386_only end def init_387 init_387_only end def init_486 init_386 init_387 init_486_only end def init_pentium init_486 init_pentium_only end def init_3dnow init_pentium init_3dnow_only end def init_p6 init_pentium init_p6_only end def init_sse init_p6 init_sse_only end def init_sse2 init_sse init_sse2_only end def init_sse3 init_sse2 init_sse3_only end def init_ssse3 init_sse3 init_ssse3_only end def init_sse41 init_ssse3 init_sse41_only end def init_sse42 init_sse41 init_sse42_only end def init_avx init_sse42 init_avx_only end def init_avx2 init_avx init_fma_only init_avx2_only end def init_all init_avx2 init_3dnow_only init_vmx_only init_aesni_only end alias init_latest init_all # # addop_* macros # def addop_macro1(name, num, *props) addop name, [(num << 3) | 4], nil, {:w => [0, 0]}, :reg_eax, :i, *props addop(name, [num << 3], :mrmw, {:d => [0, 1]}) { |o| o.args.reverse! } addop name, [0x80], num, {:w => [0, 0], :s => [0, 1]}, :i, *props end def addop_macro2(name, num) addop name, [0x0F, 0xBA], (4 | num), :u8 addop(name, [0x0F, 0xA3 | (num << 3)], :mrm) { |op| op.args.reverse! } end def addop_macro3(name, num) addop name, [0xD0], num, {:w => [0, 0]}, :imm_val1 addop name, [0xD2], num, {:w => [0, 0]}, :reg_cl addop name, [0xC0], num, {:w => [0, 0]}, :u8 end def addop_macrotttn(name, bin, hint, *props, &blk) [%w{o}, %w{no}, %w{b nae c}, %w{nb ae nc}, %w{z e}, %w{nz ne}, %w{be na}, %w{nbe a}, %w{s}, %w{ns}, %w{p pe}, %w{np po}, %w{l nge}, %w{nl ge}, %w{le ng}, %w{nle g}].each_with_index { |e, i| b = bin.dup if b[0] == 0x0F b[1] |= i else b[0] |= i end e.each { |k| addop(name + k, b.dup, hint, *props, &blk) } } end def addop_macrostr(name, bin, type) # addop(name, bin.dup, {:w => [0, 0]}) { |o| o.props[type] = true } # TODO allow segment override addop(name+'b', bin) { |o| o.props[:opsz] = 16 ; o.props[type] = true } addop(name+'b', bin) { |o| o.props[:opsz] = 32 ; o.props[type] = true } bin = bin.dup bin[0] |= 1 addop(name+'w', bin) { |o| o.props[:opsz] = 16 ; o.props[type] = true } addop(name+'d', bin) { |o| o.props[:opsz] = 32 ; o.props[type] = true } end def addop_macrofpu1(name, n) addop(name, [0xD8, n<<3], :modrmA, :regfp0) { |o| o.props[:argsz] = 32 } addop(name, [0xDC, n<<3], :modrmA, :regfp0) { |o| o.props[:argsz] = 64 } addop(name, [0xD8, 0xC0|(n<<3)], :regfp, {:d => [0, 2]}) { |o| o.args.reverse! } end def addop_macrofpu2(name, n, n2=0) addop(name, [0xDE|n2, n<<3], :modrmA, :regfp0) { |o| o.props[:argsz] = 16 } addop(name, [0xDA|n2, n<<3], :modrmA, :regfp0) { |o| o.props[:argsz] = 32 } end def addop_macrofpu3(name, n) addop_macrofpu2 name, n, 1 addop(name, [0xDF, 0x28|(n<<3)], :modrmA, :regfp0) { |o| o.props[:argsz] = 64 } end def addop_macrogg(ggrng, name, bin, *args, &blk) ggoff = 1 ggoff = 2 if bin[1] == 0x38 or bin[1] == 0x3A ggrng.each { |gg| bindup = bin.dup bindup[ggoff] |= gg sfx = %w(b w d q)[gg] addop name+sfx, bindup, *args, &blk } end def addop_macrossps(name, bin, hint, *a) addop name, bin.dup, hint, *a addop(name.sub(/ps$/, 'ss'), bin.dup, hint, *a) { |o| o.props[:needpfx] = 0xF3 } end def addop_macrosdpd(name, bin, hint, *a) addop(name, bin.dup, hint, *a) { |o| o.props[:needpfx] = 0x66 } addop(name.sub(/pd$/, 'sd'), bin.dup, hint, *a) { |o| o.props[:needpfx] = 0xF2 } end # special ret (iret/retf), that still default to 32b mode in x64 def addop_macroret(name, bin, *args) addop(name + '.i32', bin.dup, nil, :stopexec, :setip, *args) { |o| o.props[:opsz] = 32 } addop(name + '.i16', bin.dup, nil, :stopexec, :setip, *args) { |o| o.props[:opsz] = 16 } if name != 'sysret' addop(name, bin.dup, nil, :stopexec, :setip, *args) { |o| o.props[:opsz] = @size } end # add an AVX instruction needing a VEX prefix (c4h/c5h) # the prefix is hardcoded def addop_vex(name, vexspec, bin, *args) argnr = vexspec.shift argt = vexspec.shift if argnr and vexspec.first.kind_of?(::Symbol) l = vexspec.shift pfx = vexspec.shift of = vexspec.shift w = vexspec.shift argt ||= (l == 128 ? :vexvxmm : :vexvymm) lpp = ((l >> 8) << 2) | [nil, 0x66, 0xF3, 0xF2].index(pfx) mmmmm = [nil, 0x0F, 0x0F38, 0x0F3A].index(of) c4bin = [0xC4, mmmmm, lpp, bin] c4bin[1] |= 1 << 7 if @size != 64 c4bin[1] |= 1 << 6 if @size != 64 c4bin[2] |= 1 << 7 if w == 1 c4bin[2] |= 0xF << 3 if not argnr addop(name, c4bin, *args) { |o| o.args.insert(argnr, argt) if argnr o.fields[:vex_r] = [1, 7] if @size == 64 o.fields[:vex_x] = [1, 6] if @size == 64 o.fields[:vex_b] = [1, 5] o.fields[:vex_w] = [2, 7] if not w o.fields[:vex_vvvv] = [2, 3] if argnr yield o if block_given? } return if w == 1 or mmmmm != 1 c5bin = [0xC5, lpp, bin] c5bin[1] |= 1 << 7 if @size != 64 c5bin[1] |= 0xF << 3 if not argnr addop(name, c5bin, *args) { |o| o.args.insert(argnr, argt) if argnr o.fields[:vex_r] = [1, 7] if @size == 64 o.fields[:vex_vvvv] = [1, 3] if argnr yield o if block_given? } end # helper function: creates a new Opcode based on the arguments, eventually # yields it for further customisation, and append it to the instruction set # is responsible of the creation of disambiguating opcodes if necessary (:s flag hardcoding) def addop(name, bin, hint=nil, *argprops) fields = (argprops.first.kind_of?(Hash) ? argprops.shift : {}) op = Opcode.new name, bin op.fields.replace fields case hint when nil when :mrm, :mrmw, :mrmA op.fields[:reg] = [bin.length, 3] op.fields[:modrm] = [bin.length, 0] op.fields[:w] = [bin.length - 1, 0] if hint == :mrmw argprops.unshift :reg, :modrm argprops << :modrmA if hint == :mrmA op.bin << 0 when :reg op.fields[:reg] = [bin.length-1, 0] argprops.unshift :reg when :regfp op.fields[:regfp] = [bin.length-1, 0] argprops.unshift :regfp, :regfp0 when :modrmA op.fields[:modrm] = [bin.length-1, 0] argprops << :modrm << :modrmA when Integer # mod/m, reg == opcode extension = hint op.fields[:modrm] = [bin.length, 0] op.bin << (hint << 3) argprops.unshift :modrm when :mrmmmx op.fields[:regmmx] = [bin.length, 3] op.fields[:modrm] = [bin.length, 0] bin << 0 argprops.unshift :regmmx, :modrmmmx when :mrmxmm op.fields[:regxmm] = [bin.length, 3] op.fields[:modrm] = [bin.length, 0] bin << 0 argprops.unshift :regxmm, :modrmxmm when :mrmymm op.fields[:regymm] = [bin.length, 3] op.fields[:modrm] = [bin.length, 0] bin << 0 argprops.unshift :regymm, :modrmymm else raise SyntaxError, "invalid hint #{hint.inspect} for #{name}" end argprops.each { |a| op.props[a] = true if @valid_props[a] op.args << a if @valid_args[a] } yield op if block_given? if $DEBUG argprops -= @valid_props.keys + @valid_args.keys raise "Invalid opcode definition: #{name}: unknown #{argprops.inspect}" unless argprops.empty? argprops = (op.props.keys - @valid_props.keys) + (op.args - @valid_args.keys) + (op.fields.keys - @fields_mask.keys) raise "Invalid opcode customisation: #{name}: #{argprops.inspect}" unless argprops.empty? end addop_post(op) end # this recursive method is in charge of Opcode duplication (eg to hardcode some flag) def addop_post(op) if df = op.fields.delete(:d) # hardcode the bit dop = op.dup addop_post dop op.bin[df[0]] |= 1 << df[1] op.args.reverse! addop_post op return elsif wf = op.fields.delete(:w) # hardcode the bit dop = op.dup dop.props[:argsz] = 8 # 64-bit w=0 s=1 => UD dop.fields.delete(:s) if @size == 64 addop_post dop op.bin[wf[0]] |= 1 << wf[1] addop_post op return elsif sf = op.fields.delete(:s) # add explicit choice versions, with lower precedence (so that disassembling will return the general version) # eg "jmp", "jmp.i8", "jmp.i" # also hardcode the bit op32 = op addop_post op32 op8 = op.dup op8.bin[sf[0]] |= 1 << sf[1] op8.args.map! { |arg| arg == :i ? :i8 : arg } addop_post op8 op32 = op32.dup op32.name << '.i' addop_post op32 op8 = op8.dup op8.name << '.i8' addop_post op8 return elsif op.args.first == :regfp0 dop = op.dup dop.args.delete :regfp0 addop_post dop end if op.props[:needpfx] @opcode_list.unshift op else @opcode_list << op end if (op.args == [:i] or op.args == [:farptr] or op.name == 'ret') and op.name !~ /\.i/ # define opsz-override version for ambiguous opcodes op16 = op.dup op16.name << '.i16' op16.props[:opsz] = 16 @opcode_list << op16 op32 = op.dup op32.name << '.i32' op32.props[:opsz] = 32 @opcode_list << op32 elsif op.props[:strop] or op.props[:stropz] or op.args.include? :mrm_imm or op.args.include? :modrm or op.name =~ /loop|xlat/ # define adsz-override version for ambiguous opcodes (TODO allow movsd edi / movsd di syntax) # XXX loop pfx 67 = eip+cx, 66 = ip+ecx op16 = op.dup op16.name << '.a16' op16.props[:adsz] = 16 @opcode_list << op16 op32 = op.dup op32.name << '.a32' op32.props[:adsz] = 32 @opcode_list << op32 end end end end