class Metasm::ARM

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

Public Class Methods

new(endianness = :little) click to toggle source
Calls superclass method Metasm::CPU::new
# File metasm/cpu/arm/main.rb, line 60
def initialize(endianness = :little)
        super()
        @endianness = endianness
        @size = 32
end

Public Instance Methods

backtrace_binding() click to toggle source
# File metasm/cpu/arm/decode.rb, line 128
def backtrace_binding
        @backtrace_binding ||= init_backtrace_binding
end
build_bin_lookaside() click to toggle source

create the lookaside hash from the first byte of the opcode

# File metasm/cpu/arm/decode.rb, line 22
def build_bin_lookaside
        lookaside = Array.new(256) { [] }

        opcode_list.each { |op|
                build_opcode_bin_mask op

                b   = (op.bin >> 20) & 0xff
                msk = (op.bin_mask >> 20) & 0xff
                b &= msk

                for i in b..(b | (255^msk))
                        lookaside[i] << op if i & msk == b
                end
        }

        lookaside
end
build_opcode_bin_mask(op) click to toggle source

create the bin_mask for a given opcode

# File metasm/cpu/arm/decode.rb, line 12
def build_opcode_bin_mask(op)
        # bit = 0 if can be mutated by an field value, 1 if fixed by opcode
        op.bin_mask = 0
        op.fields.each { |k, (m, s)|
                op.bin_mask |= m << s
        }
        op.bin_mask = 0xffffffff ^ op.bin_mask
end
dbg_end_stepout(dbg, addr, di) click to toggle source
# File metasm/cpu/arm/debug.rb, line 34
def dbg_end_stepout(dbg, addr, di)
        di and di.opcode.name == 'foobar'     # TODO
end
dbg_flag_list() click to toggle source
# File metasm/cpu/arm/debug.rb, line 22
def dbg_flag_list
        @dbg_flag_list ||= []
end
dbg_need_stepover(dbg, addr, di) click to toggle source
# File metasm/cpu/arm/debug.rb, line 30
def dbg_need_stepover(dbg, addr, di)
        di and di.opcode.props[:saveip]
end
dbg_register_flags() click to toggle source
# File metasm/cpu/arm/debug.rb, line 14
def dbg_register_flags
        @dbg_register_flags ||= :flags
end
dbg_register_list() click to toggle source
# File metasm/cpu/arm/debug.rb, line 18
def dbg_register_list
        @dbg_register_list ||= [:r0, :r1, :r2, :r3, :r4, :r5, :r6, :r7, :r8, :r9, :r10, :r11, :r12, :sp, :lr, :pc]
end
dbg_register_pc() click to toggle source
# File metasm/cpu/arm/debug.rb, line 11
def dbg_register_pc
        @dbg_register_pc ||= :pc
end
dbg_register_size() click to toggle source
# File metasm/cpu/arm/debug.rb, line 26
def dbg_register_size
        @dbg_register_size ||= Hash.new(32)
end
decode_findopcode(edata) click to toggle source
# File metasm/cpu/arm/decode.rb, line 40
def decode_findopcode(edata)
        return if edata.ptr+4 > edata.length
        di = DecodedInstruction.new(self)
        val = edata.decode_imm(:u32, @endianness)
        di.misc = val
        di if di.opcode = @bin_lookaside[(val >> 20) & 0xff].find { |op|
                (not op.props[:cond] or
                 ((val >> @fields_shift[:cond]) & @fields_mask[:cond]) != 0xf) and
                (op.bin & op.bin_mask) == (val & op.bin_mask)
        }
end
decode_instr_interpret(di, addr) click to toggle source
# File metasm/cpu/arm/decode.rb, line 121
def decode_instr_interpret(di, addr)
        if di.opcode.args[-1] == :i24
                di.instruction.args[-1] = Expression[di.instruction.args[-1] + addr + 8]
        end
        di
