1 /* ppcbxx.h -- PowerPC Branch trick
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) 2004-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
33
34 /*************************************************************************
35 // filter / scan
36 **************************************************************************/
37
38 #define W_CTO 4 /* width of cto; must match stub/ppc_bxx.S */
39
F(Filter * f)40 static int F(Filter *f)
41 {
42 #ifdef U
43 // filter
44 upx_byte *b = f->buf;
45 const unsigned addvalue = f->addvalue;
46 #else
47 // scan
48 const upx_byte *b = f->buf;
49 #endif
50 const unsigned size = umin(f->buf_len, 0u - (~0u<<(32 - (6+ W_CTO))));
51 const unsigned size4 = size -4;
52
53 unsigned ic;
54 unsigned calls = 0, noncalls = 0;
55 unsigned lastnoncall = size, lastcall = 0;
56
57 // find 26-2-W_CTO bits of displacements that contain no targets
58 {
59 unsigned char buf[256];
60 unsigned short wbuf[256];
61 const size_t WW = (size_t)0 - ((~(size_t)0) << W_CTO); // ???
62 memset(wbuf, 0, sizeof(wbuf));
63 memset(buf , 0, WW);
64 memset(buf + WW, 1, 256 - WW);
65
66 for (ic = 0; ic<=size4; ic+=4) if (COND(b,ic)) {
67 unsigned const off = (int)(get_be32(b+ic)<<6) >>6;
68 if (size <= (off & (~0u<<2))+ic) {
69 buf[(~(~0u<<W_CTO)) & (off>>(26 - W_CTO))] |= 1;
70 ++wbuf[0xff&(off>>18)];
71 }
72 }
73
74 if (getcto(f, buf) < 0) {
75 #if (W_CTO != 0)
76 return -1;
77 #else
78 f->cto = 0;
79 #endif
80 }
81 }
82 const unsigned char cto8 = f->cto;
83 #ifdef U
84 const unsigned cto = (unsigned)f->cto << (24+2 - W_CTO);
85 #endif
86
87 for (ic = 0; ic<=size4; ic+=4) if (COND(b,ic)) {
88 unsigned const word = get_be32(b+ic);
89 unsigned const off = (int)(word<<6) >>6;
90 unsigned const jc = (off & (~0u<<2))+ic;
91 // try to detect 'real' calls only
92 if (jc < size) {
93 #ifdef U
94 set_be32(b+ic,(0xfc000003&word) | (jc+addvalue+cto));
95 #endif
96 calls++;
97 lastcall = ic;
98 }
99 else {
100 #if (W_CTO != 0)
101 assert((~(~0u<<W_CTO) & (word>>(24+2 - W_CTO))) != (unsigned) cto8); // this should not happen
102 #endif
103 lastnoncall = ic;
104 noncalls++;
105 }
106 }
107
108 f->calls = calls;
109 f->noncalls = noncalls;
110 f->lastcall = lastcall;
111 ACC_UNUSED(lastnoncall);
112
113 #if 0 || defined(TESTING)
114 printf("\ncalls=%d noncalls=%d text_size=%x calltrickoffset=%x\n",
115 calls,noncalls,size,cto8);
116 #endif
117 return 0;
118 }
119
120
121 /*************************************************************************
122 // unfilter
123 **************************************************************************/
124
125 #ifdef U
U(Filter * f)126 static int U(Filter *f)
127 {
128 upx_byte *b = f->buf;
129 const unsigned size4 = umin(f->buf_len - 4, 0u - (~0u<<(32 - (6+ W_CTO))));
130 const unsigned addvalue = f->addvalue;
131
132 unsigned ic;
133
134 for (ic = 0; ic<=size4; ic+=4) if (COND(b,ic)) {
135 unsigned const word = get_be32(b+ic);
136 if ((~(~0u<<W_CTO) & (word>>(24+2 - W_CTO))) == (unsigned) f->cto) {
137 unsigned const jc = word & (~(~0u<<(26 - W_CTO)) & (~0u<<2));
138 set_be32(b+ic, (0xfc000003&word)|(0x03fffffc&(jc-ic-addvalue)));
139 f->calls++;
140 f->lastcall = ic;
141 }
142 else {
143 f->noncalls++;
144 }
145 }
146 return 0;
147 }
148 #endif
149
150
151 #undef F
152 #undef U
153
154 #undef W_CTO
155
156 /* vim:set ts=4 sw=4 et: */
157