From 46f925611467c91458d87d33145705b7a0b3c61a Mon Sep 17 00:00:00 2001 From: John Reiser Date: Sat, 19 Feb 2005 23:32:39 +0000 Subject: [PATCH] PowerPC unfilter, decompress, and register definitions Added Files: ppc_bxx.S ppc_d_nrv2e.S ppc_regs.h committer: jreiser 1108855959 +0000 --- src/stub/ppc_bxx.S | 60 +++++++++++++++ src/stub/ppc_d_nrv2e.S | 168 +++++++++++++++++++++++++++++++++++++++++ src/stub/ppc_regs.h | 40 ++++++++++ 3 files changed, 268 insertions(+) create mode 100644 src/stub/ppc_bxx.S create mode 100644 src/stub/ppc_d_nrv2e.S create mode 100644 src/stub/ppc_regs.h diff --git a/src/stub/ppc_bxx.S b/src/stub/ppc_bxx.S new file mode 100644 index 00000000..15dd395d --- /dev/null +++ b/src/stub/ppc_bxx.S @@ -0,0 +1,60 @@ +/* ppc_bxx.S -- PowerPC Branch Trick unfilter + + This file is part of the UPX executable compressor. + + Copyright (C) 2005 John F. Reiser + All Rights Reserved. + + UPX and the UCL library are free software; you can redistribute them + and/or modify them under the terms of the GNU General Public License as + published by the Free Software Foundation; either version 2 of + the License, or (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; see the file COPYING. + If not, write to the Free Software Foundation, Inc., + 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + + John F. Reiser + +*/ + +#include "ppc_regs.h" + +ppcbxx: # (*f_unf)(xo->buf, out_len, h.b_cto8, h.b_ftid); +#define W_CTO 4 /* must match filteri/ppcbxx.h */ + +#define ptr a0 +#define len a1 +#define cto8 a2 +#define ftid a3 + +#define ptr0 a4 + + cmpli cr0,ftid,0xd0; bnelr- cr0 # if (0xd0!=ftid) return; + rlwinm. len,len,32-2,2,31; beqlr- cr0 # if (0==(len>>=2)) return; + addi cto8,cto8,18< + + John F. Reiser + +*/ + +#include "ppc_regs.h" + +/* Returns 0 on success; non-zero on failure. */ +decompress: # (uchar const *src, size_t lsrc, uchar *dst, size_t &ldst) + +/* PowerPC has no 'cmplis': compare logical [unsigned] immediate shifted [by 16] */ +#define hibit r0 /* holds 0x80000000 during decompress */ + +#define src a0 +#define lsrc a1 +#define dst a2 +#define ldst a3 /* Out: actually a reference: &len_dst */ + +#define off a4 +#define len a5 +#define bits a6 +#define disp a7 + + stw dst,0(ldst) # original dst + add lsrc,lsrc,src # input eof + + lis hibit,0x8000 # 0x80000000 for detecting next bit + lis bits,0x8000 # prepare for first load + addi src,src,-1 # prepare for 'lbzu' + addi dst,dst,-1 # prepare for 'stbu' + li disp,-1 # initial displacement + + mflr t3 # return address + b top_n2e + +/* jump on next bit, with branch prediction: y==>likely; n==>unlikely + cr0 is set by the cmpl ["compare logical"==>unsigned]: + lt next bit is 0 + gt next bit is 1 + eq must load next 32 bits from memory + + beql-: branch and link [call subroutine] if cr0 is eq, unlikely +*/ +#define jnextb0y cmpl 0,bits,hibit; add bits,bits,bits; beql- get32; blt+ +#define jnextb0n cmpl 0,bits,hibit; add bits,bits,bits; beql- get32; blt- +#define jnextb1y cmpl 0,bits,hibit; add bits,bits,bits; beql- get32; bgt+ +#define jnextb1n cmpl 0,bits,hibit; add bits,bits,bits; beql- get32; bgt- + +/* rotate next bit into bottom bit of reg */ +#define getnextb(reg) addc. bits,bits,bits; beql- get32; adde reg,reg,reg + +get32: + # fetch 4 bytes unaligned and LITTLE ENDIAN +#if 0 /*{ clean; but 4 instr larger, and 3 cycles longer */ + lbz bits,1(src) # lo8 + lbz t0,2(src); rlwimi bits,t0, 8,16,23 + lbz t0,3(src); rlwimi bits,t0,16, 8,15 + lbzu t0,4(src); rlwimi bits,t0,24, 0, 7 +#else /*}{ pray for no unalignment trap or slowdown */ + li bits,1 # compensate for 'lbzu' + lwbrx bits,bits,src # bits= fetch_le32(bits+src) + addi src,src,4 +#endif /*}*/ + + cmpl 0,bits,hibit # cr0 for jnextb + addc bits,bits,bits # CArry for getnextb + ori bits,bits,1 # the flag bit + ret + +lit_n2e: +#define tmp len + lbzu tmp,1(src) + stbu tmp,1(dst) +#undef tmp +top_n2e: + jnextb1y lit_n2e + li off,1 + b getoff_n2e + +off_n2e: + addi off,off,-1 + getnextb(off) +getoff_n2e: + getnextb(off) + jnextb0n off_n2e + + li len,0 + addic. off,off,-3 # CArry set [and ignored], but no 'addi.' + rlwinm off,off,8,0,31-8 # off<<=8; + blt- offprev_n2e + lbzu t0,1(src) + nor. disp,off,t0 # disp = -(1+ (off|t0)); + srawi disp,disp,1 # shift off low bit (sets CArry; ignored) + beq- eof_n2e + andi. t0,t0,1 # complement of low bit of unshifted disp + beq+ lenlast_n2e # low bit was 1 + b lenmore_n2e # low bit was 0 + +offprev_n2e: + jnextb1y lenlast_n2e +lenmore_n2e: + li len,1 # 1: "the msb" + jnextb1y lenlast_n2e +len_n2e: + getnextb(len) + jnextb0n len_n2e + addi len,len,6-2-2 + b gotlen_n2e + +lenlast_n2e: + getnextb(len) # 0,1,2,3 +gotlen_n2e: +#define tmp off + subfic tmp,disp,(~0)+(-0x500) # want CArry only +#undef tmp + addi len,len,2 + addze len,len # len += (disp < -0x500); + +#define back off + add back,disp,dst # point back to match in dst + mtctr len +short_n2e: +#define tmp len + lbzu tmp,1(back) + stbu tmp,1(dst) +#undef tmp + bdnz+ short_n2e + b top_n2e +#undef back + +eof_n2e: +#define tmp r0 /* hibit is dead */ + lwz tmp,0(ldst) # original dst + mtlr t3 # return address + addi dst,dst,1 # uncorrect for 'stbu' + addi src,src,1 # uncorrect for 'lbzu' + subf dst,tmp,dst # dst -= tmp; // dst length +#undef tmp + subf a0,lsrc,src # src -= eof; // return 0: good; else: bad + stw dst,0(ldst) + ret + diff --git a/src/stub/ppc_regs.h b/src/stub/ppc_regs.h new file mode 100644 index 00000000..38d285e6 --- /dev/null +++ b/src/stub/ppc_regs.h @@ -0,0 +1,40 @@ +#ifndef __PPC_REGS__ /*{*/ +#define __PPC_REGS__ + +#define r0 0 +#define r1 1 +#define r2 2 + +#define r29 29 +#define r30 30 +#define r31 31 + + /* Stack pointer */ +#define sp 1 + + /* Subroutine arguments; not saved by callee */ +#define a0 3 +#define a1 4 +#define a2 5 +#define a3 6 +#define a4 7 +#define a5 8 +#define a6 9 +#define a7 10 + + /* Scratch (temporary) registers; not saved by callee */ +#define t0 2 +#define t1 11 +#define t2 12 +#define t3 13 + +/* branch and link */ +#define call bl + +/* branch to link register */ +#define ret blr + +/* move register */ +#define movr mr + +#endif /*} __PPC_REGS__ */