end
decode_instr_op(edata, di) click to toggle source
# File metasm/cpu/arm/decode.rb, line 57
def decode_instr_op(edata, di)
        op = di.opcode
        di.instruction.opname = op.name
        val = di.misc # saved decoded u32

        field_val = lambda { |f|
                r = (val >> @fields_shift[f]) & @fields_mask[f]
                case f
                when :i12; Expression.make_signed(r, 12)
                when :i24; Expression.make_signed(r, 24)
                when :i8_12; ((r >> 4) & 0xf0) | (r & 0xf)
                when :stype; [:lsl, :lsr, :asr, :ror][r]
                when :u; [:-, :+][r]
                else r
                end
        }

        if op.props[:cond]
                cd = %w[eq ne cs cc mi pl vs vc hi ls ge lt gt le al][field_val[:cond]]
                if cd != 'al'
                        di.opcode = di.opcode.dup
                        di.instruction.opname = di.opcode.name.dup
                        di.instruction.opname[(op.props[:cond_name_off] || di.opcode.name.length), 0] = cd
                        if di.opcode.props[:stopexec]
                                di.opcode.props = di.opcode.props.dup
                                di.opcode.props.delete :stopexec
                        end
                end
        end

        op.args.each { |a|
                di.instruction.args << case a
                when :rd, :rn, :rm; Reg.new field_val[a]
                when :rm_rs; Reg.new field_val[:rm], field_val[:stype], Reg.new(field_val[:rs])
                when :rm_is; Reg.new field_val[:rm], field_val[:stype], field_val[:shifti]
                when :i12; Expression[field_val[a]]
                when :i24; Expression[field_val[a] << 2]
                when :i8_r
                        i = field_val[:i8]
                        r = field_val[:rotate]*2
                        Expression[((i >> r) | (i << (32-r))) & 0xffff_ffff]
                when :mem_rn_rm, :mem_rn_i8_12, :mem_rn_rms, :mem_rn_i12
                        b = Reg.new(field_val[:rn])
                        o = case a
                        when :mem_rn_rm; Reg.new(field_val[:rm])
                        when :mem_rn_i8_12; field_val[:i8_12]
                        when :mem_rn_rms; Reg.new(field_val[:rm], field_val[:stype], field_val[:shifti])
                        when :mem_rn_i12; field_val[:i12]
                        end
                        Memref.new(b, o, field_val[:u], op.props[:baseincr])
                when :reglist
                        di.instruction.args.last.updated = true if op.props[:baseincr]
                        msk = field_val[a]
                        l = RegList.new((0..15).map { |n| Reg.new(n) if (msk & (1 << n)) > 0 }.compact)
                        l.usermoderegs = true if op.props[:usermoderegs]
                        l
                else raise SyntaxError, "Internal error: invalid argument #{a} in #{op.name}"
                end
        }

        di.bin_length = 4
        di
end
disassembler_default_func() click to toggle source
# File metasm/cpu/arm/decode.rb, line 52
def disassembler_default_func
        df = DecodedFunction.new
        df
end
encode_instr_op(program, instr, op) click to toggle source
# File metasm/cpu/arm/encode.rb, line 12
def encode_instr_op(program, instr, op)
        base = op.bin
        set_field = lambda { |f, v|
                v = v.reduce if v.kind_of?(Expression)
                case f
                when :i8_12
                        base = Expression[base, :|, [[v, :&, 0xf], :|, [[v, :<<, 4], :&, 0xf00]]]
                        next
                when :stype; v = [:lsl, :lsr, :asr, :ror].index(v)
                when :u; v = [:-, :+].index(v)
                end
                base = Expression[base, :|, [[v, :&, @fields_mask[f]], :<<, @fields_shift[f]]]
        }

        val, mask, shift = 0, 0, 0

        if op.props[:cond]
                coff = op.props[:cond_name_off] || op.name.length
                cd = instr.opname[coff, 2]
                cdi = %w[eq ne cs cc mi pl vs vc hi ls ge lt gt le al].index(cd) || 14       # default = al
                set_field[:cond, cdi]
        end

        op.args.zip(instr.args).each { |sym, arg|
                case sym
                when :rd, :rs, :rn, :rm; set_field[sym, arg.i]
                when :rm_rs
                        set_field[:rm, arg.i]
                        set_field[:stype, arg.stype]
                        set_field[:rs, arg.shift.i]
                when :rm_is
                        set_field[:rm, arg.i]
                        set_field[:stype, arg.stype]
                        set_field[:shifti, arg.shift]
                when :mem_rn_rm, :mem_rn_rms, :mem_rn_i8_12, :mem_rn_i12
                        set_field[:rn, arg.base.i]
                        case sym
                        when :mem_rn_rm
                                set_field[:rm, arg.offset.i]
                        when :mem_rn_rms
                                set_field[:rm, arg.offset.i]
                                set_field[:stype, arg.offset.stype]
                                set_field[:rs, arg.offset.shift.i]
                        when :mem_rn_i8_12
                                set_field[:i8_12, arg.offset]
                        when :mem_rn_i12
                                set_field[:i12, arg.offset]
                        end
                        # TODO set_field[:u] etc
                when :reglist
                        set_field[sym, arg.list.inject(0) { |rl, r| rl | (1 << r.i) }]
                when :i8_r
                        b = arg.reduce & 0xffffffff
                        r = (0..15).find {
                                next true if b < 0x100
                                b = ((b << 2) & 0xffff_ffff) | ((b >> 30) & 3)
                                false
                        }
                        raise EncodeError, "Invalid constant" if not r
                        set_field[:i8, b]
                        set_field[:rotate, r]
                when :i12, :i24
                        val, mask, shift = arg, @fields_mask[sym], @fields_shift[sym]
                end
        }

        if op.args[-1] == :i24
                # convert label name for branch to relative offset
                label = program.new_label('l_'+op.name)
                target = val
                target = target.rexpr if target.kind_of?(Expression) and target.op == :+ and not target.lexpr
                val = Expression[[target, :-, [label, :+, 8]], :>>, 2]

                EncodedData.new('', :export => { label => 0 }) <<
                Expression[base, :|, [[val, :<<, shift], :&, mask]].encode(:u32, @endianness)
        else
                Expression[base, :|, [[val, :<<, shift], :&, mask]].encode(:u32, @endianness)
        end
