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