class Metasm::AMD64

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

new(*a) click to toggle source

Create a new instance of an X86 cpu arguments (any order)

  • instruction set (386, 486, sse2…) [latest]

  • endianness [:little]

Calls superclass method 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

addop_macroret(name, bin, *args) click to toggle source
Calls superclass method 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
addop_macrostr(name, bin, type) click to toggle source
Calls superclass method 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
addop_post(op) click to toggle source
Calls superclass method 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
adsz(di, op=nil) click to toggle source
# 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
backtrace_update_function_binding_check(dasm, faddr, f, b) click to toggle source
# 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
check_reserved_name(name) click to toggle source
# File metasm/cpu/x86_64/parse.rb, line 72
def check_reserved_name(name)
        Reg.s_to_i[name]
end
dbg_func_arg(dbg, argnr) click to toggle source
# 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
dbg_func_arg_set(dbg, argnr, arg) click to toggle source
# 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
dbg_register_flags() click to toggle source
# File metasm/cpu/x86_64/debug.rb, line 14
def dbg_register_flags
        @dbg_register_flags ||= :rflags
end
dbg_register_list() click to toggle source
# 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
dbg_register_pc() click to toggle source
# File metasm/cpu/x86_64/debug.rb, line 11
def dbg_register_pc
        @dbg_register_pc ||= :rip
end
dbg_register_size() click to toggle source
# 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
decode_c_function_prototype(cp, sym, orig=nil) click to toggle source

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
decode_instr_interpret(di, addr) click to toggle source
Calls superclass method 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
decode_instr_op(edata, di) click to toggle source
# 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
decode_prefix(instr, byte) click to toggle source
Calls superclass method 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
encode_instr_op(program, i, op) click to toggle source

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
gui_hilight_word_regexp_init() click to toggle source
# 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
init_386_common_only() click to toggle source
Calls superclass method 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
init_avx_only() click to toggle source
Calls superclass method 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
init_cpu_constants() click to toggle source
Calls superclass method 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
init_sse3() click to toggle source
# File metasm/cpu/x86_64/opcodes.rb, line 70
def init_sse3
        init_x8664_only
        init_sse3_only
end
init_sse41_only() click to toggle source
Calls superclass method 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
init_x8664_only() click to toggle source

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
new_ccompiler(parser, exe=ExeFormat.new) click to toggle source
# 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
opsz(di, op=nil) click to toggle source
# 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
parse_arg_valid?(o, spec, arg) click to toggle source

check if the argument matches the opcode's argument spec

Calls superclass method 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
parse_argregclasslist() click to toggle source

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
parse_instruction_checkproto(i) click to toggle source
# 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
parse_modrm(lex, tok, cpu) click to toggle source

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
parse_parser_instruction(lexer, instr) click to toggle source
Calls superclass method 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
parse_prefix(i, pfx) click to toggle source
Calls superclass method 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
register_symbols() click to toggle source
# 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
shortname() click to toggle source
# File metasm/cpu/x86_64/main.rb, line 139
def shortname
        "x64#{'_be' if @endianness == :big}"
end
str_to_reg(str) click to toggle source
# 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
tune_prepro(pp) click to toggle source

defines some preprocessor macros to say who we are: TODO

Calls superclass method 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