end
get_backtrace_binding(di) click to toggle source
# File metasm/cpu/arm/decode.rb, line 136
def get_backtrace_binding(di)
        a = di.instruction.args.map { |arg|
                case arg
                when Reg; arg.symbolic
                when Memref; arg.symbolic(di.address)
                else arg
                end
        }

        if binding = backtrace_binding[di.opcode.name]
                binding[di, *a]
        else
                puts "unhandled instruction to backtrace: #{di}" if $VERBOSE
                # assume nothing except the 1st arg is modified
                case a[0]
                when Indirection, Symbol; { a[0] => Expression::Unknown }
                when Expression; (x = a[0].externals.first) ? { x => Expression::Unknown } : {}
                else {}
                end.update(:incomplete_binding => Expression[1])
        end

end
get_xrefs_x(dasm, di) click to toggle source
# File metasm/cpu/arm/decode.rb, line 159
def get_xrefs_x(dasm, di)
        if di.opcode.props[:setip]
                [di.instruction.args.last]
        else
                # TODO ldr pc, ..
                []
        end
end
init_backtrace_binding() click to toggle source
# File metasm/cpu/arm/decode.rb, line 132
def init_backtrace_binding
        @backtrace_binding ||= {}
end
init_opcode_list() click to toggle source
# File metasm/cpu/arm/main.rb, line 66
def init_opcode_list
        init_latest
        @opcode_list
end
opcode_list_byname() click to toggle source
# File metasm/cpu/arm/parse.rb, line 12
def opcode_list_byname
        @opcode_list_byname ||= opcode_list.inject({}) { |h, o|
                (h[o.name] ||= []) << o
                if o.props[:cond]
                        coff = o.props[:cond_name_off] || o.name.length
                        %w[eq ne cs cc mi pl vs vc hi ls ge lt gt le al].each { |cd|
                                n = o.name.dup
                                n[coff, 0] = cd
                                (h[n] ||= []) << o
                        }
                end
                h
        }
end
parse_arg_valid?(op, sym, arg) click to toggle source
# File metasm/cpu/arm/parse.rb, line 27
def parse_arg_valid?(op, sym, arg)
        case sym
        when :rd, :rs, :rn, :rm; arg.kind_of?(Reg) and arg.shift == 0 and (arg.updated ? op.props[:baseincr] : !op.props[:baseincr])
        when :rm_rs; arg.kind_of?(Reg) and arg.shift.kind_of?(Reg)
        when :rm_is; arg.kind_of?(Reg) and arg.shift.kind_of?(Integer)
        when :i12, :i24, :i8_12; arg.kind_of?(Expression)
        when :i8_r
                if arg.kind_of?(Expression)
                        b = arg.reduce
                        !b.kind_of?(Integer) or (0..15).find {
                                        b = ((b << 2) & 0xffff_ffff) | ((b >> 30) & 3)
                                        b < 0x100 }
                end
        when :mem_rn_rm, :mem_rn_i8_12, :mem_rn_rms, :mem_rn_i12
                os = case sym
                     when :mem_rn_rm; :rm
                     when :mem_rn_i8_12; :i8_12
                     when :mem_rn_rms; :rm_rs
                     when :mem_rn_i12; :i12
                     end
                arg.kind_of?(Memref) and parse_arg_valid?(op, os, arg.offset)
        when :reglist; arg.kind_of?(RegList)
        end
        # TODO check flags on reglist, check int values
