Files
upx/src/filter/ppcbxx.h
T
Markus F.X.J. Oberhumer 996ca8d17d all: welcome 2025
2025-01-17 21:18:55 +01:00

153 lines
4.6 KiB
C++

/* ppcbxx.h -- PowerPC Branch trick
This file is part of the UPX executable compressor.
Copyright (C) 1996-2025 Markus Franz Xaver Johannes Oberhumer
Copyright (C) 1996-2025 Laszlo Molnar
Copyright (C) 2004-2025 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
<markus@oberhumer.com> <ezerotven+github@gmail.com>
John F. Reiser
<jreiser@users.sourceforge.net>
*/
/*************************************************************************
// filter / scan
**************************************************************************/
#define W_CTO 4 /* width of cto; must match stub/ppc_bxx.S */
static int F(Filter *f) {
#ifdef U
// filter
byte *b = f->buf;
const unsigned addvalue = f->addvalue;
#else
// scan
const byte *b = f->buf;
#endif
const unsigned size = upx::umin(f->buf_len, 0u - (~0u << (32 - (6 + W_CTO))));
const unsigned size4 = size - 4;
unsigned ic;
unsigned calls = 0, noncalls = 0;
unsigned lastnoncall = size, lastcall = 0;
// find 26-2-W_CTO bits of displacements that contain no targets
{
unsigned char buf[256];
unsigned short wbuf[256];
const size_t WW = (size_t) 0 - ((~(size_t) 0) << W_CTO); // ???
memset(wbuf, 0, sizeof(wbuf));
memset(buf, 0, WW);
memset(buf + WW, 1, 256 - WW);
for (ic = 0; ic <= size4; ic += 4)
if (COND(b, ic)) {
unsigned const off = (int) (get_be32(b + ic) << 6) >> 6;
if (size <= (off & (~0u << 2)) + ic) {
buf[(~(~0u << W_CTO)) & (off >> (26 - W_CTO))] |= 1;
++wbuf[0xff & (off >> 18)];
}
}
if (getcto(f, buf) < 0) {
#if (W_CTO != 0)
return -1;
#else
f->cto = 0;
#endif
}
}
const unsigned char cto8 = f->cto;
#ifdef U
const unsigned cto = (unsigned) f->cto << (24 + 2 - W_CTO);
#endif
for (ic = 0; ic <= size4; ic += 4)
if (COND(b, ic)) {
unsigned const word = get_be32(b + ic);
unsigned const off = (int) (word << 6) >> 6;
unsigned const jc = (off & (~0u << 2)) + ic;
// try to detect 'real' calls only
if (jc < size) {
#ifdef U
set_be32(b + ic, (0xfc000003 & word) | (jc + addvalue + cto));
#endif
calls++;
lastcall = ic;
} else {
#if (W_CTO != 0)
assert((~(~0u << W_CTO) & (word >> (24 + 2 - W_CTO))) !=
(unsigned) cto8); // this should not happen
#endif
lastnoncall = ic;
noncalls++;
}
}
f->calls = calls;
f->noncalls = noncalls;
f->lastcall = lastcall;
ACC_UNUSED(lastnoncall);
#if 0 || defined(TESTING)
printf("\ncalls=%d noncalls=%d text_size=%x calltrickoffset=%x\n",
calls,noncalls,size,cto8);
#endif
return 0;
}
/*************************************************************************
// unfilter
**************************************************************************/
#ifdef U
static int U(Filter *f) {
byte *b = f->buf;
const unsigned size4 = upx::umin(f->buf_len - 4, 0u - (~0u << (32 - (6 + W_CTO))));
const unsigned addvalue = f->addvalue;
unsigned ic;
for (ic = 0; ic <= size4; ic += 4)
if (COND(b, ic)) {
unsigned const word = get_be32(b + ic);
if ((~(~0u << W_CTO) & (word >> (24 + 2 - W_CTO))) == (unsigned) f->cto) {
unsigned const jc = word & (~(~0u << (26 - W_CTO)) & (~0u << 2));
set_be32(b + ic, (0xfc000003 & word) | (0x03fffffc & (jc - ic - addvalue)));
f->calls++;
f->lastcall = ic;
} else {
f->noncalls++;
}
}
return 0;
}
#endif
#undef F
#undef U
#undef W_CTO
/* vim:set ts=4 sw=4 et: */