/* arm.v4t-linux.shlib-init.S -- Linux Elf shared library init & decompressor * * This file is part of the UPX executable compressor. * * Copyright (C) 1996-2020 Markus Franz Xaver Johannes Oberhumer * Copyright (C) 1996-2020 Laszlo Molnar * Copyright (C) 2000-2020 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. * * Markus F.X.J. Oberhumer Laszlo Molnar * * * John F. Reiser * */ NBPW= 4 #define ARM_OLDABI 1 #include "arch/arm/v5a/macros.S" #define bkpt .long 0xe7f001f0 /* reserved instr; Linux GNU eabi breakpoint */ #define bkpt_th .short 0xde01 /* reserved instr; Linux GNU eabi breakpoint */ sz_Elf32_Ehdr = 13*NBPW sz_Elf32_Phdr = 8*NBPW sz_b_info= 12 sz_unc= 0 sz_cpr= 4 b_method= 8 sz_l_info= 12 sz_p_info= 12 PROT_READ= 1 PROT_WRITE= 2 PROT_EXEC= 4 MAP_PRIVATE= 2 MAP_FIXED= 0x10 MAP_ANONYMOUS= 0x20 PAGE_SHIFT= 12 PAGE_MASK= (~0<>12) src for f_exp //D_INFO: // .long offset(.) // detect relocation // .long offset(user DT_INIT) // .long offset(escape_hatch) // override with round_up(2, PT_LOAD[0]{.p_memsz + .p_vaddr}) // .long offset(dst for f_exp) #define DEBUG 0 .code 16 //; .balign 4 .real_start_ofELFMAINX: .thumb_func _start: .globl _start #if DEBUG //{ bkpt_th // for debugging #else //}{ nop #endif //} push {r0,r1,r2,r3,r4,r5,r6,r7,lr} _=9 o_uinit= 1 // lr adr esi,here sub esi,#(here - _start) + 5*NBPW // -NBPW + &D_INFO here: ldr tmp,[esi,#0*NBPW] // offset(b_info)|(asl_delta>>12) mov edi,#1 add ecx,esi,#NBPW // &D_INFO ldr eax,[esi,#1*NBPW] and edi,tmp // asl_delta>>12 sub tmp,edi // offset(b_info) sub ecx,eax; //str ecx,[SP(o_reloc)] lsl edi,#12 // asl_delta ldr eax,[esi,#2*NBPW]; cmp eax,#0; beq 0f // empty user_init add eax,ecx // reloc DT_INIT for step 12 add eax,edi str eax,[SP(o_uinit)] 0: ldr edi,[esi,#4*NBPW]; add edi,ecx // dst for f_exp add esi,tmp,ecx // &b_info src for f_exp sub sp,#3*NBPW // 3 slots of space _=1+_ // &escape_hatch (step 10) o_hatch=_ // 10 _=2+_ // param space: munmap temp pages (step 9) p_unmap=_ // 12 push_ lr // will be lr at entry to user_init o_lr=_ // 13 ldr eax,[esi,#sz_cpr]; add esi,#sz_b_info add esi,eax // skip unpack helper block lodslu // eax=dstlen lsl tmp,edi,#(32-PAGE_SHIFT) lsr tmp,tmp,#(32-PAGE_SHIFT) // tmp= fragment add eax,tmp; push_ eax // params: mprotect restored pages step 8 sub edi,tmp; push_ edi p_mprot=_ // 15 sub eax,tmp // dstlen add edi,tmp // dst lsr tmp,tmp,#2; push_ tmp // w_fragment o_wfrag=_ // 16 call4 L610 f_unfilter: // (char *ptr, uint len, uint cto, uint fid) #define ptr r0 #define len r1 #define cto r2 /* FIXME: unused */ #define fid r3 #define t1 r2 #define t2 r3 #ifndef FILTER_ID /*{*/ #define FILTER_ID 0x50 /* little-endian */ #endif /*}*/ lsl fid,fid,#24; lsr len,len,#2 lsr fid,fid,#24; lsl len,len,#2 cmp fid,#FILTER_ID; bne unf_done // last use of fid b tst_unf top_unf: sub len,len,#4 ldr t1,[ptr,len] lsl t2,t1,#4 lsr t2,t2,#4+24 // bits 27..24 cmp t2,#0x0b; bne tst_unf // not 'bl' subroutine call lsr len,len,#2; sub t2,t1,len // convert to word-relative displacement lsl len,len,#2 lsr t1,t1,#24; lsl t2,t2,#8 lsl t1,t1,#24; lsr t2,t2,#8 orr t1,t1,t2 // re-combine str t1,[ptr,len] tst_unf: cmp len,#0 bne top_unf unf_done: ret #undef ptr #undef len #undef cto #undef fid #undef t1 #undef t2 .thumb_func L610: push_ lr // &f_unfilter (thumb mode) o_unflt=_ // 17 ldrb tmp,[esi,#b_method-4+1]; push_ tmp // ftid ldrb tmp,[esi,#b_method-4+2]; push_ tmp // cto8 push_ eax // dstlen also for unfilter step 7 push_ edi // dst param for unfilter step 7 p_unflt=_ // 21 lodslu; mov ecx,eax // ecx= srclen lodslu; push_ eax // method,filter,cto,junk call4 L710 .arm f_decompress: #define LINUX_ARM_CACHEFLUSH 1 section NRV_HEAD // empty section NRV_TAIL // empty section NRV2E #include "arch/arm/v4a/nrv2e_d8.S" section NRV2D #include "arch/arm/v4a/nrv2d_d8.S" section NRV2B #include "arch/arm/v4a/nrv2b_d8.S" #include "arch/arm/v4a/lzma_d.S" section ELFMAINY end_decompress: .globl end_decompress msg_SELinux: mov r2,#L71 - L70 // length adr r1,L70 // message text mov r0,#2 // fd stderr #if defined(ARMEL_EABI4) /*{*/ mov r7,#__NR_write swi 0 #else /*}{*/ swi __NR_write #endif /*}*/ die: mov r0,#127 #if defined(ARMEL_EABI4) /*{*/ mov r7,#__NR_exit swi 0 #else /*}{*/ swi __NR_exit #endif /*}*/ L70: .asciz "PROT_EXEC|PROT_WRITE failed.\n" L71: /* IDENTSTR goes here */ section ELFMAINZ .code 16; .balign 2 .real_start_ofELFMAINZ: .thumb_func L710: .real_start_ofL710: // 1. allocate temporary pages // 2. copy to temporary pages: // fragment of page below dst; compressed src; // decompress+unfilter; supervise // 3. mmap destination pages for decompressed data // 4. create escape hatch // 5. jump to temporary pages // 6. uncompress // 7. unfilter // 8. mprotect decompressed pages // 9 setup args for unmap of temp pages // 10. jump to escape hatch // 11. unmap temporary pages // 12. goto user DT_INIT mov tmp,lr; sub tmp,#1; push_ tmp // &f_decompress (ARM mode) o_uncpr=_ // 23 add tmp,SP(p_unflt)+1*NBPW; push_ tmp // &dstlen push_ edi // dst push_ ecx // srclen push_ esi // src; arglist ready for decompress step 6 p_uncpr=_ // 27 mov tmp,#3 and tmp,esi // length of prefix alignment add ecx,#3 // allow suffix alignment add ecx,tmp // prefix increases byte length lsr ecx,#2 // w_srclen ldr tmp,[SP(o_wfrag)]; add edx,tmp,ecx // w_srclen + w_frag ldr tmp,[SP(o_uncpr)]; bl wlen_subr; add edx,ecx ldr tmp,[SP(o_unflt)]; bl wlen_subr; add edx,ecx call4 L220 SAVE_=_ supervise: // moved at runtime before being executed // Allocate pages for result of decompressing. // These replace the compressed source and the following hole. mov arg5,#0; mvn arg5,arg5 // -1; cater to *BSD for fd of MAP_ANON mov arg4,#MAP_PRIVATE|MAP_ANONYMOUS|MAP_FIXED mov arg3,#PROT_READ|PROT_WRITE ldr arg2,[SP(p_mprot)+4] // dstlen ldr arg1,[SP(p_mprot) ] // dst mov r6,arg1 // required result thumb_sys7t __NR_mmap64; cmp r0,r6; beq 0f; bkpt_th; 0: // Restore fragment of page below dst ldr ecx,[SP(o_wfrag)] //mov edi,r0 // NOP: edi==r0 ldr esi,[SP(p_unmap)] bl movsl pop {arg1,arg2,arg3,arg4, eax} _=-5+_ // 22 blx eax // decompress pop_ tmp // toss arg5 // Place the escape hatch pop {arg1,arg2} // addr, len mov tmp,#1 push {arg1,arg2} add edi,arg1,arg2 // ldr edi,[SP(o_hatch)] add edi,#1 bic edi,tmp // round_up(2, .p_memsz + .p_vaddr) ldr tmp,hatch // the 2 instructions str tmp,[edi] add edi,#1 // thumb mode str edi,[SP(o_hatch)] //p_unflt // 21 pop {arg1,arg2,arg3,arg4, eax, r5} // r5= w_fragment [discard] _=-6+_ // 15 tst arg4,arg4; beq 0f // 0==ftid ==> no filter blx eax // f_unfilter 0: ldr arg1,[sp,#0*NBPW] // lo(dst) ldr arg2,[sp,#1*NBPW] // len add arg2,arg1 // hi(dst) bl x__ARM_NR_cacheflush //p_mprot // 15 pop {arg1,arg2, tmp}; mov lr,tmp _=-3+_ // 12 mov arg3,#PROT_READ|PROT_EXEC thumb_sys7t __NR_mprotect //p_unmap .if __NR_munmap <= 0xff mov r7,#__NR_munmap .else mov r7,#__NR_munmap>>16 lsl r7,#16 add r7,#__NR_munmap - ((__NR_munmap>>16)<<16) .endif pop {arg1,arg2, pc} // goto hatch _=-3+_ // 9 .balign 4 hatch: swi 0 // 0xdf00; munmap pop {r0,r1,r2,r3,r4,r5,r6,r7,pc} // 0xbdff; goto user DT_INIT .thumb_func movsl_subr: .real_start_ofmovsl_subr: lsr esi,esi,#2 lsl esi,esi,#2 // word align [corrects for thumb-mode] push {lr}; mov tmp,esi; bl wlen_subr pop {tmp}; mov lr,tmp // FALL THROUGH to the part of 'movsl' that trims to a multiple of 8 words. // 7/8 of the time this is faster; 1/8 of the time it's slower. 9: ldr tmp,[esi,#0]; add esi,#4 str tmp,[edi,#0]; add edi,#4 sub ecx,#1 .thumb_func movsl: // In: edi= 4-byte aligned dst; esi= 4-byte aligned src; ecx= word count .real_start_ofmovsl: mov tmp,#7; tst ecx,tmp; bne 9b lsr ecx,#3; beq 8f // THUMB return when zero .balign 4; bx pc; nop // enter ARM mode .arm stmdb sp!,{r2, r4,r6, r7,r8,r9} // tmp===r3, ecx===r5 7: ldmia esi!,{r2,r3,r4,r6, r7,r8,r9,r12}; subs ecx,ecx,#1 stmia edi!,{r2,r3,r4,r6, r7,r8,r9,r12}; bne 7b ldmia sp!,{r2, r4,r6, r7,r8,r9} 9: ret 8: .thumb bx lr #if !defined(ARMEL_EABI4) /*{*/ .arm .balign 4 x__NR_mmap: do_sys7t __NR_mmap64 bx lr x__NR_munmap: do_sys7t __NR_munmap bx lr x__NR_mprotect: do_sys7t __NR_mprotect bx lr .thumb #endif /*}*/ .thumb_func x__ARM_NR_cacheflush: .real_start_ofx__ARM_NR_cacheflush: mov arg3,#0 mov r7,#__ARM_NR_BASE>>16 lsl r7,#16 add r7,# __ARM_NR_cacheflush - __ARM_NR_BASE swi 0 bx lr .thumb_func L220: .real_start_ofL220: _=SAVE_ // 27 mov tmp,lr; sub tmp,#1; push_ tmp // &supervise o_super=_ // 28 bl wlen_subr; add edx,ecx // wlen_supervise lsl arg2,edx,#2 // convert to bytes // Allocate pages to hold temporary copy. mov arg5,#0; mvn arg5,arg5 // -1; cater to *BSD for fd of MAP_ANON mov arg4,#MAP_PRIVATE|MAP_ANONYMOUS mov arg3,#PROT_READ|PROT_WRITE|PROT_EXEC str arg2,[SP(p_unmap)+1*NBPW] // length to unmap mov arg1,#0 // any addr thumb_sys7t __NR_mmap64; asr tmp,r0,#12; add tmp,#1; bne 0f; bkpt_th; 0: str r0,[SP(p_unmap)] // address to unmap ldr esi,[SP(p_mprot)] //mov edi,r0 // edi= dst NOP: edi==r0 ldr ecx,[SP(o_wfrag)] // w_fragment bl movsl // copy the fragment ldr esi,[SP(p_uncpr)+0*NBPW] // src ldr ecx,[SP(p_uncpr)+1*NBPW] // len mov tmp,#3 and tmp,esi // length of prefix alignment sub esi,tmp // down to word aligned add ecx,tmp // prefix increases byte length add tmp,edi // skip prefix at destination str tmp,[SP(p_uncpr)+0*NBPW] // dst add ecx,#3 // round up to full words lsr ecx,#2 bl movsl // copy all aligned words that contain compressed data mov edx,edi // lo(dst) of copied code ldr esi,[SP(o_uncpr)] str edi,[SP(o_uncpr)] bl movsl_subr // copy decompressor add tmp,edi,#1 // dst f_unfilter thumb mode ldr esi,[SP(o_unflt)] str tmp,[SP(o_unflt)] bl movsl_subr // copy f_unfilter pop_ esi // &supervise add r7,edi,#1 // &copied (thumb mode) bl movsl_subr // copy supervisor mov arg2,edi // hi(dst) of copied code mov arg1,edx // lo(dst) of copied code mov lr,r7 // return address for ... b x__ARM_NR_cacheflush // call with continuation return get4u: ldrb eax,[esi,#3]; ldrb tmp,[esi,#2]; lsl eax,#8; orr eax,tmp ldrb tmp,[esi,#1]; lsl eax,#8; orr eax,tmp ldrb tmp,[esi,#0]; lsl eax,#8; orr eax,tmp add esi,#4 ret wlen_subr: // Out: ecx= nwords of inline subr at *tmp lsr tmp,tmp,#2 lsl tmp,tmp,#2 // word align (correct for thumb mode) sub tmp,#4 ldrh ecx,[tmp,#0]; lsl ecx,#32-11; lsr ecx,#32-11-11 // hi(disp) ldrh tmp,[tmp,#2]; lsl tmp,#32-11; lsr tmp,#32-11- 0 // lo(disp) add ecx,tmp // disp add ecx,#1+1 // disp omits 1 word; prepare to round lsr ecx,#1 // round up to whole 32-bit words ret /*__XTHEENDX__*/ /* vim:set ts=8 sw=8 et: */