end
parse_argument(lexer) click to toggle source
# File metasm/cpu/arm/parse.rb, line 53
def parse_argument(lexer)
        raise lexer, "unexpected EOS" if not lexer.nexttok
        if Reg.s_to_i[lexer.nexttok.raw]
                arg = Reg.new Reg.s_to_i[lexer.readtok.raw]
                lexer.skip_space
                case lexer.nexttok.raw.downcase
                when 'lsl', 'lsr', 'asr', 'ror'
                        arg.stype = lexer.readtok.raw.downcase.to_sym
                        lexer.skip_space
                        if Reg.s_to_i[lexer.nexttok.raw]
                                arg.shift = Reg.new Reg.s_to_i[lexer.readtok.raw]
                        else
                                arg.shift = Expression.parse(lexer).reduce
                        end
                when 'rrx'
                        lexer.readtok
                        arg.stype = :ror
                when '!'
                        lexer.readtok
                        arg.updated = true
                end if lexer.nexttok
        elsif lexer.nexttok.raw == '{'
                lexer.readtok
                arg = RegList.new
                loop do
                        lexer.skip_space
                        raise "unterminated reglist" if lexer.eos?
                        if Reg.s_to_i[lexer.nexttok.raw]
                                arg.list << Reg.new(Reg.s_to_i[lexer.readtok.raw])
                                lexer.skip_space
                                raise "unterminated reglist" if lexer.eos?
                        end
                        case lexer.nexttok.raw
                        when ','; lexer.readtok
                        when '-'
                                lexer.readtok
                                lexer.skip_space
                                raise "unterminated reglist" if lexer.eos?
                                if not r = Reg.s_to_i[lexer.nexttok.raw]
                                        raise lexer, "reglist parse error: invalid range"
                                end
                                lexer.readtok
                                (arg.list.last.i+1..r).each { |v|
                                        arg.list << Reg.new(v)
                                }
                        when '}'; lexer.readtok ; break
                        else raise lexer, "reglist parse error: ',' or '}' expected, got #{lexer.nexttok.raw.inspect}"
                        end
                end
                if lexer.nexttok and lexer.nexttok.raw == '^'
                        lexer.readtok
                        arg.usermoderegs = true
                end
        elsif lexer.nexttok.raw == '['
                lexer.readtok
                raise "unexpected EOS" if lexer.eos?
                if not base = Reg.s_to_i[lexer.nexttok.raw]
                        raise lexer, 'invalid mem base (reg expected)'
                end
                base = Reg.new Reg.s_to_i[lexer.readtok.raw]
                raise "unexpected EOS" if lexer.eos?
                if lexer.nexttok.raw == ']'
                        lexer.readtok
                        #closed = true
                end
                if !lexer.nexttok or lexer.nexttok.raw != ','
                        raise lexer, 'mem off expected'
                end
                lexer.readtok
                off = parse_argument(lexer)
                if not off.kind_of?(Expression) and not off.kind_of?(Reg)
                        raise lexer, 'invalid mem off (reg/imm expected)'
                end
                case lexer.nexttok and lexer.nexttok.raw
                when ']'
                when ','
                end
                lexer.readtok
                arg = Memref.new(base, off)
                if lexer.nexttok and lexer.nexttok.raw == '!'
                        lexer.readtok
                        arg.incr = :pre     # TODO :post
                end
        else
                arg = Expression.parse lexer
        end
        arg
end

Private Instance Methods

addop(name, bin, *args) click to toggle source

ARM MODE

# File metasm/cpu/arm/opcodes.rb, line 15
def addop(name, bin, *args)
        args << :cond if not args.delete :uncond

        suppl = nil
        o = Opcode.new name, bin
        args.each { |a|
                # Should Be One fields
                if a == :sbo16 ; o.bin |= 0b1111 << 16 ; next ; end
                if a == :sbo12 ; o.bin |= 0b1111 << 12 ; next ; end
                if a == :sbo8  ; o.bin |= 0b1111 <<  8 ; next ; end
                if a == :sbo0  ; o.bin |= 0b1111 <<  0 ; next ; end

                o.args << a if @valid_args[a]
                o.props[a] = true if @valid_props[a]
                o.props.update a if a.kind_of?(Hash)
                # special args -> multiple fields
                suppl ||= { :i8_r => [:i8, :rotate], :rm_is => [:rm, :stype, :shifti],
                        :rm_rs => [:rm, :stype, :rs], :mem_rn_rm => [:rn, :rm, :rsx, :u],
                        :mem_rn_i8_12 => [:rn, :i8_12, :u],
                        :mem_rn_rms => [:rn, :rm, :stype, :shifti, :i],
                        :mem_rn_i12 => [:rn, :i12, :u]
                }[a]
        }

        args.concat suppl if suppl

        args.each { |a| o.fields[a] = [@fields_mask[a], @fields_shift[a]] if @fields_mask[a] }

        @opcode_list << o
end
addop_data(name, op, a1, a2) click to toggle source
# File metasm/cpu/arm/opcodes.rb, line 51
def addop_data(name, op, a1, a2)
        addop_data_s name, op << 21, a1, a2
        addop_data_s name+'s', (op << 21) | (1 << 20), a1, a2, :cond_name_off => name.length
