1/* arm_nrv2e_d8.S -- ARM decompressor for NRV2E
2
3   This file is part of the UPX executable compressor.
4
5   Copyright (C) 1996-2020 Markus Franz Xaver Johannes Oberhumer
6   Copyright (C) 1996-2020 Laszlo Molnar
7   Copyright (C) 2000-2020 John F. Reiser
8   All Rights Reserved.
9
10   UPX and the UCL library are free software; you can redistribute them
11   and/or modify them under the terms of the GNU General Public License as
12   published by the Free Software Foundation; either version 2 of
13   the License, or (at your option) any later version.
14
15   This program is distributed in the hope that it will be useful,
16   but WITHOUT ANY WARRANTY; without even the implied warranty of
17   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18   GNU General Public License for more details.
19
20   You should have received a copy of the GNU General Public License
21   along with this program; see the file COPYING.
22   If not, write to the Free Software Foundation, Inc.,
23   59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
24
25   Markus F.X.J. Oberhumer              Laszlo Molnar
26   <markus@oberhumer.com>               <ezerotven+github@gmail.com>
27
28   John F. Reiser
29   <jreiser@users.sourceforge.net>
30*/
31#define SAFE 0  /* 1 for src+dst bounds checking: cost 40 bytes */
32
33#define src  r0
34#define len  r1  /* overlaps 'cnt' */
35#define dst  r2
36#define tmp  r3
37#define bits r4
38#define off  r5
39#define wrnk r6  /* 0x500  M2_MAX_OFFSET before "wrinkle" */
40#define srclim r7
41#if 1==SAFE  /*{*/
42#define dstlim r12
43#endif  /*}*/
44
45#define cnt  r1  /* overlaps 'len' while reading an offset */
46
47#if 1==SAFE  /*{*/
48#define CHECK_SRC  cmp src,srclim; bhs bad_src_n2e
49#define CHECK_DST  cmp dst,dstlim; bhs bad_dst_n2e
50#else  /*}{*/
51#define CHECK_SRC  /*empty*/
52#define CHECK_DST  /*empty*/
53#endif  /*}*/
54
55#if 0  /*{ DEBUG only: check newly-decompressed against original dst */
56#define CHECK_BYTE \
57   push {wrnk}; \
58   ldrb  wrnk,[dst]; \
59   cmp   wrnk,tmp; beq 0f; bkpt; \
600: pop  {wrnk}
61#else  /*}{*/
62#define CHECK_BYTE  /*empty*/
63#endif  /*}*/
64
65/* "mov lr,pc; bxx ..." implements conditional subroutine call */
66#define GETBIT  add bits,bits; mov lr,pc; beq get1_n2e
67
68#define getnextb(reg) GETBIT; adc reg,reg
69#define   jnextb0     GETBIT; bcc
70#define   jnextb1     GETBIT; bcs
71
72#ifndef PURE_THUMB
73ucl_nrv2e_decompress_8: .globl ucl_nrv2e_decompress_8  @ ARM mode
74        .type ucl_nrv2e_decompress_8, %function
75/* error = (*)(char const *src, int len_src, char *dst, int *plen_dst)
76   Actual decompressed length is stored through plen_dst.
77   For SAFE mode: at call, *plen_dst must be allowed length of output buffer.
78*/
79        adr r12,1+.thumb_nrv2e_d8; bx r12  @ enter THUMB mode
80        .code 16  @ THUMB mode
81        .thumb_func
82#endif
83
84.thumb_nrv2e_d8:
85        push {r2,r3, r4,r5,r6,r7, lr}
86#define sp_DST0 0  /* stack offset of original dst */
87        add srclim,len,src  @ srclim= eof_src;
88#if 1==SAFE  /*{*/
89        ldr tmp,[r3]  @ len_dst
90        add tmp,dst
91        mov dstlim,tmp
92#endif  /*}*/
93        mov bits,#1; neg off,bits  @ off= -1 initial condition
94        lsl bits,#31  @ 1<<31: refill next time
95        mov wrnk,#5
96        lsl wrnk,#8  @ 0x500  @ nrv2e M2_MAX_OFFSET
97        b top_n2e
98
99#if 1==SAFE  /*{*/
100bad_dst_n2e:  # return value will be 2
101        add src,srclim,#1
102bad_src_n2e:  # return value will be 1
103        add src,#1
104#endif  /*}*/
105eof_n2e:
106        pop {r3,r4}  @ r3= orig_dst; r4= plen_dst
107        sub src,srclim  @ 0 if actual src length equals expected length
108        sub dst,r3  @ actual dst length
109        str dst,[r4]
110        pop {r4,r5,r6,r7 /*,pc*/}
111        pop {r1}; bx r1  @ "pop {,pc}" fails return to ARM mode on ARMv4T
112
113get1_n2e:  @ In: Carry set [from adding 0x80000000 (1<<31) to itself]
114          ldrb bits,[src]  @ zero-extend next byte
115        adc bits,bits  @ double and insert CarryIn as low bit
116          CHECK_SRC
117          add src,#1
118        lsl bits,#24  @ move to top byte, and set CarryOut from old bit 8
119        mov pc,lr  @ return, stay in current (THUMB) mode
120
121lit_n2e:
122        CHECK_SRC; ldrb tmp,[src]; add src,#1
123        CHECK_BYTE
124        CHECK_DST; strb tmp,[dst]; add dst,#1
125top_n2e:
126        jnextb1 lit_n2e
127        mov cnt,#1; b getoff_n2e
128
129off_n2e:
130        sub cnt,#1
131        getnextb(cnt)
132getoff_n2e:
133        getnextb(cnt)
134        jnextb0 off_n2e
135
136        sub tmp,cnt,#3  @ set Carry
137        mov len,#0  @ Carry unaffected
138        blo offprev_n2e  @ cnt was 2; tests Carry only
139        lsl tmp,#8
140        CHECK_SRC; ldrb off,[src]; add src,#1  @ low 7+1 bits
141        orr  off,tmp
142        mvn  off,off; beq eof_n2e  @ off= ~off
143        asr  off,#1; bcs lenlast_n2e
144        b lenmore_n2e
145
146offprev_n2e:
147        jnextb1 lenlast_n2e
148lenmore_n2e:
149        mov len,#1
150        jnextb1 lenlast_n2e
151len_n2e:
152        getnextb(len)
153        jnextb0 len_n2e
154        add len,#6-2
155        b gotlen_n2e
156
157lenlast_n2e:
158        getnextb(len)  @ 0,1,2,3
159        add len,#2
160gotlen_n2e:  @ 'cmn': add the inputs, set condition codes, discard the sum
161        cmn wrnk,off; bcs near_n2e  @ within M2_MAX_OFFSET
162        add len,#1  @ too far away, so minimum match length is 3
163near_n2e:
164#if 1==SAFE  /*{*/
165        ldr tmp,[sp,#sp_DST0]
166        sub tmp,dst
167        sub tmp,off; bhi bad_dst_n2e  @ reaching back too far
168
169        add tmp,dst,cnt
170        cmp tmp,dstlim; bhi bad_dst_n2e  @ too much output
171#endif  /*}*/
172        ldrb tmp,[dst]  @ force cacheline allocate
173copy_n2e:
174        ldrb tmp,[dst,off]
175        CHECK_BYTE
176        strb tmp,[dst]; add dst,#1
177        sub len,#1; bne copy_n2e
178        b top_n2e
179
180#ifndef PURE_THUMB
181        .size ucl_nrv2e_decompress_8, .-ucl_nrv2e_decompress_8
182#endif
183
184/*
185vi:ts=8:et:nowrap
186 */
187
188