class Metasm::X86_64::ModRM

ModRM represents indirections (eg dword ptr [eax+4*ebx+12h]) 16bit mode unavailable in x64 opcodes use 64bit addressing by default, use adsz override (67h) prefix to switch to 32 immediate values are encoded as :i32 sign-extended to 64bits

Public Class Methods

decode(edata, byte, endianness, adsz, opsz, seg=nil, regclass=Reg, pfx={}) click to toggle source
# File metasm/cpu/x86_64/decode.rb, line 13
def self.decode(edata, byte, endianness, adsz, opsz, seg=nil, regclass=Reg, pfx={})
        m = (byte >> 6) & 3
        rm = byte & 7

        if m == 3
                rm |= 8 if pfx[:rex_b] and (regclass != SimdReg or opsz != 64)      # mm8 -> mm0
                return regclass.new(rm, opsz)
        end

        adsz ||= 64

        # mod 0/1/2 m 4 => sib
        # mod 0 m 5 => rip+imm
        # sib: i 4 => no index, b 5 => no base

        s = i = b = imm = nil
        if rm == 4
                sib = edata.get_byte.to_i

                ii = (sib >> 3) & 7
                ii |= 8 if pfx[:rex_x]
                if ii != 4
                        s = 1 << ((sib >> 6) & 3)
                        if pfx[:mrmvex]
                                i = SimdReg.new(ii, pfx[:mrmvex])
                        else
                                i = Reg.new(ii, adsz)
                        end

                end

                bb = sib & 7
                if bb == 5 and m == 0
                        m = 2      # :i32 follows
                else
                        bb |= 8 if pfx[:rex_b]
                        b = Reg.new(bb, adsz)
                end
        elsif rm == 5 and m == 0
                b = Reg.new(16, adsz)
                m = 2       # :i32 follows
        else
                rm |= 8 if pfx[:rex_b]
                b = Reg.new(rm, adsz)
        end

        case m
        when 1; itype = :i8
        when 2; itype = :i32
        end
        imm = Expression[edata.decode_imm(itype, endianness)] if itype

        if imm and imm.reduce.kind_of? Integer and imm.reduce < -0x100_0000
                # probably a base address -> unsigned
                imm = Expression[imm.reduce & ((1 << adsz) - 1)]
        end

        opsz = pfx[:argsz] if pfx[:argsz]
        new adsz, opsz, s, i, b, imm, seg
end
encode_reg(reg, mregval = 0) click to toggle source
# File metasm/cpu/x86_64/encode.rb, line 13
def self.encode_reg(reg, mregval = 0)
        v = reg.kind_of?(Reg) ? reg.val_enc : reg.val & 7
        0xc0 | (mregval << 3) | v
end

Public Instance Methods

encode(reg = 0, endianness = :little) click to toggle source
# File metasm/cpu/x86_64/encode.rb, line 18
def encode(reg = 0, endianness = :little)
        reg = reg.val if reg.kind_of? Ia32::Argument

        ret = EncodedData.new << (reg << 3)

        # add bits in the first octet of ret.data (1.9 compatibility layer)
        or_bits = lambda { |v|       # rape me
                if ret.data[0].kind_of? Integer
                        ret.data[0] |= v
                else
                        ret.data[0] = (ret.data[0].unpack('C').first | v).chr
                end
        }

        if not self.b and not self.i
                # imm only, use sib
                or_bits[4]
                imm = self.imm || Expression[0]
                [ret << ((4 << 3) | 5) << imm.encode(:i32, endianness)]

        elsif (self.b and self.b.val == 16) or (self.i and self.i.val == 16) # rip+imm       (rip == addr of the octet after the current instr)
                # should have been filtered by #parse, but just in case
                raise "invalid rip addressing #{self}" if (self.i and self.b) or (self.s and self.s != 1)
                or_bits[5]
                imm = self.imm || Expression[0]
                [ret << imm.encode(:i32, endianness)]

        elsif not self.b and self.s != 1
                # sib with no b
                raise EncodeError, "Invalid ModRM #{self}" if @i.val == 4   # XXX 12 ?
                or_bits[4]
                s = {8=>3, 4=>2, 2=>1}[@s]
                imm = self.imm || Expression[0]
                fu = (s << 6) | (@i.val_enc << 3) | 5
                fu = fu.chr if s >= 2       # rb1.9 encoding fix
                [ret << fu << imm.encode(:i32, endianness)]
        else
                imm = @imm.reduce if self.imm
                imm = nil if imm == 0

                if not self.i or (not self.b and self.s == 1)
                        # no sib byte (except for [esp])
                        @s, @i, @b = nil, nil, @s if not self.b
                        or_bits[@b.val_enc]
                        ret << 0x24 if @b.val_enc == 4     # XXX val_enc ?
                else
                        # sib
                        or_bits[4]

                        @b, @i = @i, @b if @s == 1 and @i.kind_of?(Reg) and (@i.val_enc == 4 or @b.val_enc == 5)

                        raise EncodeError, "Invalid ModRM #{self}" if @i.val == 4

                        s = {8=>3, 4=>2, 2=>1, 1=>0}[@s]
                        fu = (s << 6) | (@i.val_enc << 3) | @b.val_enc
                        fu = fu.chr if s >= 2      # rb1.9 encoding fix
                        ret << fu
                end

                imm ||= 0 if @b.val_enc == 5
                if imm
                        case Expression.in_range?(imm, :i8)
                        when true
                                or_bits[1<<6]
                                [ret << Expression.encode_imm(imm, :i8, endianness)]
                        when false
                                or_bits[2<<6]
                                [ret << Expression.encode_imm(imm, :a32, endianness)]
                        when nil
                                rets = ret.dup
                                or_bits[1<<6]
                                ret << @imm.encode(:i8, endianness)
                                rets, ret = ret, rets     # or_bits[] modifies ret directly
                                or_bits[2<<6]
                                ret << @imm.encode(:a32, endianness)
                                [ret, rets]
                        end
                else
                        [ret]
                end
        end
end