end
addop_data_s(name, op, a1, a2, *h) click to toggle source
# File metasm/cpu/arm/opcodes.rb, line 46
def addop_data_s(name, op, a1, a2, *h)
        addop name, op | (1 << 25), a1, a2, :i8_r, :rotate, *h
        addop name, op, a1, a2, :rm_is, *h
        addop name, op | (1 << 4), a1, a2, :rm_rs, *h
end
addop_ldm(name, op) click to toggle source
# File metasm/cpu/arm/opcodes.rb, line 108
def addop_ldm(name, op)
        addop_ldm_u name, op
end
addop_ldm_go(name, op, *a) click to toggle source
# File metasm/cpu/arm/opcodes.rb, line 88
def addop_ldm_go(name, op, *a)
        addop name, op, :rn, :reglist, {:cond_name_off => 3}, *a
        addop name, op, :rn, :reglist, {:cond_name_off => name.length}, *a    # post-ARMv6 the condition code is at the end of the opname
end
addop_ldm_p(name, op) click to toggle source
# File metasm/cpu/arm/opcodes.rb, line 100
def addop_ldm_p(name, op)
        addop_ldm_s name+'a', op              # target memory included
        addop_ldm_s name+'b', op | (1 << 24)  # target memory excluded, transfer starts at next addr
end
addop_ldm_s(name, op) click to toggle source
# File metasm/cpu/arm/opcodes.rb, line 96
def addop_ldm_s(name, op)
        addop_ldm_w name, op                  # transfer regs
        addop_ldm_w name, op | (1 << 22), :usermoderegs       # transfer usermode regs
end
addop_ldm_u(name, op) click to toggle source
# File metasm/cpu/arm/opcodes.rb, line 104
def addop_ldm_u(name, op)
        addop_ldm_p name+'d', op              # transfer made downward
        addop_ldm_p name+'i', op | (1 << 23)  # transfer made upward
end
addop_ldm_w(name, op, *a) click to toggle source
# File metasm/cpu/arm/opcodes.rb, line 92
def addop_ldm_w(name, op, *a)
        addop_ldm_go name, op, *a             # base reg untouched
        addop_ldm_go name, op | (1 << 21), {:baseincr => :post}, *a   # base updated
end
addop_load(name, op) click to toggle source
# File metasm/cpu/arm/opcodes.rb, line 83
def addop_load(name, op)
        addop_load_o name, op
        addop_load_o name+'b', op | (1 << 22), :cond_name_off => name.length
end
addop_load_lsh() click to toggle source
# File metasm/cpu/arm/opcodes.rb, line 65
def addop_load_lsh
        op = 9 << 4
        addop_load_lsh_o 'strh',  op | (1 << 5)
        addop_load_lsh_o 'ldrd',  op | (1 << 6)
        addop_load_lsh_o 'strd',  op | (1 << 6) | (1 << 5)
        addop_load_lsh_o 'ldrh',  op | (1 << 20) | (1 << 5)
        addop_load_lsh_o 'ldrsb', op | (1 << 20) | (1 << 6)
        addop_load_lsh_o 'ldrsh', op | (1 << 20) | (1 << 6) | (1 << 5)
end
addop_load_lsh_o(name, op) click to toggle source
# File metasm/cpu/arm/opcodes.rb, line 61
def addop_load_lsh_o(name, op)
        addop_load_puw name, op, :rsz, :mem_rn_rm, {:cond_name_off => 3}
        addop_load_puw name, op | (1 << 22), :mem_rn_i8_12, {:cond_name_off => 3}
end
addop_load_o(name, op, *a) click to toggle source
# File metasm/cpu/arm/opcodes.rb, line 79
def addop_load_o(name, op, *a)
        addop_load_puwt name, op, :mem_rn_i12, *a
        addop_load_puwt name, op | (1 << 25), :mem_rn_rms, *a
end
addop_load_puw(name, op, *a) click to toggle source
# File metasm/cpu/arm/opcodes.rb, line 56
def addop_load_puw(name, op, *a)
        addop name, op, {:baseincr => :post}, :rd, :u, *a
        addop name, op | (1 << 24), :rd, :u, *a
        addop name, op | (1 << 24) | (1 << 21), {:baseincr => :pre}, :rd, :u, *a
end
addop_load_puwt(name, op, *a) click to toggle source
# File metasm/cpu/arm/opcodes.rb, line 75
def addop_load_puwt(name, op, *a)
        addop_load_puw name, op, *a
        addop name+'t', op | (1 << 21), {:baseincr => :post, :cond_name_off => name.length}, :rd, :u, *a
end
addop_t(name, bin, *args) click to toggle source

THUMB2 MODE

