class Metasm::PPC
Public Class Methods
new()
click to toggle source
Calls superclass method
# File metasm/cpu/ppc/main.rb, line 111 def initialize super() @endianness = :big @size = 32 end
Public Instance Methods
addop(name, bin, *argprops)
click to toggle source
# File metasm/cpu/ppc/opcodes.rb, line 11 def addop(name, bin, *argprops) o = Opcode.new name, bin argprops.each { |a| o.args << a if @valid_args[a] o.fields[a] = [@fields_mask[a], @fields_shift[a]] if @fields_mask[a] o.props[a] = true if @valid_props[a] } @opcode_list << o end
addop_(base, bin, *argprops)
click to toggle source
adds op and 'op.' with last bit of bin set
# File metasm/cpu/ppc/opcodes.rb, line 86 def addop_(base, bin, *argprops) addop(base, bin, *argprops) addop(base+'.', bin|1, *argprops) end
addop_branch(nbase, bin, *argprops)
click to toggle source
generate l/a variations, add :setip/:saveip, include lr/ctr in opname
# File metasm/cpu/ppc/opcodes.rb, line 22 def addop_branch(nbase, bin, *argprops) nbase += 'ctr' if argprops.delete :ctr nbase += 'lr' if argprops.delete :lr addop(nbase, bin, :setip, *argprops) addop(nbase+'l', bin|1, :setip, :saveip, *argprops) return if nbase[-2, 2] == 'lr' or nbase[-3, 3] == 'ctr' addop(nbase+'a', bin|2, :setip, *argprops) addop(nbase+'la', bin|3, :setip, :saveip, *argprops) end
addop_branchcond(nbase, bin, *argprops)
click to toggle source
generate condition variations, passes to addop_branch
# File metasm/cpu/ppc/opcodes.rb, line 34 def addop_branchcond(nbase, bin, *argprops) # :bi & 0b11100 is the condition register to use, shift&mask == :bfa. Defaults to cr0 # bo values # no cc (10000 != 0) addop_branch(nbase, bin|(0b10100<<21), :ign_bo_zzz, :stopexec, *argprops) addop_branch(nbase+'dz', bin|(0b10010<<21), :ign_bo_at2, :stopexec, *argprops) if not argprops.include? :ctr addop_branch(nbase+'dnz', bin|(0b10000<<21), :ign_bo_at2, :stopexec, *argprops) if not argprops.include? :ctr # conditional %w[lt gt eq so].each_with_index { |cd, i| ncd = {'lt' => 'gte', 'gt' => 'lte', 'eq' => 'ne', 'so' => 'nso'}[cd] addop_branch(nbase+cd, bin|(0b1100<<21)|(i<<16), :ign_bo_at, *argprops) addop_branch(nbase+cd, bin|(0b1100<<21)|(i<<16), :ign_bo_at, :bfa, *argprops) addop_branch(nbase+ncd, bin|(0b100<<21)|(i<<16), :ign_bo_at, *argprops) addop_branch(nbase+ncd, bin|(0b100<<21)|(i<<16), :ign_bo_at, :bfa, *argprops) next if argprops.include? :ctr addop_branch(nbase+'dz'+cd, bin|(0b1010<<21)|(i<<16), :ign_bo_z, *argprops) addop_branch(nbase+'dz'+cd, bin|(0b1010<<21)|(i<<16), :ign_bo_z, :bfa, *argprops) addop_branch(nbase+'dnz'+cd, bin|(0b1000<<21)|(i<<16), :ign_bo_z, *argprops) addop_branch(nbase+'dnz'+cd, bin|(0b1000<<21)|(i<<16), :ign_bo_z, :bfa, *argprops) addop_branch(nbase+'dz'+ncd, bin|(0b010<<21)|(i<<16), :ign_bo_z, *argprops) addop_branch(nbase+'dz'+ncd, bin|(0b010<<21)|(i<<16), :ign_bo_z, :bfa, *argprops) addop_branch(nbase+'dnz'+ncd, bin|(0b000<<21)|(i<<16), :ign_bo_z, *argprops) addop_branch(nbase+'dnz'+ncd, bin|(0b000<<21)|(i<<16), :ign_bo_z, :bfa, *argprops) } end
addop_cmp(nbase, bin, *argprops)
click to toggle source
generate cmp variations (default cr0, w/d)
# File metasm/cpu/ppc/opcodes.rb, line 78 def addop_cmp(nbase, bin, *argprops) addop nbase.sub(/(cmpl?)/, '\\1w'), bin, *(argprops-[:bf]) addop nbase.sub(/(cmpl?)/, '\\1w'), bin, *argprops addop nbase.sub(/(cmpl?)/, '\\1d'), bin|(1<<@fields_shift[:l]), *(argprops-[:bf]) addop nbase.sub(/(cmpl?)/, '\\1d'), bin|(1<<@fields_shift[:l]), *argprops end
addop_o(base, bin, *argprops)
click to toggle source
adds op and 'opo'
# File metasm/cpu/ppc/opcodes.rb, line 92 def addop_o(base, bin, *argprops) addop(base, bin, *argprops) addop(base+'o', bin|0x400, *argprops) end
addop_trap(nbase, bin, *argprops)
click to toggle source
# File metasm/cpu/ppc/opcodes.rb, line 62 def addop_trap(nbase, bin, *argprops) addop nbase+'trap', bin|(0b11111<<21), *argprops addop nbase+'lt', bin|(0b10000<<21), *argprops addop nbase+'le', bin|(0b10100<<21), *argprops addop nbase+'eq', bin|(0b00100<<21), *argprops addop nbase+'ge', bin|(0b01100<<21), *argprops addop nbase+'gt', bin|(0b01000<<21), *argprops addop nbase+'ne', bin|(0b11000<<21), *argprops addop nbase+'llt', bin|(0b00010<<21), *argprops addop nbase+'lle', bin|(0b00110<<21), *argprops addop nbase+'lge', bin|(0b00101<<21), *argprops addop nbase+'lgt', bin|(0b00001<<21), *argprops end
backtrace_is_function_return(expr, di=nil)
click to toggle source
# File metasm/cpu/ppc/decode.rb, line 144 def backtrace_is_function_return(expr, di=nil) expr.reduce_rec == :lr end
backtrace_is_stack_address(expr)
click to toggle source
# File metasm/cpu/ppc/decode.rb, line 148 def backtrace_is_stack_address(expr) Expression[expr].expr_externals.include? :sp end
backtrace_update_function_binding(dasm, faddr, f, retaddrlist, *wantregs)
click to toggle source
# File metasm/cpu/ppc/decode.rb, line 126 def backtrace_update_function_binding(dasm, faddr, f, retaddrlist, *wantregs) retaddrlist.to_a.map! { |retaddr| dasm.decoded[retaddr] ? dasm.decoded[retaddr].block.list.last.address : retaddr } b = f.backtrace_binding bt_val = lambda { |r| bt = [] retaddrlist.to_a.each { |retaddr| bt |= dasm.backtrace(Expression[r], retaddr, :include_start => true, :snapshot_addr => faddr, :origin => retaddr) } b[r] = ((bt.length == 1) ? bt.first : Expression::Unknown) } wantregs = GPR::Sym if wantregs.empty? wantregs.map { |r| r.to_sym }.each(&bt_val) #puts "update_func_bind: #{Expression[faddr]} has sp -> #{b[:$sp]}" if not Expression[b[:$sp], :-, :$sp].reduce.kind_of?(::Integer) if $VERBOSE end
build_bin_lookaside()
click to toggle source
# File metasm/cpu/ppc/decode.rb, line 22 def build_bin_lookaside lookaside = Array.new(256) { [] } opcode_list.each { |op| next if not op.bin.kind_of? Integer build_opcode_bin_mask op b = op.bin >> 24 msk = op.bin_mask >> 24 for i in b..(b | (255^msk)) next if i & msk != b & msk lookaside[i] << op end } lookaside end
build_opcode_bin_mask(op)
click to toggle source
# File metasm/cpu/ppc/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 return if not op.bin.kind_of? Integer op.bin_mask = 0 op.fields.each { |k, (m, s)| op.bin_mask |= m << s } op.bin_mask = 0xffff_ffff ^ op.bin_mask end
decode_aliases(i)
click to toggle source
# File metasm/cpu/ppc/decode.rb, line 89 def decode_aliases(i) case i.opname when /^n?or\.?$/ if i.args[1] == i.args[2] i.args.pop i.opname = {'or' => 'mr', 'or.' => 'mr.', 'nor' => 'not', 'nor.' => 'not.'}[i.opname] end when /^addi/ if a = i.args[2].reduce and a.kind_of? Integer and a < 0 i.args[2] = Expression[-a] i.opname = i.opname.sub('addi', 'subi') end end case i.opname when /^(add|sub|xor|and|or|div|mul|nand)/ if i.args.length == 3 and i.args[0] == i.args[1] i.args.shift end end end
decode_findopcode(edata)
click to toggle source
# File metasm/cpu/ppc/decode.rb, line 39 def decode_findopcode(edata) return if edata.ptr+4 > edata.length di = DecodedInstruction.new(self) val = edata.decode_imm(:u32, @endianness) edata.ptr -= 4 di if di.opcode = @bin_lookaside[val >> 24].find { |op| (op.bin & op.bin_mask) == (val & op.bin_mask) } end
decode_instr_interpret(di, addr)
click to toggle source
converts relative branch offsets to absolute addresses else just add the offset off
of the instruction + its length (off may be an Expression
) assumes edata.ptr points just after the instruction (as decode_instr_op
left it) do not call twice on the same di !
# File metasm/cpu/ppc/decode.rb, line 116 def decode_instr_interpret(di, addr) if di.opcode.props[:setip] and di.instruction.args.last.kind_of? Expression and di.opcode.name[0] != ?t and di.opcode.name[-1] != ?a arg = Expression[addr, :+, di.instruction.args.last].reduce di.instruction.args[-1] = Expression[arg] end di end
decode_instr_op(edata, di)
click to toggle source
# File metasm/cpu/ppc/decode.rb, line 49 def decode_instr_op(edata, di) before_ptr = edata.ptr op = di.opcode di.instruction.opname = op.name val = edata.decode_imm(:u32, @endianness) field_val = lambda { |f| r = (val >> @fields_shift[f]) & @fields_mask[f] case f when :bd, :d, :ds, :dq, :si, :ui; r = Expression.make_signed(r<<@fields_shift[f], 16) when :li; r = Expression.make_signed(r<<@fields_shift[f], 26) else r end } op.args.each { |a| di.instruction.args << case a when :ra, :rb, :rs, :rt; GPR.new field_val[a] when :fra, :frb, :frc, :frs, :frt; FPR.new field_val[a] when :ra_i16, :ra_i16s, :ra_i16q i = field_val[{:ra_i16 => :d, :ra_i16s => :ds, :ra_i16q => :dq}[a]] Memref.new GPR.new(field_val[:ra]), Expression[i] when :bd, :d, :ds, :dq, :si, :ui, :li, :sh, :mb, :me, :mb_, :me_, :u; Expression[field_val[a]] when :ba, :bf, :bfa, :bt; CR.new field_val[a] when :bb, :bh, :flm, :fxm, :l_, :l__, :lev, :nb, :sh_, :spr, :sr, :tbr, :th, :to puts "PPC.decode: unsupported argument #{a.inspect}" if $VERBOSE # TODO Expression[field_val[a]] 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 decode_aliases(di.instruction) di end
decompile_blocks(dcmp, myblocks, deps, func, nextaddr = nil)
click to toggle source
# File metasm/cpu/ppc/decompile.rb, line 97 def decompile_blocks(dcmp, myblocks, deps, func, nextaddr = nil) scope = func.initializer func.type.args.each { |a| scope.symbol[a.name] = a } stmts = scope.statements func_entry = myblocks.first[0] until myblocks.empty? b, to = myblocks.shift if l = dcmp.dasm.get_label_at(b) stmts << C::Label.new(l) end # list of assignments [[dest reg, expr assigned]] ops = [] # reg binding (reg => value, values.externals = regs at block start) binding = {} # Expr => CExpr ce = lambda { |*e| dcmp.decompile_cexpr(Expression[Expression[*e].reduce], scope) } # Expr => Expr.bind(binding) => CExpr ceb = lambda { |*e| ce[Expression[*e].bind(binding)] } # dumps a CExprs that implements an assignment to a reg (uses ops[], patches op => [reg, nil]) commit = lambda { deps[b].map { |k| [k, ops.rindex(ops.reverse.find { |r, v| r == k })] }.sort_by { |k, i| i.to_i }.each { |k, i| next if not i or not binding[k] e = k final = [] ops[0..i].reverse_each { |r, v| final << r if not v e = Expression[e].bind(r => v).reduce if not final.include? r } ops[i][1] = nil binding.delete k stmts << ce[k, :'=', e] if k != e } } # go ! dcmp.dasm.decoded[b].block.list.each_with_index { |di, didx| a = di.instruction.args if di.opcode.props[:setip] and not di.opcode.props[:stopexec] # conditional jump commit[] n = dcmp.backtrace_target(get_xrefs_x(dcmp.dasm, di).first, di.address) #cc = ceb[decode_cc_to_expr(di.opcode.name[1..-1])] cc = ceb[:condjmp] stmts << C::If.new(C::CExpression[cc], C::Goto.new(n)) to.delete dcmp.dasm.normalize(n) next end case di.opcode.name when 'blr' commit[] stmts << C::Return.new(nil) when 'bl' # :saveip n = dcmp.backtrace_target(get_xrefs_x(dcmp.dasm, di).first, di.address) args = [] if t = dcmp.c_parser.toplevel.symbol[n] and t.type.args stackoff = Expression[dcmp.dasm.backtrace(:sp, di.address, :snapshot_addr => func_entry), :-, :sp].bind(:sp => :frameptr).reduce rescue nil args_todo = t.type.args.dup args = [] args_todo.each { if stackoff.kind_of? Integer var = Indirection[[:frameptr, :+, stackoff], @size/8] stackoff += @size/8 else var = 0 end args << ceb[var] binding.delete var } end commit[] #next if not di.block.to_subfuncret if n.kind_of? ::String if not f = dcmp.c_parser.toplevel.symbol[n] # internal functions are predeclared, so this one is extern f = dcmp.c_parser.toplevel.symbol[n] = C::Variable.new f.name = n f.type = C::Function.new(C::BaseType.new(:int)) dcmp.c_parser.toplevel.statements << C::Declaration.new(f) end commit[] else # indirect funcall fptr = ceb[n] binding.delete n commit[] proto = C::Function.new(C::BaseType.new(:int)) f = C::CExpression[[fptr], proto] end binding.delete :eax e = C::CExpression[f, :funcall, args] e = C::CExpression[ce[:eax], :'=', e, f.type.type] if deps[b].include? :eax and f.type.type != C::BaseType.new(:void) stmts << e when 'b' a = di.instruction.args.first if a.kind_of? Expression else # indirect jmp, convert to return (*fptr)(); n = di.instruction.args.first.symbolic fptr = ceb[n] binding.delete n commit[] proto = C::Function.new(C::BaseType.new(:void)) ret = C::Return.new(C::CExpression[[[fptr], C::Pointer.new(proto)], :funcall, []]) class << ret ; attr_accessor :from_instr end ret.from_instr = di stmts << ret to = [] end else bd = get_fwdemu_binding(di) if di.backtrace_binding[:incomplete_binding] commit[] stmts << C::Asm.new(di.instruction.to_s, nil, nil, nil, nil, nil) else bd.each { |k, v| if k.kind_of? ::Symbol ops << [k, v] else # memory stmts << ceb[k, :'=', v] binding.delete k end } update = {} bd.each { |k, v| next if not k.kind_of? ::Symbol update[k] = Expression[Expression[v].bind(binding).reduce] } binding.update update end end } commit[] case to.length when 0 if not myblocks.empty? and not %w[ret jmp].include? dcmp.dasm.decoded[b].block.list.last.instruction.opname puts " block #{Expression[b]} has no to and don't end in ret" end when 1 if (myblocks.empty? ? nextaddr != to[0] : myblocks.first.first != to[0]) stmts << C::Goto.new(dcmp.dasm.auto_label_at(to[0], 'unknown_goto')) end else puts " block #{Expression[b]} with multiple to" end end end
decompile_func_finddeps(dcmp, blocks, func)
click to toggle source
list variable dependency for each block, remove useless writes returns { blockaddr => [list of vars that are needed by a following block] }
# File metasm/cpu/ppc/decompile.rb, line 26 def decompile_func_finddeps(dcmp, blocks, func) deps_r = {} ; deps_w = {} ; deps_to = {} deps_subfunc = {} # things read/written by subfuncs # find read/writes by each block blocks.each { |b, to| deps_r[b] = [] ; deps_w[b] = [] ; deps_to[b] = to deps_subfunc[b] = [] blk = dcmp.dasm.decoded[b].block blk.list.each { |di| a = di.backtrace_binding.values w = [] di.backtrace_binding.keys.each { |k| case k when ::Symbol; w |= [k] else a |= Expression[k].externals # if dword [eax] <- 42, eax is read end } #a << :eax if di.opcode.name == 'ret' # standard ABI deps_r[b] |= a.map { |ee| Expression[ee].externals.grep(::Symbol) }.flatten - [:unknown] - deps_w[b] deps_w[b] |= w.map { |ee| Expression[ee].externals.grep(::Symbol) }.flatten - [:unknown] } stackoff = nil blk.each_to_normal { |t| t = dcmp.backtrace_target(t, blk.list.last.address) next if not t = dcmp.c_parser.toplevel.symbol[t] t.type = C::Function.new(C::BaseType.new(:int)) if not t.type.kind_of? C::Function # XXX this may seem a bit extreme, and yes, it is. stackoff ||= Expression[dcmp.dasm.backtrace(:sp, blk.list.last.address, :snapshot_addr => blocks.first[0]).first, :-, :sp].reduce } if stackoff # last block instr == subfunction call deps_r[b] |= deps_subfunc[b] - deps_w[b] #deps_w[b] |= [:eax, :ecx, :edx] # standard ABI end } # find regs read and never written (must have been set by caller and are part of the func ABI) uninitialized = lambda { |b, r, done| from = deps_to.keys.find_all { |f| deps_to[f].include? b } - done from.empty? or from.find { |f| !deps_w[f].include?(r) and uninitialized[f, r, done + [b]] } } # remove writes from a block if no following block read the value dw = {} deps_w.each { |b, deps| dw[b] = deps.reject { |dep| ret = true done = [] todo = deps_to[b].dup while a = todo.pop next if done.include? a done << a if not deps_r[a] or deps_r[a].include? dep ret = false break elsif not deps_w[a].include? dep todo.concat deps_to[a] end end ret } } dw end
decompile_makestackvars(dasm, funcstart, blocks) { |block| ... }
click to toggle source
temporarily setup dasm.address_binding so that backtracking stack-related offsets resolve in :frameptr (relative to func start)
# File metasm/cpu/ppc/decompile.rb, line 13 def decompile_makestackvars(dasm, funcstart, blocks) oldfuncbd = dasm.address_binding[funcstart] dasm.address_binding[funcstart] = { :sp => :frameptr } # this would suffice, the rest here is just optimisation blocks.each { |block| yield block } dasm.address_binding[funcstart] = oldfuncbd if oldfuncbd end
disassembler_default_func()
click to toggle source
# File metasm/cpu/ppc/decode.rb, line 164 def disassembler_default_func df = DecodedFunction.new df.backtrace_binding = (0..31).inject({}) { |h, r| r != 1 ? h.update("r#{r}".to_sym => Expression::Unknown) : h } df.backtracked_for = [BacktraceTrace.new(Expression[:lr], :default, Expression[:lr], :x)] df.btfor_callback = lambda { |dasm, btfor, funcaddr, calladdr| if funcaddr != :default btfor elsif di = dasm.decoded[calladdr] and di.opcode.props[:saveip] btfor else [] end } df end
get_xrefs_x(dasm, di)
click to toggle source
# File metasm/cpu/ppc/decode.rb, line 228 def get_xrefs_x(dasm, di) return [] if not di.opcode.props[:setip] arg = case di.instruction.opname when 'bctr', 'bctrl'; :ctr when 'blr', 'blrl'; :lr else di.instruction.args.last end [Expression[ case arg when Memref; Indirection[[arg.base.to_s.to_sym, :+, arg.offset], @size/8, di.address] when Reg; arg.to_s.to_sym else arg end]] end
init()
click to toggle source
# File metasm/cpu/ppc/opcodes.rb, line 97 def init @opcode_list = [] @fields_shift.update :aa => 1, :ba => 16, :bb => 11, :bd => 2, :bf => 23, :bfa => 18, :bh => 11, :bt => 21, :d => 0, :dq => 4, :ds => 2, :flm => 17, :fra => 16, :frb => 11, :frc => 6, :frs => 21, :frt => 21, :fxm => 12, :l => 21, :l_ => 21, :l__ => 16, :lev => 5, :li => 2, :lk => 0, :mb => 5, :mb_ => 6, :me => 5, :me_ => 1, :nb => 11, :oe => 10, :ra => 16, :rb => 11, :rc => 0, :rs => 21, :rt => 21, :sh => 11, :sh_ => 1, :si => 0, :spr => 11, :sr => 16, :tbr => 11, :th => 21, :to => 21, :u => 12, :ui => 0, :ign_bo_zzz => 16, :ign_bo_z => 21, :ign_bo_at => 21, :ign_bo_at2 => 16 @fields_mask.update :aa => 1, :ba => 31, :bb => 31, :bd => 0x3FFF, :bf => 7, :bfa => 7, :bh => 3, :bt => 31, :d => 0xFFFF, :dq => 0xFFF, :ds => 0x3FFF, :flm => 255, :fra => 31, :frb => 31, :frc => 31, :frs => 31, :frt => 31, :fxm => 255, :l => 1, :l_ => 3, :l__ => 1, :lev => 127, :li => 0xFFFFFF, :lk => 1, :mb => 63, :mb_ => 31, :me => 63, :me_ => 31, :nb => 31, :oe => 1, :ra => 31, :rb => 31, :rc => 1, :rs => 31, :rt => 31, :sh => 31, :sh_ => 1, :si => 0xFFFF, :spr => 0x3FF, :sr => 15, :tbr => 0x3FF, :th => 15, :to => 31, :u => 15, :ui => 0xFFFF, :ign_bo_zzz => 0b101111111, :ign_bo_z => 1, :ign_bo_at => 3, :ign_bo_at2 => 0b100111111 @fields_shift[:ra_i16] = @fields_shift[:ra_i16s] = @fields_shift[:ra_i16q] = 0 @fields_mask[:ra_i16] = (@fields_mask[:d] << @fields_shift[:d]) | (@fields_mask[:ra] << @fields_shift[:ra]) @fields_mask[:ra_i16s] = (@fields_mask[:ds] << @fields_shift[:d]) | (@fields_mask[:ra] << @fields_shift[:ra]) @fields_mask[:ra_i16q] = (@fields_mask[:dq] << @fields_shift[:d]) | (@fields_mask[:ra] << @fields_shift[:ra]) @valid_args = @fields_mask.dup [:ign_bo_zzz, :ign_bo_z, :ign_bo_at, :ign_bo_at2, :aa, :lk, :oe, :rc, :l].each { |k| @valid_args.delete k } addop_branch 'b', 0x48000000, :li, :stopexec addop_branchcond 'b', 0x40000000, :bd addop_branchcond 'b', 0x4C000020, :lr addop_branchcond 'b', 0x4C000420, :ctr addop 'sc', 0x44000002, :lev addop 'crand', 0x4C000202, :bt, :ba, :bb addop 'crxor', 0x4C000182, :bt, :ba, :bb # alias crclr bx -> crxor bx, bx, bx addop 'cror', 0x4C000382, :bt, :ba, :bb # alias crmove bx, by -> cror bx, by, by addop 'crnand', 0x4C0001C2, :bt, :ba, :bb addop 'crnor', 0x4C000042, :bt, :ba, :bb # alias crnot bx, by -> crnor bx, by, by addop 'crandc', 0x4C000102, :bt, :ba, :bb addop 'creqv', 0x4C000242, :bt, :ba, :bb # alias crset bx -> creqv bx, bx, bx addop 'crorc', 0x4C000342, :bt, :ba, :bb addop 'mcrf', 0x4C000000, :bf, :bfa addop 'lbz', 0x88000000, :rt, :ra_i16 addop 'lbzu', 0x8C000000, :rt, :ra_i16 addop 'lbzx', 0x7C0000AE, :rt, :ra, :rb addop 'lbzux', 0x7C0000EE, :rt, :ra, :rb addop 'lhz', 0xA0000000, :rt, :ra_i16 addop 'lhzu', 0xA4000000, :rt, :ra_i16 addop 'lhzx', 0x7C00022E, :rt, :ra, :rb addop 'lhzux', 0x7C00026E, :rt, :ra, :rb addop 'lha', 0xA8000000, :rt, :ra_i16 addop 'lhau', 0xAC000000, :rt, :ra_i16 addop 'lhax', 0x7C0002AE, :rt, :ra, :rb addop 'lhaux', 0x7C0002EE, :rt, :ra, :rb addop 'lwz', 0x80000000, :rt, :ra_i16 addop 'lwzu', 0x84000000, :rt, :ra_i16 addop 'lwzx', 0x7C00002E, :rt, :ra, :rb addop 'lwzux', 0x7C00006E, :rt, :ra, :rb addop 'lwa', 0xE8000002, :rt, :ra_i16s addop 'lwax', 0x7C0002AA, :rt, :ra, :rb addop 'lwaux', 0x7C0002EA, :rt, :ra, :rb addop 'ld', 0xE8000000, :rt, :ra_i16s addop 'ldu', 0xE8000001, :rt, :ra_i16s addop 'ldx', 0x7C00002A, :rt, :ra, :rb addop 'ldux', 0x7C00006A, :rt, :ra, :rb addop 'stb', 0x98000000, :rs, :ra_i16 addop 'stbu', 0x9C000000, :rs, :ra_i16 addop 'stbx', 0x7C0001AE, :rs, :ra, :rb addop 'stbux', 0x7C0001EE, :rs, :ra, :rb addop 'sth', 0xB0000000, :rs, :ra_i16 addop 'sthu', 0xB4000000, :rs, :ra_i16 addop 'sthx', 0x7C00032E, :rs, :ra, :rb addop 'sthux', 0x7C00036E, :rs, :ra, :rb addop 'stw', 0x90000000, :rs, :ra_i16 addop 'stwu', 0x94000000, :rs, :ra_i16 addop 'stwx', 0x7C00012E, :rs, :ra, :rb addop 'stwux', 0x7C00016E, :rs, :ra, :rb addop 'std', 0xF8000000, :rs, :ra_i16s addop 'stdu', 0xF8000001, :rs, :ra_i16s addop 'stdx', 0x7C00012A, :rs, :ra, :rb addop 'stdux', 0x7C00016A, :rs, :ra, :rb addop 'lhbrx', 0x7C00062C, :rt, :ra, :rb addop 'lwbrx', 0x7C00042C, :rt, :ra, :rb addop 'sthbrx', 0x7C00072C, :rs, :ra, :rb addop 'stwbrx', 0x7C00052C, :rs, :ra, :rb addop 'lmw', 0xB8000000, :rt, :ra_i16 addop 'stmw', 0xBC000000, :rs, :ra_i16 addop 'lswi', 0x7C0004AA, :rt, :ra, :nb addop 'lswx', 0x7C00042A, :rt, :ra, :rb addop 'stswi', 0x7C0005AA, :rs, :ra, :nb addop 'stswx', 0x7C00052A, :rs, :ra, :rb addop 'li', 0x38000000, :rt, :si # alias li rx, value -> addi rx, 0, value addop 'addi', 0x38000000, :rt, :ra, :si addop 'la', 0x38000000, :rt, :ra_i16 # alias la rx, disp(ry) -> addi rx, ry, disp addop 'lis', 0x3C000000, :rt, :si # alias lis rx, value -> addis rx, 0, value addop 'addis', 0x3C000000, :rt, :ra, :si addop_o 'add', 0x7C000214, :rt, :ra, :rb addop 'addic', 0x30000000, :rt, :ra, :si addop_o 'sub', 0x7C000050, :rt, :rb, :ra # alias sub rx, ry, rz -> subf rx, rz, ry addop_o 'subf', 0x7C000050, :rt, :ra, :rb addop 'addic.', 0x34000000, :rt, :ra, :si addop 'subfic', 0x20000000, :rt, :ra, :si addop_o 'addc', 0x7C000014, :rt, :ra, :rb addop_o 'subc', 0x7C000010, :rt, :rb, :ra # alias subc rx, ry, rz -> subfc rx, rz, ry addop_o 'subfc',0x7C000010, :rt, :ra, :rb addop_o 'adde', 0x7C000114, :rt, :ra, :rb addop_o 'addme',0x7C0001D4, :rt, :ra addop_o 'subfe',0x7C000110, :rt, :ra, :rb addop_o 'subfme',0x7C0001D0,:rt, :ra addop_o 'addze',0x7C000194, :rt, :ra addop_o 'subfze',0x7C000190,:rt, :ra addop_o 'neg', 0x7C0000D0, :rt, :ra addop 'mulli', 0x1C000000, :rt, :ra, :si addop_o 'mulld',0x7C0001D2, :rt, :ra, :rb addop_o 'mullw',0x7C0001D6, :rt, :ra, :rb addop_ 'mulhd', 0x7C000092, :rt, :ra, :rb addop_ 'mulhdu',0x7C000012, :rt, :ra, :rb addop_ 'mulhw', 0x7C000096, :rt, :ra, :rb addop_ 'mulhwu',0x7C000016, :rt, :ra, :rb addop_o 'divd', 0x7C0003D2, :rt, :ra, :rb addop_o 'divw', 0x7C0003D6, :rt, :ra, :rb addop_o 'divdu',0x7C000392, :rt, :ra, :rb addop_o 'divwu',0x7C000396, :rt, :ra, :rb addop_cmp 'cmpi', 0x2C000000, :bf, :ra, :si addop_cmp 'cmp', 0x7C000000, :bf, :ra, :rb addop_cmp 'cmpli', 0x28000000, :bf, :ra, :ui addop_cmp 'cmpl', 0x7C000040, :bf, :ra, :rb addop 'andi.', 0x70000000, :ra, :rs, :ui addop 'andis.', 0x74000000, :ra, :rs, :ui addop 'nop', 0x60000000 addop 'ori', 0x60000000, :ra, :rs, :ui addop 'oris', 0x64000000, :ra, :rs, :ui addop 'xori', 0x68000000, :ra, :rs, :ui addop 'xoris', 0x6C000000, :ra, :rs, :ui addop_ 'and', 0x7C000038, :ra, :rs, :rb addop_ 'xor', 0x7C000278, :ra, :rs, :rb addop_ 'or', 0x7C000378, :ra, :rs, :rb # alias mr rx, ry -> or rx, ry, ry addop_ 'nand', 0x7C0003B8, :ra, :rs, :rb addop_ 'nor', 0x7C0000F8, :ra, :rs, :rb # alias not rx, ry -> nor rx, ry, ry addop_ 'andc', 0x7C000078, :ra, :rs, :rb addop_ 'eqv', 0x7C000238, :ra, :rs, :rb addop_ 'orc', 0x7C000338, :ra, :rs, :rb addop_ 'extsb', 0x7C000774, :ra, :rs addop_ 'extsw', 0x7C0007B4, :ra, :rs addop_ 'extsh', 0x7C000734, :ra, :rs addop_ 'cntlzd',0x7C000074, :ra, :rs addop_ 'cntlzw',0x7C000034, :ra, :rs addop 'popcntb',0x7C0000F4, :ra, :rs addop 'clrldi', 0x78000000, :ra, :rs, :mb # alias clrldi rx, ry, n -> rldicl rx, ry, 0, n addop_ 'rldicl',0x78000000, :ra, :rs, :sh, :mb, :sh_ # alias extrdi rx, ry, n, b -> rldicl rx, ry, b+n, 64 - n # alias srdi rx, ry, n -> rldicl rx, ry, 64 - n, n addop_ 'rldicr',0x78000004, :ra, :rs, :sh, :me, :sh_ # alias extldi rx, ry, n, b -> rldicr rx, ry, b, n - 1 # alias sldi rx, ry, n -> rldicr rx, ry, n, 63 - n # alias clrrdi rx, ry, n -> rldicr rx, ry, 0, 63 - n addop_ 'rldic', 0x78000008, :ra, :rs, :sh, :mb, :sh_ # alias clrlsldi rx, ry, b, n -> rldic rx, ry, n, b - n addop_ 'rlwinm',0x54000000, :ra, :rs, :sh, :mb_, :me_ # alias extlwi rx, ry, n, b -> rlwinm rx, ry, b, 0, n - 1 # alias srwi rx, ry, n -> rlwinm rx, ry, 32 - n, n, 31 # alias clrrwi rx, ry, n -> rlwinm rx, ry, 0, 0, 31 - n addop 'rotld', 0x78000010, :ra, :rs, :rb # alias rotld rx, ry, rz -> rldcl rx, ry, rz, 0 addop_ 'rldcl', 0x78000010, :ra, :rs, :rb, :mb addop_ 'rldcr', 0x78000012, :ra, :rs, :rb, :me addop 'rotlw', 0x5C000000|(31<<@fields_shift[:me_]), :ra, :rs, :rb # alias rotlw rx, ry, rz -> rlwnm rx, ry, rz, 0, 31 addop_ 'rlwnm', 0x5C000000, :ra, :rs, :rb, :mb_, :me_ addop_ 'rldimi',0x7800000C, :ra, :rs, :sh, :mb, :sh_ # alias insrdi rx, ry, n, b -> rldimi rx, ry, 64 - (b+n), b addop_ 'rlwimi',0x50000000, :ra, :rs, :sh, :mb_, :me_ # alias inslwi rx, ry, n, b -> rlwimi rx, ry, 32-b, b, b+n - 1 addop_ 'sld', 0x7C000036, :ra, :rs, :rb addop_ 'slw', 0x7C000030, :ra, :rs, :rb addop_ 'srd', 0x7C000436, :ra, :rs, :rb addop_ 'srw', 0x7C000430, :ra, :rs, :rb addop_ 'sradi', 0x7C000674, :ra, :rs, :sh, :sh_ addop_ 'srawi', 0x7C000670, :ra, :rs, :sh addop_ 'srad', 0x7C000634, :ra, :rs, :rb addop_ 'sraw', 0x7C000630, :ra, :rs, :rb #addop 'mtspr', 0x7C0003A6, :spr, :rs addop 'mtxer', 0x7C0003A6|(1<<16), :rs addop 'mtlr', 0x7C0003A6|(8<<16), :rs addop 'mtctr', 0x7C0003A6|(9<<16), :rs #addop 'mfspr', 0x7C0002A6, :rt, :spr addop 'mfxer', 0x7C0002A6|(1<<16), :rt addop 'mflr', 0x7C0002A6|(8<<16), :rt addop 'mfctr', 0x7C0002A6|(9<<16), :rt addop 'mtcrf', 0x7C000120, :fxm, :rs # alias mtcr rx -> mtcrf 0xff, rx addop 'mfcr', 0x7C000026, :rt addop 'lfs', 0xC0000000, :frt, :ra_i16 addop 'lfsu', 0xC4000000, :frt, :ra_i16 addop 'lfsx', 0x7C00042E, :frt, :ra, :rb addop 'lfsux', 0x7C00046E, :frt, :ra, :rb addop 'lfd', 0xC8000000, :frt, :ra_i16 addop 'lfdu', 0xCC000000, :frt, :ra_i16 addop 'lfdx', 0x7C0004AE, :frt, :ra, :rb addop 'lfdux', 0x7C0004EE, :frt, :ra, :rb addop 'stfs', 0xD0000000, :frs, :ra_i16 addop 'stfsu', 0xD4000000, :frs, :ra_i16 addop 'stfsx', 0x7C00052E, :frs, :ra, :rb addop 'stfsux', 0x7C00056E, :frs, :ra, :rb addop 'stfd', 0xD8000000, :frs, :ra_i16 addop 'stfdu', 0xDC000000, :frs, :ra_i16 addop 'stfdx', 0x7C0005AE, :frs, :ra, :rb addop 'stfdux', 0x7C0005EE, :frs, :ra, :rb addop 'stfiwx', 0x7C0007AE, :frs, :ra, :rb addop_ 'fmr', 0xFC000090, :frt, :frb addop_ 'fabs', 0xFC000210, :frt, :frb addop_ 'fneg', 0xFC000050, :frt, :frb addop_ 'fnabs', 0xFC000110, :frt, :frb addop_ 'fadd', 0xFC00002A, :frt, :fra, :frb addop_ 'fadds', 0xEC00002A, :frt, :fra, :frb addop_ 'fsub', 0xFC000028, :frt, :fra, :frb addop_ 'fsubs', 0xEC000028, :frt, :fra, :frb addop_ 'fmul', 0xFC000032, :frt, :fra, :frc addop_ 'fmuls', 0xEC000032, :frt, :fra, :frc addop_ 'fdiv', 0xFC000024, :frt, :fra, :frb addop_ 'fdivs', 0xEC000024, :frt, :fra, :frb addop_ 'fmadd', 0xFC00003A, :frt, :fra, :frc, :frb addop_ 'fmadds',0xEC00003A, :frt, :fra, :frc, :frb addop_ 'fmsub', 0xFC000038, :frt, :fra, :frc, :frb addop_ 'fmsubs',0xEC000038, :frt, :fra, :frc, :frb addop_ 'fnmadd',0xFC00003E, :frt, :fra, :frc, :frb addop_ 'fnmadds',0xEC00003E,:frt, :fra, :frc, :frb addop_ 'fnmsub',0xFC00003C, :frt, :fra, :frc, :frb addop_ 'fnmsubs',0xEC00003C,:frt, :fra, :frc, :frb addop_ 'frsp', 0xFC000018, :frt, :frb addop_ 'fctid', 0xFC00065C, :frt, :frb addop_ 'fctidz',0xFC00065E, :frt, :frb addop_ 'fctiw', 0xFC00001C, :frt, :frb addop_ 'fctiwz',0xFC00001E, :frt, :frb addop_ 'fcfid', 0xFC00069C, :frt, :frb addop 'fcmpu', 0xFC000000, :bf, :fra, :frb addop 'fcmpo', 0xFC000040, :bf, :fra, :frb addop_ 'mffs', 0xFC00048E, :frt addop 'mcrfs', 0xFC000080, :bf, :bfa addop_ 'mtfsfi',0xFC00010C, :bf, :u addop_ 'mtfsf', 0xFC00058E, :flm, :frb addop_ 'mtfsb0',0xFC00008C, :bt addop_ 'mtfsb1',0xFC00004C, :bt addop 'mtocrf', 0x7C100120, :fxm, :rs addop_ 'fsqrt', 0xFC00002C, :frt, :frb addop_ 'fsqrts',0xEC00002C, :frt, :frb addop_ 'fre', 0xFC000030, :frt, :frb addop_ 'fres', 0xEC000030, :frt, :frb addop_ 'frsqrte',0xFC000034,:frt, :frb addop_ 'frsqrtes',0xEC000034, :frt, :frb addop_ 'fsel', 0xFC00002E, :frt, :fra, :frc, :frb addop 'mcrxr', 0x7C000400, :bf addop 'icbi', 0x7C0007AC, :ra, :rb addop 'dcbt', 0x7C00022C, :ra, :rb addop 'dcbtst', 0x7C0001EC, :ra, :rb addop 'dcbz', 0x7C0007EC, :ra, :rb addop 'dcbst', 0x7C00006C, :ra, :rb addop 'dcbf', 0x7C0000AC, :ra, :rb addop 'isync', 0x4C00012C addop 'lwarx', 0x7C000028, :rt, :ra, :rb addop 'ldarx', 0x7C0000A8, :rt, :ra, :rb addop 'stwcx.', 0x7C00012D, :rs, :ra, :rb addop 'stdcx.', 0x7C0001AD, :rs, :ra, :rb addop 'sync', 0x7C0004AC, :l_ addop 'eieio', 0x7C0006AC addop 'mftb', 0x7C0002E6, :rt, :tbr addop 'eciwx', 0x7C00026C, :rt, :ra, :rb addop 'ecowx', 0x7C00036C, :rs, :ra, :rb addop 'dcbt', 0x7C00022C, :ra, :rb, :th addop 'dcbf', 0x7C0000AC, :ra, :rb addop 'dcbf', 0x7C0000AC, :ra, :rb, :l addop 'sc', 0x44000002, :lev addop 'rfid', 0x4C000024 addop 'hrfid', 0x4C000224 addop 'mtmsrd', 0x7C000164, :rs, :l__ addop 'mfmsr', 0x7C0000A6, :rt addop 'slbie', 0x7C000364, :rb addop 'slbmte', 0x7C000324, :rs, :rb addop 'slbmfev',0x7C0006A6, :rt, :rb addop 'slbmfee',0x7C000726, :rt, :rb addop 'tlbie', 0x7C000264, :rb, :l addop 'tlbiel', 0x7C000224, :rb, :l addop 'tlbia', 0x7C0002E4 addop 'tlbsync',0x7C00046C addop 'mtmsr', 0x7C000124, :rs, :l__ addop 'lq', 0xE0000000, :rt, :ra_i16q addop 'stq', 0xF8000002, :rs, :ra_i16s addop 'mtsr', 0x7C0001A4, :sr, :rs addop 'mtsrin', 0x7C0001E4, :rs, :rb addop 'mfsr', 0x7C0004A6, :rt, :sr addop 'mfsrin', 0x7C000526, :rt, :rb addop_trap 'tw', 0x7C000008, :ra, :rb addop_trap 'twi', 0xC0000000, :ra, :si addop_trap 'td', 0x7C000088, :ra, :rb addop_trap 'tdi', 0x08000000, :ra, :si # pseudo-instructions addop 'mr', :pseudo, :ra, :rb addop 'not', :pseudo, :ra addop 'not', :pseudo, :ra, :rb @opcode_list.each { |op| if op.name =~ /^addi/ addop op.name.sub('add', 'sub'), :pseudo, *op.args end if op.name =~ /^(add|sub|xor|and|or|div|mul|nand)/ and op.args.length == 3 addop op.name, :pseudo, *op.args[1..-1] end } end
init_backtrace_binding()
click to toggle source
# File metasm/cpu/ppc/decode.rb, line 179 def init_backtrace_binding @backtrace_binding ||= {} opcode_list.map { |ol| ol.name }.uniq.each { |op| binding = case op when 'mr', 'li', 'la'; lambda { |di, a0, a1| { a0 => Expression[a1] } } when 'lis'; lambda { |di, a0, a1| { a0 => Expression[a1, :<<, 16] } } when 'mtctr'; lambda { |di, a0| { :ctr => Expression[a0] } } when 'mfctr'; lambda { |di, a0| { a0 => Expression[:ctr] } } when 'mtlr'; lambda { |di, a0| { :lr => Expression[a0] } } when 'mflr'; lambda { |di, a0| { a0 => Expression[:lr] } } when 'lwzu'; lambda { |di, a0, m| ret = { a0 => Expression[m] } ptr = m.pointer.externals.grep(Symbol).first ret[ptr] = m.pointer if ptr != a0 ret } when 'lwz'; lambda { |di, a0, m| { a0 => Expression[m] } } when 'stwu'; lambda { |di, a0, m| { m => Expression[a0], m.pointer.externals.grep(Symbol).first => m.pointer } } when 'stw'; lambda { |di, a0, m| { m => Expression[a0] } } when 'rlwinm'; lambda { |di, a0, a1, sh, mb, me| mb, me = mb.reduce, me.reduce cpmsk = (1<<@size) - 1 a1 = Expression[a1, :&, cpmsk] rol = Expression[[a1, :<<, sh], :|, [a1, :>>, [@size, :-, sh]]] if mb == me+1 msk = cpmsk elsif mb < me+1 msk = (((1 << ((me+1)-mb)) - 1) << (@size-(me+1))) else msk = (((1 << (mb-(me+1))) - 1) << (@size-mb)) ^ cpmsk end { a0 => Expression[Expression[rol, :&, msk].reduce] } } when 'add', 'addi', 'add.', 'addi.'; lambda { |di, *a| { a[0] => Expression[a[-2], :+, a[-1]] } } when 'addis', 'addis.'; lambda { |di, *a| { a[0] => Expression[a[-2], :+, [a[-1], :<<, 16]] } } when 'sub', 'subi', 'sub.', 'subi.'; lambda { |di, *a| { a[0] => Expression[a[-2], :-, a[-1]] } } when 'subis', 'subis.'; lambda { |di, *a| { a[0] => Expression[a[-2], :-, [a[-1], :<<, 16]] } } when /^b.*la?$/; lambda { |di, *a| { :lr => Expression[di.next_addr] } } when 'nop', /^cmp/, /^b/; lambda { |di, *a| {} } end @backtrace_binding[op] ||= binding if binding } @backtrace_binding end
init_opcode_list()
click to toggle source
# File metasm/cpu/ppc/main.rb, line 117 def init_opcode_list init end
parse_arg_valid?(op, sym, arg)
click to toggle source
# File metasm/cpu/ppc/parse.rb, line 13 def parse_arg_valid?(op, sym, arg) case sym when :ra, :rb, :rs, :rt; arg.kind_of?(GPR) when :fra, :frb, :frc, :frs, :frt; arg.kind_of?(FPR) when :ra_i16, :ra_i16s, :ra_i16q; arg.kind_of?(Memref) when :bd, :d, :ds, :dq, :si, :ui, :li, :sh, :mb, :me, :mb_, :me_, :u; arg.kind_of?(Expression) when :ba, :bf, :bfa, :bt; arg.kind_of?(CR) when :ign_bo_zzz, :ign_bo_z, :ign_bo_at, :ign_bo_at2, :aa, :lk, :oe, :rc, :l; # ? when :bb, :bh, :flm, :fxm, :l_, :l__, :lev, :nb, :sh_, :spr, :sr, :tbr, :th, :to # TODO else raise "internal error: mips arg #{sym.inspect}" end end
parse_argument(pgm)
click to toggle source
# File metasm/cpu/ppc/parse.rb, line 27 def parse_argument(pgm) pgm.skip_space return if not tok = pgm.readtok if tok.type == :string return GPR.new(GPR.s_to_i[tok.raw]) if GPR.s_to_i[tok.raw] return SPR.new(SPR.s_to_i[tok.raw]) if SPR.s_to_i[tok.raw] return FPR.new(FPR.s_to_i[tok.raw]) if FPR.s_to_i[tok.raw] return CR.new(CR.s_to_i[tok.raw]) if CR.s_to_i[tok.raw] return MSR.new if tok.raw == 'msr' end pgm.unreadtok tok arg = Expression.parse pgm pgm.skip_space # check memory indirection: 'off(base reg)' # XXX scaled index ? if arg and pgm.nexttok and pgm.nexttok.type == :punct and pgm.nexttok.raw == '(' pgm.readtok pgm.skip_space_eol ntok = pgm.readtok raise tok, "Invalid base #{ntok}" unless ntok and ntok.type == :string and GPR.s_to_i[ntok.raw] base = GPR.new GPR.s_to_i[ntok.raw] pgm.skip_space_eol ntok = pgm.readtok raise tok, "Invalid memory reference, ')' expected" if not ntok or ntok.type != :punct or ntok.raw != ')' arg = Memref.new base, arg end arg end
render_instruction(i)
click to toggle source
# File metasm/cpu/ppc/main.rb, line 121 def render_instruction(i) r = [i.opname] if not i.args.empty? r << ' ' i.args.each { |a| r << a << ', ' } r.pop end r end
replace_instr_arg_immediate(i, old, new)
click to toggle source
# File metasm/cpu/ppc/decode.rb, line 152 def replace_instr_arg_immediate(i, old, new) i.args.map! { |a| case a when Expression; a == old ? new : Expression[a.bind(old => new).reduce] when Memref a.offset = (a.offset == old ? new : Expression[a.offset.bind(old => new).reduce]) if a.offset.kind_of? Expression a else a end } end
Private Instance Methods
encode_instr_op(exe, instr, op)
click to toggle source
# File metasm/cpu/ppc/encode.rb, line 13 def encode_instr_op(exe, instr, op) base = op.bin set_field = lambda { |f, v| base |= (v & @fields_mask[f]) << @fields_shift[f] } val, mask, shift = 0, 0, 0 # TODO # convert label name for jmp/call/loop to relative offset if op.props[:setip] and op.name[0] != ?t and instr.args.last.kind_of? Expression postlabel = exe.new_label('jmp_offset') instr = instr.dup instr.args[-1] = Expression[[instr.args[-1], :-, postlabel], :>>, 2] postdata = EncodedData.new '', :export => {postlabel => 0} else postdata = '' end op.args.zip(instr.args).each { |sym, arg| case sym when :rs, :rt, :rd, :ba, :bf, :bfa, :bt set_field[sym, arg.i] when :ft set_field[sym, arg.i] when :rs_i16 set_field[:rs, arg.base.i] val, mask, shift = arg.offset, @fields_mask[:i16], @fields_shift[:i16] when :sa, :i16, :i20 val, mask, shift = arg, @fields_mask[sym], @fields_shift[sym] when :i26 val, mask, shift = Expression[arg, :>>, 2], @fields_mask[sym], @fields_shift[sym] end } Expression[base, :+, [[val, :&, mask], :<<, shift]].encode(:u32, @endianness) << postdata end