1/* arm_nrv2b_d8.S -- ARM decompressor for NRV2B
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
32#define src  r0
33#define len  r1
34#define dst  r2
35#define tmp  r3
36#define bits r4
37#define off  r5
38/*           r6  UNUSED */
39#define wrnk r7  /* 0xd00  M2_MAX_OFFSET before "wrinkle" */
40
41/* r12 ("ip") is assumed to be a scratch register. */
42
43#define GETBIT  add bits,bits; mov lr,pc; beq get1_n2b
44
45#define getnextb(reg) GETBIT; adc reg,reg
46#define   jnextb0     GETBIT; bcc
47#define   jnextb1     GETBIT; bcs
48
49#ifndef PURE_THUMB
50ucl_nrv2b_decompress_8: .globl ucl_nrv2b_decompress_8  @ ARM mode
51        .type ucl_nrv2b_decompress_8, %function
52/* error = (*)(char const *src, int len_src, char *dst, int *plen_dst) */
53        adr r12,1+.thumb_nrv2b_d8  @ load pc-relative address
54        bx  r12  @ enter THUMB mode
55        .code 16  @ THUMB mode
56        .thumb_func
57#endif
58
59.thumb_nrv2b_d8:
60        add r1,len,src  @ r1= eof_src;
61        push {r1,r2,r3, r4,r5,r6,r7, lr}
62        mov bits,#1; neg off,bits  @ off= -1 initial condition
63        lsl bits,#31  @ 1<<31: refill next time
64        mov wrnk,#0xd
65        lsl wrnk,#8  @ 0xd00
66        b top_n2b
67
68eof_n2b:
69        pop {r1,r3,r4}  @ r1= eof_src; r3= orig_dst; r4= plen_dst
70        sub src,r1  @ 0 if actual src length equals expected length
71        sub dst,r3  @ actual dst length
72        str dst,[r4]
73        pop {r4,r5,r6,r7 /*,pc*/}
74        pop {r1}; bx r1  @ "pop {,pc}" fails return to ARM mode on ARMv4T
75
76get1_n2b:
77        ldrb bits,[src]  @ zero-extend next byte
78        adc bits,bits  @ double and insert CarryIn as low bit
79        add src,#1
80        lsl bits,#24  @ move to top byte, and set CarryOut from old bit 8
81        mov pc,lr
82
83lit_n2b:
84        ldrb tmp,[src]; add src,#1
85        strb tmp,[dst]; add dst,#1
86top_n2b:
87        jnextb1 lit_n2b
88        mov len,#1  @ the msb
89getoff_n2b:  @ ss11 len= [2..)
90        getnextb(len)
91        jnextb0 getoff_n2b
92
93        sub tmp,len,#3  @ set Carry
94        mov len,#0  @ Carry unaffected
95        blo offprev_n2b  @ ss11 returned 2
96        lsl tmp,#8
97        ldrb off,[src]; add src,#1  @ low 8 bits
98        orr  off,tmp
99        mvn  off,off; beq eof_n2b  @ off= ~off
100offprev_n2b:  @ In: 0==len
101        getnextb(len); getnextb(len); bne plus1_n2b  @ two bits; 1,2,3 ==> 2,3,4
102
103        mov len,#1  @ the msb
104getlen_n2b:  @ ss11 len= [2..)
105        getnextb(len)
106        jnextb0 getlen_n2b
107
108        add len,#2  @ [2..) ==> [4..);
109plus1_n2b:
110        add len,#1  @ 1,2,3 ==> 2,3,4; [4..) ==> [5..)
111/* 'cmn': add the inputs, set condition codes, discard the sum */
112        cmn off,wrnk; bcs near_n2b  @ within M2_MAX_OFFSET
113        add len,#1  @ too far away, so minimum match length is 3
114near_n2b:
115        ldrb tmp,[dst]  @ force cacheline allocate
116copy_n2b:
117        ldrb tmp,[dst,off]
118        strb tmp,[dst]; add dst,#1
119        sub len,#1; bne copy_n2b
120        b top_n2b
121
122#ifndef PURE_THUMB
123        .size ucl_nrv2b_decompress_8, .-ucl_nrv2b_decompress_8
124#endif
125
126/*
127vi:ts=8:et:nowrap
128 */
129
130