# File metasm/cpu/arm/opcodes.rb, line 190
def addop_t(name, bin, *args)
        o = Opcode.new name, bin
        args.each { |a|
                o.args << a if @valid_args[a]
                o.props[a] = true if @valid_props[a]
                o.props.update a if a.kind_of?(Hash)
        }

        args.each { |a| o.fields[a] = [@fields_mask[a], @fields_shift[a]] if @fields_mask[a] }

        @opcode_list_t << o
end
init_arm_thumb2() click to toggle source
# File metasm/cpu/arm/opcodes.rb, line 203
def init_arm_thumb2
        @opcode_list_t = []
        @valid_props_t = {}
        @valid_args_t = {}
        @fields_mask_t = {}
        @fields_shift_t = {}

        [:i16, :i16_3_8, :i16_rd].each { |p| @valid_props_t[p] = true }
        [:i5, :rm, :rn, :rd].each { |p| @valid_args_t[p] = true }
        @fields_mask_t.update :i5 => 0x1f, :i3 => 7, :i51 => 0x5f,
                :rm => 7, :rn => 7, :rd => 7, :rdn => 7, :rdn8 => 7
        @fields_shift_t.update :i5 => 6, :i3 => 6, :i51 => 3,
                :rm => 6, :rn => 3, :rd => 0, :rdn => 0, :rdn8 => 8

        addop_t 'mov', 0b000_00 << 11, :rd, :rm
        addop_t 'lsl', 0b000_00 << 11, :rd, :rm, :i5
        addop_t 'lsr', 0b000_01 << 11, :rd, :rm, :i5
        addop_t 'asr', 0b000_10 << 11, :rd, :rm, :i5

        addop_t 'add', 0b000_1100 << 9, :rd, :rn, :rm
        addop_t 'add', 0b000_1110 << 9, :rd, :rn, :i3
        addop_t 'sub', 0b000_1101 << 9, :rd, :rn, :rm
        addop_t 'sub', 0b000_1111 << 9, :rd, :rn, :i3

        addop_t 'mov', 0b001_00 << 10, :rdn8, :i8
        addop_t 'cmp', 0b001_01 << 10, :rdn8, :i8
        addop_t 'add', 0b001_10 << 10, :rdn8, :i8
        addop_t 'sub', 0b001_11 << 10, :rdn8, :i8

        addop_t 'and', (0b010000 << 10) | ( 0 << 6), :rdn, :rm
        addop_t 'eor', (0b010000 << 10) | ( 1 << 6), :rdn, :rm        # xor
        addop_t 'lsl', (0b010000 << 10) | ( 2 << 6), :rdn, :rm
        addop_t 'lsr', (0b010000 << 10) | ( 3 << 6), :rdn, :rm
        addop_t 'asr', (0b010000 << 10) | ( 4 << 6), :rdn, :rm
        addop_t 'adc', (0b010000 << 10) | ( 5 << 6), :rdn, :rm
        addop_t 'sbc', (0b010000 << 10) | ( 6 << 6), :rdn, :rm
        addop_t 'ror', (0b010000 << 10) | ( 7 << 6), :rdn, :rm
        addop_t 'tst', (0b010000 << 10) | ( 8 << 6), :rdn, :rm
        addop_t 'rsb', (0b010000 << 10) | ( 9 << 6), :rdn, :rm
        addop_t 'cmp', (0b010000 << 10) | (10 << 6), :rdn, :rm
        addop_t 'cmn', (0b010000 << 10) | (11 << 6), :rdn, :rm
        addop_t 'orr', (0b010000 << 10) | (12 << 6), :rdn, :rm        # or
        addop_t 'mul', (0b010000 << 10) | (13 << 6), :rdn, :rm
        addop_t 'bic', (0b010000 << 10) | (14 << 6), :rdn, :rm
        addop_t 'mvn', (0b010000 << 10) | (15 << 6), :rdn, :rm

        addop_t 'add', 0b010001_00 << 8, :rdn, :rm, :dn
        addop_t 'cmp', 0b010001_01 << 8, :rdn, :rm, :dn
        addop_t 'mov', 0b010001_10 << 8, :rdn, :rm, :dn

        addop_t 'bx',  0b010001_110 << 7, :rm
        addop_t 'blx', 0b010001_111 << 7, :rm

        addop_t 'ldr',   0b01001 << 11, :rd, :pc_i8
        addop_t 'str',   0b0101_000 << 9, :rd, :rn, :rm
        addop_t 'strh',  0b0101_001 << 9, :rd, :rn, :rm
        addop_t 'strb',  0b0101_010 << 9, :rd, :rn, :rm
        addop_t 'ldrsb', 0b0101_011 << 9, :rd, :rn, :rm
        addop_t 'ldr',   0b0101_100 << 9, :rd, :rn, :rm
        addop_t 'ldrh',  0b0101_101 << 9, :rd, :rn, :rm
        addop_t 'ldrb',  0b0101_110 << 9, :rd, :rn, :rm
        addop_t 'ldrsh', 0b0101_111 << 9, :rd, :rn, :rm

        addop_t 'str',  0b01100 << 11, :rd, :rn, :i5
        addop_t 'ldr',  0b01101 << 11, :rd, :rn, :i5
        addop_t 'strb', 0b01110 << 11, :rd, :rn, :i5
        addop_t 'ldrb', 0b01111 << 11, :rd, :rn, :i5
        addop_t 'strh', 0b10000 << 11, :rd, :rn, :i5
        addop_t 'ldrh', 0b10001 << 11, :rd, :rn, :i5
        addop_t 'str',  0b10010 << 11, :rd, :sp_i8
        addop_t 'ldr',  0b10011 << 11, :rd, :sp_i8
        addop_t 'adr',  0b10100 << 11, :rd, :pc, :i8
        addop_t 'add',  0b10101 << 11, :rd, :sp, :i8

        # 0b1011 misc
        addop_t 'add',  0b1011_0000_0 << 7, :sp, :i7
        addop_t 'sub',  0b1011_0000_1 << 7, :sp, :i7
        addop_t 'sxth', 0b1011_0010_00 << 6, :rd, :rn
        addop_t 'sxtb', 0b1011_0010_01 << 6, :rd, :rn
        addop_t 'uxth', 0b1011_0010_10 << 6, :rd, :rn
        addop_t 'uxtb', 0b1011_0010_11 << 6, :rd, :rn
        addop_t 'cbz',  0b1011_0001 << 8, :rd, :i51
        addop_t 'cbnz', 0b1011_1001 << 8, :rd, :i51
        addop_t 'push', 0b1011_0100 << 8, :rlist
        addop_t 'push', 0b1011_0101 << 8, :rlist
        addop_t 'pop',  0b1011_1100 << 8, :rlist
        addop_t 'pop',  0b1011_1101 << 8, :rlist
        #addop_t 'unpredictable', 0b1011_0110_0100_0000, :i4
        addop_t 'setendle', 0b1011_0110_0101_0000
        addop_t 'setendbe', 0b1011_0110_0101_1000
        addop_t 'cps', 0b1011_0110_0110_0000
        #addop_t 'unpredictable', 0b1011_0110_0110_1000, :msk_0001_0111
        addop_t 'rev',   0b1011_1010_00 << 6, :rd, :rn
        addop_t 'rev16', 0b1011_1010_01 << 6, :rd, :rn
        addop_t 'revsh', 0b1011_1010_11 << 6, :rd, :rn
        addop_t 'bkpt',  0b1011_1110 << 8, :i8
        addop_t 'it',    0b1011_1111 << 8, :itcond, :itmsk
        addop_t 'nop',   0b1011_1111_0000_0000
        addop_t 'yield', 0b1011_1111_0000_0001
        addop_t 'wfe',   0b1011_1111_0000_0010
        addop_t 'wfi',   0b1011_1111_0000_0011
        addop_t 'sev',   0b1011_1111_0000_0100
        addop_t 'nop',   0b1011_1111_0000_0000, :i4


        addop_t 'stmia', 0b11000 << 11, :rn, :rlist   # stmea
        addop_t 'ldmia', 0b11001 << 11, :rn, :rlist   # ldmfd
        addop_t 'undef', 0b1101_1110 << 8, :i8
        addop_t 'svc',   0b1101_1111 << 8, :i8
        addop_t 'b',     0b1101 << 12, :cond, :i8
        addop_t 'b',     0b11100 << 11, :i11

        # thumb-32
