class Metasm::X86_64
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
The x86_64, 64-bit extension of the x86 CPU
(x64, em64t, amd64…)
Public Class Methods
Create a new instance of an X86
cpu arguments (any order)
-
instruction set (386, 486, sse2…) [latest]
-
endianness [:little]
Metasm::Ia32::new
# File metasm/cpu/x86_64/main.rb, line 113 def initialize(*a) super(:latest) @size = 64 a.delete @size @endianness = (a & [:big, :little]).first || :little a.delete @endianness @family = a.pop || :latest raise "Invalid arguments #{a.inspect}" if not a.empty? raise "Invalid X86_64 family #{@family.inspect}" if not respond_to?("init_#@family") end
Public Instance Methods
Metasm::Ia32#addop_macroret
# File metasm/cpu/x86_64/opcodes.rb, line 96 def addop_macroret(name, bin, *args) addop(name + '.i64', bin, nil, :stopexec, :setip, *args) { |o| o.props[:opsz] = 64 } super(name, bin, *args) end
Metasm::Ia32#addop_macrostr
# File metasm/cpu/x86_64/opcodes.rb, line 89 def addop_macrostr(name, bin, type) super(name, bin, type) bin = bin.dup bin[0] |= 1 addop(name+'q', bin) { |o| o.props[:opsz] = 64 ; o.props[type] = true } end
Metasm::Ia32#addop_post
# File metasm/cpu/x86_64/opcodes.rb, line 101 def addop_post(op) if op.fields[:d] or op.fields[:w] or op.fields[:s] or op.args.first == :regfp0 return super(op) end if op.props[:needpfx] @opcode_list.unshift op else @opcode_list << op end if op.args == [:i] or op.name == 'ret' # define opsz-override version for ambiguous opcodes op16 = op.dup op16.name << '.i16' op16.props[:opsz] = 16 @opcode_list << op16 # push call ret jz can't 32bit op64 = op.dup op64.name << '.i64' op64.props[:opsz] = 64 @opcode_list << op64 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 (movsq) # XXX loop pfx 67 = rip+ecx, 66/rex ignored op32 = op.dup op32.name << '.a32' op32.props[:adsz] = 32 @opcode_list << op32 op64 = op.dup op64.name << '.a64' op64.props[:adsz] = 64 @opcode_list << op64 end end
# File metasm/cpu/x86_64/decode.rb, line 242 def adsz(di, op=nil) if di and di.instruction.prefix and di.instruction.prefix[:adsz] and (op || di.opcode).props[:needpfx] != 0x67; 32 else 64 end end
# File metasm/cpu/x86_64/decode.rb, line 307 def backtrace_update_function_binding_check(dasm, faddr, f, b) # TODO save regs according to ABI end
# File metasm/cpu/x86_64/parse.rb, line 72 def check_reserved_name(name) Reg.s_to_i[name] end
# File metasm/cpu/x86_64/debug.rb, line 26 def dbg_func_arg(dbg, argnr) if dbg.class.name =~ /win/i list = [:rcx, :rdx, :r8, :r9] off = 0x20 else list = [:rdi, :rsi, :rdx, :rcx, :r8, :r9] off = 0 end if r = list[argnr] dbg.get_reg_value(r) else argnr -= list.length dbg.memory_read_int(Expression[:esp, :+, off + 8 + 8*argnr]) end end
# File metasm/cpu/x86_64/debug.rb, line 41 def dbg_func_arg_set(dbg, argnr, arg) if dbg.class.name =~ /win/i list = [:rcx, :rdx, :r8, :r9] off = 0x20 else list = [:rdi, :rsi, :rdx, :rcx, :r8, :r9] off = 0 end if r = list[argnr] dbg.set_reg_value(r, arg) else argnr -= list.length dbg.memory_write_int(Expression[:esp, :+, off + 8 + 8*argnr], arg) end end
# File metasm/cpu/x86_64/debug.rb, line 14 def dbg_register_flags @dbg_register_flags ||= :rflags end
# File metasm/cpu/x86_64/debug.rb, line 18 def dbg_register_list @dbg_register_list ||= [:rax, :rbx, :rcx, :rdx, :rsi, :rdi, :rbp, :rsp, :r8, :r9, :r10, :r11, :r12, :r13, :r14, :r15, :rip] end
# File metasm/cpu/x86_64/debug.rb, line 11 def dbg_register_pc @dbg_register_pc ||= :rip end
# File metasm/cpu/x86_64/debug.rb, line 22 def dbg_register_size @dbg_register_size ||= Hash.new(64).update(:cs => 16, :ds => 16, :es => 16, :fs => 16, :gs => 16) end
returns a DecodedFunction
from a parsed C
function prototype
# File metasm/cpu/x86_64/decode.rb, line 253 def decode_c_function_prototype(cp, sym, orig=nil) sym = cp.toplevel.symbol[sym] if sym.kind_of?(::String) df = DecodedFunction.new orig ||= Expression[sym.name] new_bt = lambda { |expr, rlen| df.backtracked_for << BacktraceTrace.new(expr, orig, expr, rlen ? :r : :x, rlen) } # return instr emulation if sym.has_attribute 'noreturn' or sym.has_attribute '__noreturn__' df.noreturn = true else new_bt[Indirection[:rsp, @size/8, orig], nil] end # register dirty (MS standard ABI) [:rax, :rcx, :rdx, :r8, :r9, :r10, :r11].each { |r| df.backtrace_binding.update r => Expression::Unknown } if cp.lexer.definition['__MS_X86_64_ABI__'] reg_args = [:rcx, :rdx, :r8, :r9] else reg_args = [:rdi, :rsi, :rdx, :rcx, :r8, :r9] end al = cp.typesize[:ptr] df.backtrace_binding[:rsp] = Expression[:rsp, :+, al] # scan args for function pointers # TODO walk structs/unions.. stackoff = al sym.type.args.to_a.zip(reg_args).each { |a, r| if not r r = Indirection[[:rsp, :+, stackoff], al, orig] stackoff += (cp.sizeof(a) + al - 1) / al * al end if a.type.untypedef.kind_of? C::Pointer pt = a.type.untypedef.type.untypedef if pt.kind_of? C::Function new_bt[r, nil] df.backtracked_for.last.detached = true elsif pt.kind_of? C::Struct new_bt[r, al] else new_bt[r, cp.sizeof(nil, pt)] end end } df end
Metasm::Ia32#decode_instr_interpret
# File metasm/cpu/x86_64/decode.rb, line 221 def decode_instr_interpret(di, addr) super(di, addr) # [rip + 42] => [rip - addr + foo] if m = di.instruction.args.grep(ModRM).first and ((m.b and m.b.val == 16) or (m.i and m.i.val == 16)) and m.imm and m.imm.reduce.kind_of?(Integer) m.imm = Expression[[:-, di.address + di.bin_length], :+, di.address+di.bin_length+m.imm.reduce] end di end
# File metasm/cpu/x86_64/decode.rb, line 94 def decode_instr_op(edata, di) before_ptr = edata.ptr op = di.opcode di.instruction.opname = op.name bseq = edata.read(op.bin.length).unpack('C*') # decode_findopcode ensures that data >= op.length pfx = di.instruction.prefix || {} field_val = lambda { |f| if fld = op.fields[f] (bseq[fld[0]] >> fld[1]) & @fields_mask[f] end } field_val_r = lambda { |f| v = field_val[f] v |= 8 if v and (op.fields[f][1] == 3 ? pfx[:rex_r] : pfx[:rex_b]) # gruick ? v } pfx[:rex_r] = 1 if op.fields[:vex_r] and field_val[:vex_r] == 0 pfx[:rex_b] = 1 if op.fields[:vex_b] and field_val[:vex_b] == 0 pfx[:rex_x] = 1 if op.fields[:vex_x] and field_val[:vex_x] == 0 pfx[:rex_w] = 1 if op.fields[:vex_w] and field_val[:vex_w] == 1 di.instruction.prefix = pfx if not di.instruction.prefix and not pfx.empty? # for opsz(di) + vex_w case op.props[:needpfx] when 0x66; pfx.delete :opsz when 0x67; pfx.delete :adsz when 0xF2, 0xF3; pfx.delete :rep end if op.props[:setip] and not op.props[:stopexec] and pfx[:seg] case pfx.delete(:seg).val when 1; pfx[:jmphint] = 'hintnojmp' when 3; pfx[:jmphint] = 'hintjmp' end end opsz = op.props[:argsz] || opsz(di) adsz = pfx[:adsz] ? 32 : 64 mmxsz = (op.props[:xmmx] && pfx[:opsz]) ? 128 : 64 op.args.each { |a| di.instruction.args << case a when :reg; Reg.new field_val_r[a], opsz when :eeec; CtrlReg.new field_val_r[a] when :eeed; DbgReg.new field_val_r[a] when :eeet; TstReg.new field_val_r[a] when :seg2, :seg2A, :seg3, :seg3A; SegReg.new field_val[a] when :regmmx; SimdReg.new field_val[a], mmxsz # rex_r ignored when :regxmm; SimdReg.new field_val_r[a], 128 when :regymm; SimdReg.new field_val_r[a], 256 when :farptr; Farptr.decode edata, @endianness, opsz when :i8, :u8, :i16, :u16, :i32, :u32, :i64, :u64; Expression[edata.decode_imm(a, @endianness)] when :i # 64bit constants are sign-extended from :i32 type = (opsz == 64 ? op.props[:imm64] ? :a64 : :i32 : "#{op.props[:unsigned_imm] ? 'a' : 'i'}#{opsz}".to_sym ) v = edata.decode_imm(type, @endianness) v &= 0xffff_ffff_ffff_ffff if opsz == 64 and op.props[:unsigned_imm] and v.kind_of? Integer Expression[v] when :mrm_imm; ModRM.new(adsz, opsz, nil, nil, nil, Expression[edata.decode_imm("a#{adsz}".to_sym, @endianness)], pfx.delete(:seg)) when :modrm; ModRM.decode edata, field_val[:modrm], @endianness, adsz, opsz, pfx.delete(:seg), Reg, pfx when :modrmmmx; ModRM.decode edata, field_val[:modrm], @endianness, adsz, mmxsz, pfx.delete(:seg), SimdReg, pfx.merge(:argsz => op.props[:argsz]) when :modrmxmm; ModRM.decode edata, field_val[:modrm], @endianness, adsz, 128, pfx.delete(:seg), SimdReg, pfx.merge(:argsz => op.props[:argsz], :mrmvex => op.props[:mrmvex]) when :modrmymm; ModRM.decode edata, field_val[:modrm], @endianness, adsz, 256, pfx.delete(:seg), SimdReg, pfx.merge(:argsz => op.props[:argsz], :mrmvex => op.props[:mrmvex]) when :vexvreg; Reg.new((field_val[:vex_vvvv] ^ 0xf), opsz) when :vexvxmm; SimdReg.new((field_val[:vex_vvvv] ^ 0xf), 128) when :vexvymm; SimdReg.new((field_val[:vex_vvvv] ^ 0xf), 256) when :i4xmm; SimdReg.new(edata.decode_imm(:u8, @endianness) >> 4, 128) when :i4ymm; SimdReg.new(edata.decode_imm(:u8, @endianness) >> 4, 256) when :regfp; FpReg.new field_val[a] when :imm_val1; Expression[1] when :imm_val3; Expression[3] when :reg_cl; Reg.new 1, 8 when :reg_eax; Reg.new 0, opsz when :reg_dx; Reg.new 2, 16 when :regfp0; FpReg.new nil else raise SyntaxError, "Internal error: invalid argument #{a} in #{op.name}" end } di.bin_length += edata.ptr - before_ptr return if edata.ptr > edata.length if op.name == 'movsx' or op.name == 'movzx' or op.name == 'movsxd' if op.name == 'movsxd' di.instruction.args[1].sz = 32 elsif opsz == 8 di.instruction.args[1].sz = 8 else di.instruction.args[1].sz = 16 end if pfx[:rex_w] di.instruction.args[0].sz = 64 elsif pfx[:opsz] di.instruction.args[0].sz = 16 else di.instruction.args[0].sz = 32 end elsif op.name == 'crc32' di.instruction.args[0].sz = 32 end # sil => bh di.instruction.args.each { |a| a.val += 12 if a.kind_of? Reg and a.sz == 8 and not pfx[:rex] and a.val >= 4 and a.val <= 8 } case pfx.delete(:rep) when :nz if di.opcode.props[:strop] pfx[:rep] = 'rep' elsif di.opcode.props[:stropz] pfx[:rep] = 'repnz' end when :z if di.opcode.props[:strop] pfx[:rep] = 'rep' elsif di.opcode.props[:stropz] pfx[:rep] = 'repz' end end di end
Metasm::Ia32#decode_prefix
# File metasm/cpu/x86_64/decode.rb, line 75 def decode_prefix(instr, byte) x = super(instr, byte) if instr.prefix.delete :rex # rex ignored if not last instr.prefix.delete :rex_b instr.prefix.delete :rex_x instr.prefix.delete :rex_r instr.prefix.delete :rex_w end if byte & 0xf0 == 0x40 x = instr.prefix[:rex] = byte instr.prefix[:rex_b] = 1 if byte & 1 > 0 instr.prefix[:rex_x] = 1 if byte & 2 > 0 instr.prefix[:rex_r] = 1 if byte & 4 > 0 instr.prefix[:rex_w] = 1 if byte & 8 > 0 end x end
returns all forms of the encoding of instruction i using opcode op program may be used to create a new label for relative jump/call
# File metasm/cpu/x86_64/encode.rb, line 106 def encode_instr_op(program, i, op) base = op.bin.dup oi = op.args.zip(i.args) set_field = lambda { |f, v| fld = op.fields[f] base[fld[0]] |= v << fld[1] } # # handle prefixes and bit fields # pfx = i.prefix.map { |k, v| case k when :jmp; {:jmp => 0x3e, :nojmp => 0x2e}[v] when :lock; 0xf0 when :rep; {'repnz' => 0xf2, 'repz' => 0xf3, 'rep' => 0xf2}[v] when :jmphint; {'hintjmp' => 0x3e, 'hintnojmp' => 0x2e}[v] when :seg; [0x26, 0x2E, 0x36, 0x3E, 0x64, 0x65][v.val] end }.compact.pack 'C*' rex_w = rex_r = rex_x = rex_b = 0 if op.name == 'movsx' or op.name == 'movzx' or op.name == 'movsxd' case i.args[0].sz when 64; rex_w = 1 when 32 when 16; pfx << 0x66 end elsif op.name == 'crc32' case i.args[1].sz when 64; rex_w = 1 when 32; when 16; pfx << 0x66 end else opsz = op.props[:argsz] || i.prefix[:sz] oi.each { |oa, ia| case oa when :reg, :reg_eax, :modrm, :mrm_imm raise EncodeError, "Incompatible arg size in #{i}" if ia.sz and opsz and opsz != ia.sz opsz = ia.sz end } opsz ||= 64 if op.props[:auto64] opsz = op.props[:opsz] if op.props[:opsz] # XXX ? case opsz when 64; rex_w = 1 if not op.props[:auto64] and (not op.props[:argsz] or op.props[:opsz] == 64) when 32; raise EncodeError, "Incompatible arg size in #{i}" if op.props[:auto64] when 16; pfx << 0x66 end end opsz ||= @size # addrsize override / segment override / rex_bx if mrm = i.args.grep(ModRM).first mrm.encode(0, @endianness) if mrm.b or mrm.i # may reorder b/i, which must be correct for rex rex_b = 1 if mrm.b and mrm.b.val_rex.to_i > 0 rex_x = 1 if mrm.i and mrm.i.val_rex.to_i > 0 pfx << 0x67 if (mrm.b and mrm.b.sz == 32) or (mrm.i and mrm.i.sz == 32) or op.props[:adsz] == 32 pfx << [0x26, 0x2E, 0x36, 0x3E, 0x64, 0x65][mrm.seg.val] if mrm.seg elsif op.props[:adsz] == 32 pfx << 0x67 end # # encode embedded arguments # postponed = [] oi.each { |oa, ia| case oa when :reg set_field[oa, ia.val_enc] if op.fields[:reg][1] == 3 rex_r = ia.val_rex || 0 else rex_b = ia.val_rex || 0 end when :seg3, :seg3A, :seg2, :seg2A, :eeec, :eeed, :eeet, :regfp, :regmmx, :regxmm, :regymm set_field[oa, ia.val & 7] rex_r = 1 if ia.val > 7 pfx << 0x66 if oa == :regmmx and op.props[:xmmx] and ia.sz == 128 when :vexvreg, :vexvxmm, :vexvymm set_field[:vex_vvvv, ia.val ^ 0xf] when :imm_val1, :imm_val3, :reg_cl, :reg_eax, :reg_dx, :regfp0 # implicit when :modrm, :modrmmmx, :modrmxmm, :modrmymm # postpone, but we must set rex now case ia when ModRM ia.encode(0, @endianness) # could swap b/i rex_x = ia.i.val_rex || 0 if ia.i rex_b = ia.b.val_rex || 0 if ia.b when Reg rex_b = ia.val_rex || 0 else rex_b = ia.val >> 3 end postponed << [oa, ia] else postponed << [oa, ia] end } if !(op.args & [:modrm, :modrmmmx, :modrmxmm, :modrmymm]).empty? # reg field of modrm regval = (base[-1] >> 3) & 7 base.pop end # convert label name for jmp/call/loop to relative offset if op.props[:setip] and op.name[0, 3] != 'ret' and i.args.first.kind_of? Expression postlabel = program.new_label('post'+op.name) target = postponed.first[1] target = target.rexpr if target.kind_of? Expression and target.op == :+ and not target.lexpr postponed.first[1] = Expression[target, :-, postlabel] end pfx << op.props[:needpfx] if op.props[:needpfx] if op.fields[:vex_r] set_field[:vex_r, rex_r ^ 1] set_field[:vex_x, rex_x ^ 1] if op.fields[:vex_x] set_field[:vex_b, rex_b ^ 1] if op.fields[:vex_b] set_field[:vex_w, rex_w] if op.fields[:vex_w] elsif rex_r + rex_x + rex_b + rex_w >= 1 or i.args.grep(Reg).find { |r| r.sz == 8 and r.val >= 4 and r.val < 8 } rex = 0x40 rex |= 1 if rex_b == 1 rex |= 2 if rex_x == 1 rex |= 4 if rex_r == 1 rex |= 8 if rex_w == 1 pfx << rex end ret = EncodedData.new(pfx + base.pack('C*')) postponed.each { |oa, ia| case oa when :modrm, :modrmmmx, :modrmxmm, :modrmymm if ia.kind_of? ModRM ed = ia.encode(regval, @endianness) if ed.kind_of?(::Array) if ed.length > 1 # we know that no opcode can have more than 1 modrm ary = [] ed.each { |m| ary << (ret.dup << m) } ret = ary next else ed = ed.first end end else ed = ModRM.encode_reg(ia, regval) end when :mrm_imm; ed = ia.imm.encode("a#{op.props[:adsz] || 64}".to_sym, @endianness) when :i8, :u8, :i16, :u16, :i32, :u32, :i64, :u64; ed = ia.encode(oa, @endianness) when :i type = if opsz == 64 if op.props[:imm64] :a64 else if _ia = ia.reduce and _ia.kind_of?(Integer) and _ia > 0 and (_ia >> 63) == 1 # handle 0xffffffff_ffffffff -> -1, which should fit in i32 ia = Expression[_ia - (1 << 64)] end :i32 end else "a#{opsz}".to_sym end ed = ia.encode(type, @endianness) when :i4xmm, :i4ymm ed = ia.val << 4 # u8 else raise SyntaxError, "Internal error: want to encode field #{oa.inspect} as arg in #{i}" end if ret.kind_of?(::Array) ret.each { |e| e << ed } else ret << ed end } # we know that no opcode with setip accept both modrm and immediate arg, so ret is not an ::Array ret.add_export(postlabel, ret.virtsize) if postlabel ret end
# File metasm/cpu/x86_64/render.rb, line 12 def gui_hilight_word_regexp_init ret = {} %w[a b c d].each { |r| ret["#{r}l"] = "[re]?#{r}x|#{r}l" ret["#{r}h"] = "[re]?#{r}x|#{r}h" ret["#{r}x"] = ret["e#{r}x"] = ret["r#{r}x"] = "[re]?#{r}x|#{r}[hl]" } %w[sp bp si di].each { |r| ret["#{r}l"] = ret[r] = ret["e#{r}"] = ret["r#{r}"] = "[re]?#{r}|#{r}l" } (8..15).each { |i| r = "r#{i}" ret[r+'b'] = ret[r+'w'] = ret[r+'d'] = ret[r] = "#{r}[bwd]?" } ret['eip'] = ret['rip'] = '[re]ip' ret end
Metasm::Ia32#init_386_common_only
# File metasm/cpu/x86_64/opcodes.rb, line 17 def init_386_common_only super() # :imm64 => accept a real int64 as :i argument # :auto64 => ignore rex_w, always 64-bit op # :op32no64 => if write to a 32-bit reg, dont zero the top 32-bits of dest [:imm64, :auto64, :op32no64].each { |a| @valid_props[a] = true } @opcode_list.delete_if { |o| o.bin[0].to_i & 0xf0 == 0x40 } # now REX prefix @opcode_list.each { |o| o.props[:imm64] = true if o.bin == [0xB8] # mov reg, <true imm64> o.props[:auto64] = true if o.name =~ /^(j.*|loop.*|call|enter|leave|push|pop|ret)$/ } addop 'movsxd', [0x63], :mrm addop('cdqe', [0x98]) { |o| o.props[:opsz] = 64 } addop('cqo', [0x99]) { |o| o.props[:opsz] = 64 } end
Metasm::Ia32#init_avx_only
# File metasm/cpu/x86_64/opcodes.rb, line 81 def init_avx_only super() addop('rdfsbase', [0x0F, 0xAE], 0, :modrmR) { |o| o.props[:needpfx] = 0xF3 } addop('rdgsbase', [0x0F, 0xAE], 1, :modrmR) { |o| o.props[:needpfx] = 0xF3 } addop('wrfsbase', [0x0F, 0xAE], 2, :modrmR) { |o| o.props[:needpfx] = 0xF3 } addop('wrgsbase', [0x0F, 0xAE], 3, :modrmR) { |o| o.props[:needpfx] = 0xF3 } end
Metasm::Ia32#init_cpu_constants
# File metasm/cpu/x86_64/opcodes.rb, line 12 def init_cpu_constants super() [:i32, :u32, :i64, :u64].each { |a| @valid_args[a] = true } end
# File metasm/cpu/x86_64/opcodes.rb, line 70 def init_sse3 init_x8664_only init_sse3_only end
Metasm::Ia32#init_sse41_only
# File metasm/cpu/x86_64/opcodes.rb, line 75 def init_sse41_only super() addop('pextrq', [0x0F, 0x3A, 0x16], :mrmxmm, :u8) { |o| o.props[:needpfx] = 0x66; o.args[o.args.index(:modrmxmm)] = :modrm; o.props[:opsz] = o.props[:argsz] = 64 } addop('pinsrq', [0x0F, 0x3A, 0x22], :mrmxmm, :u8) { |o| o.props[:needpfx] = 0x66; o.args[o.args.index(:modrmxmm)] = :modrm; o.props[:opsz] = o.props[:argsz] = 64 } end
all x86_64 cpu understand <= sse2 instrs
# File metasm/cpu/x86_64/opcodes.rb, line 34 def init_x8664_only init_386_common_only init_386_only init_387_only init_486_only init_pentium_only init_p6_only init_sse_only init_sse2_only @opcode_list.delete_if { |o| o.args.include?(:seg2) or o.args.include?(:seg2A) or o.args.include?(:farptr) or %w[aaa aad aam aas bound daa das into jcxz jecxz lds les loadall arpl pusha pushad popa popad pushfd popfd ].include?(o.name.split('.')[0]) # split needed for lds.a32 } @opcode_list.each { |o| o.props[:auto64] = true if o.name =~ /^(enter|leave|[sl]gdt|[sl]idt|[sl]ldt|[sl]tr|push|pop|syscall)$/ } addop('cmpxchg16b', [0x0F, 0xC7], 1) { |o| o.props[:opsz] = 64 ; o.props[:argsz] = 128 } addop('iretq', [0xCF], nil, :stopexec, :setip) { |o| o.props[:opsz] = 64 } ; opcode_list.unshift opcode_list.pop addop('pushfq', [0x9C]) { |o| o.props[:auto64] = true } addop('popfq', [0x9D]) { |o| o.props[:auto64] = true } addop 'swapgs', [0x0F, 0x01, 0xF8] addop('movq', [0x0F, 0x6E], :mrmmmx, {:d => [1, 4]}) { |o| o.args = [:regmmx, :modrm] ; o.props[:opsz] = o.props[:argsz] = 64 } addop('movq', [0x0F, 0x6E], :mrmxmm, {:d => [1, 4]}) { |o| o.args = [:regxmm, :modrm] ; o.props[:opsz] = o.props[:argsz] = 64 ; o.props[:needpfx] = 0x66 } addop('jecxz', [0xE3], nil, :setip, :i8) { |o| o.props[:adsz] = 32 } addop('jrcxz', [0xE3], nil, :setip, :i8) { |o| o.props[:adsz] = 64 } end
# File metasm/cpu/x86_64/compile_c.rb, line 1031 def new_ccompiler(parser, exe=ExeFormat.new) exe.cpu = self if not exe.instance_variable_get('@cpu') CCompiler.new(parser, exe) end
# File metasm/cpu/x86_64/decode.rb, line 234 def opsz(di, op=nil) if di and di.instruction.prefix and di.instruction.prefix[:rex_w]; 64 elsif di and di.instruction.prefix and di.instruction.prefix[:opsz] and (op || di.opcode).props[:needpfx] != 0x66; 16 elsif di and (op || di.opcode).props[:auto64]; 64 else 32 end end
check if the argument matches the opcode's argument spec
Metasm::Ia32#parse_arg_valid?
# File metasm/cpu/x86_64/parse.rb, line 51 def parse_arg_valid?(o, spec, arg) return if arg.kind_of? ModRM and ((arg.b and arg.b.val == 16 and arg.i) or (arg.i and arg.i.val == 16 and (arg.b or arg.s != 1))) return if arg.kind_of? Reg and arg.sz >= 32 and arg.val == 16 # eip/rip only in modrm return if o.props[:auto64] and arg.respond_to? :sz and arg.sz == 32 # vex c4/c5 return if o.fields[:vex_r] and not o.fields[:vex_b] and (spec == :modrm or spec == :modrmxmm or spec == :modrmymm) and (((arg.kind_of?(SimdReg) or arg.kind_of?(Reg)) and arg.val >= 8) or (arg.kind_of?(ModRM) and ((arg.b and arg.b.val >= 8) or (arg.i and arg.i.val >= 8)))) if o.name == 'movsxd' return if not arg.kind_of? Reg and not arg.kind_of? ModRM arg.sz ||= 32 if spec == :reg return if not arg.kind_of? Reg return arg.sz >= 32 else return arg.sz == 32 end end return if o.name == 'xchg' and spec == :reg and o.args.include?(:reg_eax) and arg.kind_of?(Reg) and arg.sz == 32 and arg.val == 0 super(o, spec, arg) end
needed due to how ruby inheritance works wrt constants
# File metasm/cpu/x86_64/parse.rb, line 31 def parse_argregclasslist [Reg, SimdReg, SegReg, DbgReg, TstReg, CtrlReg, FpReg] end
Metasm::Ia32#parse_instruction_checkproto
# File metasm/cpu/x86_64/parse.rb, line 39 def parse_instruction_checkproto(i) # check ah vs rex prefix return if i.args.find { |a| a.kind_of? Reg and a.sz == 8 and a.val >= 16 and op = opcode_list.find { |op_| op_.name == i.opname } and ((not op.props[:auto64] and i.args.find { |aa| aa.respond_to? :sz and aa.sz == 64 }) or i.args.find { |aa| aa.kind_of? Reg and aa.val >= 8 and aa.val < 16 } or # XXX mov ah, cr12... i.args.grep(ModRM).find { |aa| (aa.b and aa.b.val >= 8 and aa.b.val < 16) or (aa.i and aa.i.val >= 8 and aa.i.val < 16) }) } super(i) end
same inheritance sh*t
# File metasm/cpu/x86_64/parse.rb, line 35 def parse_modrm(lex, tok, cpu) ModRM.parse(lex, tok, cpu) end
Metasm::Ia32#parse_parser_instruction
# File metasm/cpu/x86_64/parse.rb, line 13 def parse_parser_instruction(lexer, instr) case instr.raw.downcase when '.mode', '.bits' if tok = lexer.readtok and tok.type == :string and tok.raw == '64' lexer.skip_space raise instr, 'syntax error' if ntok = lexer.nexttok and ntok.type != :eol else raise instr, 'invalid cpu mode, 64bit only' end else super(lexer, instr) end end
Metasm::Ia32#parse_prefix
# File metasm/cpu/x86_64/parse.rb, line 26 def parse_prefix(i, pfx) super(i, pfx) or (i.prefix[:sz] = 64 if pfx == 'code64') end
# File metasm/cpu/x86_64/decode.rb, line 248 def register_symbols [:rax, :rcx, :rdx, :rbx, :rsp, :rbp, :rsi, :rdi, :r8, :r9, :r10, :r11, :r12, :r13, :r14, :r15] end
# File metasm/cpu/x86_64/main.rb, line 139 def shortname "x64#{'_be' if @endianness == :big}" end
# File metasm/cpu/x86_64/main.rb, line 134 def str_to_reg(str) # X86_64::Reg != Ia32::Reg Reg.s_to_i.has_key?(str) ? Reg.from_str(str) : SimdReg.s_to_i.has_key?(str) ? SimdReg.from_str(str) : nil end
defines some preprocessor macros to say who we are: TODO
Metasm::Ia32#tune_prepro
# File metasm/cpu/x86_64/main.rb, line 126 def tune_prepro(pp) super(pp, :itsmeX64) # ask Ia32's to just call super() pp.define_weak('_M_AMD64') pp.define_weak('_M_X64') pp.define_weak('__amd64__') pp.define_weak('__x86_64__') end