1/*
2 *  powerpc-darwin.dylib-entry.S -- program entry point & decompress (PowerPC32 dylib)
3 *
4 *  This file is part of the UPX executable compressor.
5 *
6 *  Copyright (C) 2005-2020 John F. Reiser
7 *  All Rights Reserved.
8 *
9 *  UPX and the UCL library are free software; you can redistribute them
10 *  and/or modify them under the terms of the GNU General Public License as
11 *  published by the Free Software Foundation; either version 2 of
12 *  the License, or (at your option) any later version.
13 *
14 *  This program is distributed in the hope that it will be useful,
15 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
16 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17 *  GNU General Public License for more details.
18 *
19 *  You should have received a copy of the GNU General Public License
20 *  along with this program; see the file COPYING.
21 *  If not, write to the Free Software Foundation, Inc.,
22 *  59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
23 *
24 *  John F. Reiser
25 *  <jreiser@users.sourceforge.net>
26 *
27 */
28
29#include "arch/powerpc/32/macros.S"
30#include "arch/powerpc/32/ppc_regs.h"
31
32/*************************************************************************
33// We have been CALLed as a subroutine from dyld; C-language rules apply.
34// -4*4+_start: .long offset(user_init_function)
35// -3*4+_start: .long offset(b_info of compressed Mach_headers)
36// -2*4+_start: .long length(compressed __TEXT)
37// -1*4+_start: .long 8+ total_length  # 8+ number of preceding bytes in file
38**************************************************************************/
39
40  section MACOS000
41_start: .globl _start
42        mflr r2
43        call main  # must be exactly 1 instruction; link_register= &decompress
44decompress:
45  section NRV_HEAD
46SZ_DLINE=128  # size of data cache line in Apple G5
47
48/* PowerPC has no 'cmplis': compare logical [unsigned] immediate shifted [by 16] */
49#define  hibit r0  /* holds 0x80000000 during decompress */
50
51#define src  a0
52#define lsrc a1
53#define dst  a2
54#define ldst a3  /* Out: actually a reference: &len_dst */
55#define meth a4
56
57#define off  a4
58#define len  a5
59#define bits a6
60#define disp a7
61
62  section NRV2E
63#include "arch/powerpc/32/nrv2e_d.S"
64
65  section NRV2D
66#include "arch/powerpc/32/nrv2d_d.S"
67
68  section NRV2B
69#include "arch/powerpc/32/nrv2b_d.S"
70
71#include "arch/powerpc/32/lzma_d.S"
72
73#undef off
74#undef len
75#undef bits
76#undef disp
77
78  section NRV_TAIL
79eof_nrv:
80#define dst0 a4
81#define tmp a1
82        lwz dst0,0(ldst)  // original dst
83        mtlr t3  // return address
84        subf a0,lsrc,src
85        subf tmp,dst0,dst  // -1+ dst length
86        addi a0,a0,1  // return 0: good; else: bad  [+1: correct for lbzu]
87        addi tmp,tmp,1  // dst length
88        stw  tmp,0(ldst)
89#undef tmp
90
91// CACHELINE=32 is the observed minimum line size of any cache.
92// Some caches may have larger lines, but it is cumbersome to lookup
93// {AT_DCACHEBSIZE, AT_ICACHEBSIZE, AT_UCACHEBSIZE: /usr/include/elf.h},
94// then save the correct size in a variable {where to put it?}, or to modify
95// the two instructions here.  If a cache has larger lines, then we expect
96// that the second dcbst (or icbi) on a the same line will be fast.
97// If not, then too bad.
98
99  section CFLUSH  // In: a2=dst= &highest stored byte; a4=dst0= &lowest stored byte
100CACHELINE=32
101        ori dst0,dst0,-1+ CACHELINE  // highest addr on cache line
102cfl_nrv:
103        dcbst  0,dst0  // initiate store (modified) cacheline to memory
104        cmpl cr0,dst0,dst  // did we cover the highest-addressed byte?
105        icbi   0,dst0  // discard instructions from cacheline
106        addi     dst0,dst0,CACHELINE  // highest addr on next line
107        blt  cr0,cfl_nrv  // not done yet
108#undef dst0
109        sync   // wait for all memory operations to finish
110        isync  // discard prefetched instructions (if any)
111cfl_ret:
112        ret
113
114  section ELFMAINY
115        // IDENTSTR goes here
116
117  section ELFMAINZ
118sz_l_info= 12
119sz_p_info= 12
120sz_b_info= 12
121  sz_unc= 0
122  sz_cpr= 4
123  b_method= 8
124  b_ftid=   9
125  b_cto8=  10
126
127// register numbers during entry
128#define f_unc 31
129#define f_uini 30
130#define l_unm 29
131#define a_unm 28
132#define r_unc 27
133#define r_cpr 26
134#define s_unc 25
135#define s_cpr 24
136#define l_unc 23
137#define l_cpr 22
138#define t_h   21  /* temporary */
139
140PROT_NONE  =0x00
141PROT_READ  =0x01
142PROT_WRITE =0x02
143PROT_EXEC  =0x04
144
145MAP_SHARED  =0x1
146MAP_PRIVATE =0x2
147MAP_ANON    =0x1000
148
149SYS_mmap    =197
150SYS_munmap=   73
151SYS_mprotect= 74
152
153main2:
154    teq r0,r0  // debugging
155        stwu r2,-4*(1+ 32-a0)(sp)  # retaddr
156        stmw r3,4*1(sp)
157        mflr f_unc  # f_unc= &decompress
158        lwz  t_h, -4*1(f_unc)  # "call main" at _start
159        lwz  l_unm,-4*1+ _start - decompress(f_unc)  # 4+ offset(_start)
160        rlwinm t_h,t_h,0,6,29  # 4+ main - decompress
161        add  l_unm,l_unm,t_h  # offset(main); ASSUMES (8+_start)==decompress
162        addi t_h,t_h,-4   # main - decompress
163
164        li  a0,0  # addr
165        mr  a1,l_unm  # length for munmap
166        li  a2,PROT_READ|PROT_WRITE
167        li  a3,MAP_ANON|MAP_PRIVATE
168        li  a4,-1
169        li  a5,0  # hi32(offset)
170        li  a6,0  # lo32(offset)
171        li  0,SYS_mmap
172        sc
173          li a0,-1  # failure
174        mr a_unm,a0  # address for munmap
175
176
177        li   a2,main - movup2
178        mtctr a2
179        add  a1,a0 ,l_unm  # lwa(dst); new_page + offset(main)
180        add  a0,t_h,f_unc  # lwa(src); &main
181movup1:  # descending copy [moveup2, main)
182        lbzu r0,-1(a0)
183        stbu r0,-1(a1)
184        bdnz+ movup1
185
186        subf a2,a2,l_unm  # offset(movup2)
187        mtlr a1  # &copied movup2
188        mtctr a2  # offset(movup2)
189        blr  # goto the copied code
190
191movup2:  # descending copy [base, movup2)
192        lbzu r0,-1(a0)
193        stbu r0,-1(a1)
194        bdnz+ movup2
195
196        lwz  f_uini,-4*4+ _start - decompress(f_unc)  # offset(user_init_fn)
197        subf f_unc,a0,f_unc
198        add  f_unc,a1,f_unc  # relocated decompress
199        add  f_uini,f_uini,a0
200
201        lwz  t2,-4*3+ _start - decompress(f_unc)  # offset(b_info)
202        add  r_cpr,a1,t2  # &b_info
203        add  r_unc,a0,t2  # &b_info
204        addi r_unc,r_unc,-sz_l_info -sz_p_info
205
206        // skip compressed Mach headers
207        lwz  t2,sz_cpr(r_cpr)
208        addi r_cpr,r_cpr,sz_b_info
209        add  r_cpr,r_cpr,t2
210dy_uncpr:
211        mr s_cpr,r_cpr
212        mr s_unc,r_unc
213        addi a0,r_cpr,sz_unc; call get4; beq dy_done
214                                        add r_unc,r_unc,a0; mr l_unc,a0
215        addi a0,r_cpr,sz_cpr; call get4
216                                        add r_cpr,r_cpr,a0; mr l_cpr,a0
217        addi r_cpr,r_cpr,sz_b_info
218
219        stwu l_unc,-8(sp)  # keep stack 8-byte aligned
220        mtlr f_unc
221        addi a0,s_cpr,sz_b_info  # src
222        mr a1,l_cpr
223        mr a2,s_unc  # dst
224        mr a3,sp  # &l_dst
225        lbz a4,b_method(s_cpr)
226        stwu sp,-SZ_FRAME(sp)
227        blrl  # uncompress
228        la sp,8+SZ_FRAME(sp)
229                // FIXME: check status
230
231        lbz a3,b_ftid(s_cpr); cmpli cr0,a3,0; beq dy_uncpr
232        lbz a2,b_cto8(s_cpr)
233        lwz a1,sz_unc(s_cpr)
234        mr  a0,s_unc
235        bl unfilter
236        b dy_uncpr
237
238dy_done:
239        bl dy_done2
240dy_done1:  # escape hatch
241        sc  # munmap
242          li a0,~0  # failure
243        lmw r2,4*1(sp); addi sp,sp,4*(32-r2)
244        mtlr t2  # &continuation in dyld
245        bctr  # goto user_init_function
246dy_done2:
247        li t2,(dy_done2 - dy_done1)/4
248        mflr a0; la a0,dy_done2 - dy_done1(a0)
249        mtctr t2
250dy_done3:
251        lwzu t2,-4(a0)
252        stwu t2,-4(s_unc)
253        bdnz+ dy_done3
254
255        mtlr s_unc
256        mtctr f_uini  # user_init_function
257        mr a0,a_unm
258        mr a1,l_unm
259        li  0,SYS_munmap
260        blr  # goto relocated dy_done1
261
262get4:
263        lbz t2,3(a0)
264        lbz t1,2(a0); rlwimi t2,t1, 8,16,23
265        lbz t1,1(a0); rlwimi t2,t1,16, 8,15
266        lbz t1,0(a0); rlwimi t2,t1,24, 0, 7
267        mr. a0,t2  # set condition codes
268        blr
269
270unfilter:
271#include "arch/powerpc/32/bxx.S"
272
273main:
274        b main2
275dy_top:
276len_top  = dy_top - main
277
278/* vim:set ts=8 sw=8 et: */
279