end
init_arm_v6() click to toggle source

ARMv6 instruction set, aka arm7/arm9

# File metasm/cpu/arm/opcodes.rb, line 113
def init_arm_v6
        @opcode_list = []

        [:baseincr, :cond, :cond_name_off, :usermoderegs, :tothumb, :tojazelle
        ].each { |p| @valid_props[p] = true }

        [:rn, :rd, :rm, :crn, :crd, :crm, :cpn, :reglist, :i24, :rm_rs, :rm_is,
         :i8_r, :mem_rn_rm, :mem_rn_i8_12, :mem_rn_rms, :mem_rn_i12
        ].each { |p| @valid_args[p] = true }

        @fields_mask.update :rn => 0xf, :rd => 0xf, :rs => 0xf, :rm => 0xf,
                :crn => 0xf, :crd => 0xf, :crm => 0xf, :cpn => 0xf,
                :rnx => 0xf, :rdx => 0xf, :rsx => 0xf,
                :shifti => 0x1f, :stype => 3, :rotate => 0xf, :reglist => 0xffff,
                :i8 => 0xff, :i12 => 0xfff, :i24 => 0xff_ffff, :i8_12 => 0xf0f,
                :u => 1, :mask => 0xf, :sbo => 0xf, :cond => 0xf

        @fields_shift.update :rn => 16, :rd => 12, :rs => 8, :rm => 0,
                :crn => 16, :crd => 12, :crm => 0, :cpn => 8,
                :rnx => 16, :rdx => 12, :rsx => 8,
                :shifti => 7, :stype => 5, :rotate => 8, :reglist => 0,
                :i8 => 0, :i12 => 0, :i24 => 0, :i8_12 => 0,
                :u => 23, :mask => 16, :sbo => 12, :cond => 28

        addop_data 'and', 0,  :rd, :rn
        addop_data 'eor', 1,  :rd, :rn
        addop_data 'xor', 1,  :rd, :rn
        addop_data 'sub', 2,  :rd, :rn
        addop_data 'rsb', 3,  :rd, :rn
        addop_data 'add', 4,  :rd, :rn
        addop_data 'adc', 5,  :rd, :rn
        addop_data 'sbc', 6,  :rd, :rn
        addop_data 'rsc', 7,  :rd, :rn
        addop_data_s 'tst', (8  << 21) | (1 << 20), :rdx, :rn
        addop_data_s 'teq', (9  << 21) | (1 << 20), :rdx, :rn
        addop_data_s 'cmp', (10 << 21) | (1 << 20), :rdx, :rn
        addop_data_s 'cmn', (11 << 21) | (1 << 20), :rdx, :rn
        addop_data 'orr', 12, :rd, :rn
        addop_data 'or',  12, :rd, :rn
        addop_data 'mov', 13, :rd, :rnx
        addop_data 'bic', 14, :rd, :rn
        addop_data 'mvn', 15, :rd, :rnx

        addop 'b',  0b1010 << 24, :setip, :stopexec, :i24
        addop 'bl', 0b1011 << 24, :setip, :stopexec, :i24, :saveip
        addop 'bkpt', (0b00010010 << 20) | (0b0111 << 4)              # other fields are available&unused, also cnd != AL is undef
        addop 'blx', 0b1111101 << 25, :setip, :stopexec, :saveip, :tothumb, :h, :uncond, :i24
        addop 'blx', (0b00010010 << 20) | (0b0011 << 4), :setip, :stopexec, :saveip, :tothumb, :rm, :sbo16, :sbo12, :sbo8
        addop 'bx',  (0b00010010 << 20) | (0b0001 << 4), :setip, :stopexec, :rm, :sbo16, :sbo12, :sbo8
        addop 'bxj',  (0b00010010 << 20) | (0b0010 << 4), :setip, :stopexec, :rm, :tojazelle, :sbo16, :sbo12, :sbo8

        addop_load 'str', (1 << 26)
        addop_load 'ldr', (1 << 26) | (1 << 20)
        addop_load_lsh
        addop_ldm 'stm', (1 << 27)
        addop_ldm 'ldm', (1 << 27) | (1 << 20)
        # TODO aliases (http://www.davespace.co.uk/arm/introduction-to-arm/stack.html)
        # fd = full descending  stmfd/ldmfd = stmdb/ldmia
        # ed = empty descending stmed/ldmed = stmda/ldmib
        # fa = full ascending   stmfa/ldmfa = stmib/ldmda
        # ea = empty ascending  stmea/ldmea = stmia/ldmdb

        # TODO mrs, [qus]add/sub*
        addop 'clz',   (0b00010110 << 20) | (0b0001 << 4), :rd, :rm, :sbo16, :sbo8
        addop 'ldrex', (0b00011001 << 20) | (0b1001 << 4), :rd, :rn, :sbo8, :sbo0
        addop 'strex', (0b00011000 << 20) | (0b1001 << 4), :rd, :rm, :rn, :sbo8
        addop 'rev',   (0b01101011 << 20) | (0b0011 << 4), :rd, :rm, :sbo16, :sbo8
        addop 'rev16', (0b01101011 << 20) | (0b1011 << 4), :rd, :rm, :sbo16, :sbo8
        addop 'revsh', (0b01101111 << 20) | (0b1011 << 4), :rd, :rm, :sbo16, :sbo8
        addop 'sel',   (0b01101000 << 20) | (0b1011 << 4), :rd, :rn, :rm, :sbo8

end
init_arm_v6_thumb2() click to toggle source
# File metasm/cpu/arm/opcodes.rb, line 318
def init_arm_v6_thumb2
        init_arm_v6
        init_arm_thumb2
end
Also aliased as: init_latest
init_latest()
Alias for: init_arm_v6_thumb2