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