1
0
mirror of https://github.com/upx/upx synced 2025-09-28 19:06:07 +08:00

Refactored compressWithFilters().

This commit is contained in:
Markus F.X.J. Oberhumer 2006-12-06 07:27:23 +01:00
parent 6e52364bcb
commit 8875470b37
22 changed files with 311 additions and 277 deletions

View File

@ -135,7 +135,7 @@ int upx_ucl_compress ( const upx_bytep src, unsigned src_len,
// prepare bit-buffer settings
cconf.bb_endian = 0;
cconf.bb_size = 0;
if (method >= M_NRV2B_LE32 && method <= M_CL1B_LE16)
if (method >= M_NRV2B_LE32 && method <= M_NRV2E_LE16)
{
static const unsigned char sizes[3] = {32, 8, 16};
cconf.bb_size = sizes[(method - M_NRV2B_LE32) % 3];

View File

@ -187,34 +187,6 @@
#define upx_byte unsigned char
#define upx_bytep upx_byte *
#define UPX_E_OK (0)
#define UPX_E_ERROR (-1)
#define UPX_E_OUT_OF_MEMORY (-2)
#define UPX_E_NOT_COMPRESSIBLE (-3)
#define UPX_E_INPUT_OVERRUN (-4)
#define UPX_E_OUTPUT_OVERRUN (-5)
#define UPX_E_LOOKBEHIND_OVERRUN (-6)
#define UPX_E_EOF_NOT_FOUND (-7)
#define UPX_E_INPUT_NOT_CONSUMED (-8)
#define UPX_E_NOT_YET_IMPLEMENTED (-9)
#define UPX_E_INVALID_ARGUMENT (-10)
struct upx_callback_t;
#define upx_callback_p upx_callback_t *
typedef void* (__acc_cdecl *upx_alloc_func_t)
(upx_callback_p self, unsigned items, unsigned size);
typedef void (__acc_cdecl *upx_free_func_t)
(upx_callback_p self, void* ptr);
typedef void (__acc_cdecl *upx_progress_func_t)
(upx_callback_p, unsigned, unsigned);
struct upx_callback_t
{
upx_progress_func_t nprogress;
void *user;
void reset() { memset(this, 0, sizeof(*this)); }
};
/*************************************************************************
@ -414,31 +386,23 @@ private:
#define EXIT_INTERNAL 1
// compression methods - DO NOT CHANGE
#define M_SKIP (-2)
#define M_END (-1)
#define M_ULTRA_BRUTE (-3)
#define M_NRV2B_LE32 2
#define M_NRV2B_8 3
#define M_NRV2B_LE16 4
#define M_NRV2D_LE32 5
#define M_NRV2D_8 6
#define M_NRV2D_LE16 7
#define M_NRV2E_LE32 8
#define M_NRV2E_8 9
#define M_NRV2E_LE16 10
#define M_CL1B_LE32 11
#define M_CL1B_8 12
#define M_CL1B_LE16 13
#define M_LZMA 14
#define M_DEFLATE 15 /* zlib */
// magic constants for patching
#define UPX_MAGIC_LE32 0x21585055 /* "UPX!" */
#define UPX_MAGIC2_LE32 0xD5D0D8A1
#define M_IS_NRV2B(x) ((x) >= M_NRV2B_LE32 && (x) <= M_NRV2B_LE16)
#define M_IS_NRV2D(x) ((x) >= M_NRV2D_LE32 && (x) <= M_NRV2D_LE16)
#define M_IS_NRV2E(x) ((x) >= M_NRV2E_LE32 && (x) <= M_NRV2E_LE16)
#define M_IS_CL1B(x) ((x) >= M_CL1B_LE32 && (x) <= M_CL1B_LE16)
#define M_IS_LZMA(x) (((x) & 255) == M_LZMA)
#define M_IS_DEFLATE(x) ((x) == M_DEFLATE)
// upx_compress() error codes
#define UPX_E_OK (0)
#define UPX_E_ERROR (-1)
#define UPX_E_OUT_OF_MEMORY (-2)
#define UPX_E_NOT_COMPRESSIBLE (-3)
#define UPX_E_INPUT_OVERRUN (-4)
#define UPX_E_OUTPUT_OVERRUN (-5)
#define UPX_E_LOOKBEHIND_OVERRUN (-6)
#define UPX_E_EOF_NOT_FOUND (-7)
#define UPX_E_INPUT_NOT_CONSUMED (-8)
#define UPX_E_NOT_YET_IMPLEMENTED (-9)
#define UPX_E_INVALID_ARGUMENT (-10)
// Executable formats. Note: big endian types are >= 128.
@ -478,8 +442,61 @@ private:
#define UPX_F_LINUX_ELF32_ARMBE 133
#define UPX_MAGIC_LE32 0x21585055 /* "UPX!" */
#define UPX_MAGIC2_LE32 0xD5D0D8A1
// compression methods - DO NOT CHANGE
#define M_END (-1)
#define M_SKIP (-2)
#define M_ULTRA_BRUTE (-3)
#define M_NRV2B_LE32 2
#define M_NRV2B_8 3
#define M_NRV2B_LE16 4
#define M_NRV2D_LE32 5
#define M_NRV2D_8 6
#define M_NRV2D_LE16 7
#define M_NRV2E_LE32 8
#define M_NRV2E_8 9
#define M_NRV2E_LE16 10
//#define M_CL1B_LE32 11
//#define M_CL1B_8 12
//#define M_CL1B_LE16 13
#define M_LZMA 14
#define M_DEFLATE 15 /* zlib */
#define M_IS_NRV2B(x) ((x) >= M_NRV2B_LE32 && (x) <= M_NRV2B_LE16)
#define M_IS_NRV2D(x) ((x) >= M_NRV2D_LE32 && (x) <= M_NRV2D_LE16)
#define M_IS_NRV2E(x) ((x) >= M_NRV2E_LE32 && (x) <= M_NRV2E_LE16)
//#define M_IS_CL1B(x) ((x) >= M_CL1B_LE32 && (x) <= M_CL1B_LE16)
#define M_IS_LZMA(x) (((x) & 255) == M_LZMA)
#define M_IS_DEFLATE(x) ((x) == M_DEFLATE)
// filters - DO NOT CHANGE
#define FT_END (-1)
#define FT_SKIP (-2)
#define FT_ULTRA_BRUTE (-3)
/*************************************************************************
// compression - callback_t
**************************************************************************/
struct upx_callback_t;
#define upx_callback_p upx_callback_t *
#if 0
typedef void* (__acc_cdecl *upx_alloc_func_t)
(upx_callback_p self, unsigned items, unsigned size);
typedef void (__acc_cdecl *upx_free_func_t)
(upx_callback_p self, void* ptr);
#endif
typedef void (__acc_cdecl *upx_progress_func_t)
(upx_callback_p, unsigned, unsigned);
struct upx_callback_t
{
upx_progress_func_t nprogress;
void *user;
void reset() { memset(this, 0, sizeof(*this)); }
};
/*************************************************************************
@ -588,6 +605,8 @@ struct upx_compress_config_t
void reset() { conf_lzma.reset(); conf_ucl.reset(); conf_zlib.reset(); }
};
#define NULL_cconf ((upx_compress_config_t *) NULL)
/*************************************************************************
// compression - result_t

View File

@ -61,10 +61,10 @@ const FilterImp::FilterEntry *FilterImp::getFilter(int id)
memset(filter_map, 0xff, sizeof(filter_map));
for (int i = 0; i < n_filters; i++)
{
int fid = filters[i].id;
assert(fid >= 0 && fid <= 255);
assert(filter_map[fid] == 0xff);
filter_map[fid] = (unsigned char) i;
int filter_id = filters[i].id;
assert(filter_id >= 0 && filter_id <= 255);
assert(filter_map[filter_id] == 0xff);
filter_map[filter_id] = (unsigned char) i;
}
done = true;
}
@ -85,6 +85,20 @@ bool Filter::isValidFilter(int filter_id)
return fe != NULL;
}
bool Filter::isValidFilter(int filter_id, const int *allowed_filters)
{
if (!isValidFilter(filter_id))
return false;
if (filter_id == 0)
return true;
if (allowed_filters == NULL)
return false;
while (*allowed_filters != FT_END)
if (*allowed_filters++ == filter_id)
return true;
return false;
}
/*************************************************************************
// high level API

View File

@ -62,6 +62,7 @@ public:
bool scan(const upx_byte *buf, unsigned buf_len);
static bool isValidFilter(int filter_id);
static bool isValidFilter(int filter_id, const int *allowed_filters);
public:
// Will be set by each call to filter()/unfilter().

View File

@ -115,19 +115,18 @@ PackArmPe::~PackArmPe()
const int *PackArmPe::getCompressionMethods(int method, int level) const
{
static const int m_nrv2b[] = { M_NRV2B_8, M_NRV2E_8, M_LZMA, M_END };
static const int m_nrv2e[] = { M_NRV2E_8, M_NRV2B_8, M_LZMA, M_END };
static const int m_all[] = { M_NRV2B_8, M_NRV2E_8, M_LZMA, M_END };
static const int m_lzma[] = { M_LZMA, M_END };
static const int m_nrv2b[] = { M_NRV2B_8, M_END };
static const int m_nrv2e[] = { M_NRV2E_8, M_END };
if (!use_thumb_stub)
return getDefaultCompressionMethods_8(method, level);
if (M_IS_NRV2B(method))
return m_nrv2b;
if (M_IS_NRV2E(method))
return m_nrv2e;
if (M_IS_LZMA(method))
return m_lzma;
if (method == -1) return m_all;
if (M_IS_LZMA(method)) return m_lzma;
if (M_IS_NRV2B(method)) return m_nrv2b;
if (M_IS_NRV2E(method)) return m_nrv2e;
return m_nrv2e;
}
@ -698,20 +697,20 @@ void PackArmPe::pack(OutputFile *fo)
ft.buf_len = ih.codesize;
ft.addvalue = ih.codebase - rvamin;
// compress
int strategy = allow_filter ? 0 : -3;
int filter_strategy = allow_filter ? 0 : -3;
// disable filters for files with broken headers
if (ih.codebase + ih.codesize > ph.u_len)
{
ft.buf_len = 1;
strategy = -3;
filter_strategy = -3;
}
// limit stack size needed for runtime decompression
upx_compress_config_t cconf; cconf.reset();
cconf.conf_lzma.max_num_probs = 1846 + (768 << 4); // ushort: ~28KB stack
compressWithFilters(&ft, 2048, strategy,
NULL, &cconf, ih.codebase, rvamin);
compressWithFilters(&ft, 2048, &cconf, filter_strategy,
ih.codebase, rvamin);
// info: see buildLoader()
newvsize = (ph.u_len + rvamin + ph.overlap_overhead + oam1) &~ oam1;
/*

View File

@ -45,16 +45,11 @@ static const
const int *PackCom::getCompressionMethods(int method, int level) const
{
static const int m_nrv2b[] = { M_NRV2B_LE16, -1 };
if (M_IS_NRV2B(method))
return m_nrv2b;
static const int m_nrv2b[] = { M_NRV2B_LE16, M_END };
#if 0
// NOT IMPLEMENTED
static const int m_nrv2d[] = { M_NRV2D_LE16, -1 };
if (M_IS_NRV2D(method))
return m_nrv2d;
static const int m_nrv2d[] = { M_NRV2D_LE16, M_END };
#endif
UNUSED(level);
UNUSED(method); UNUSED(level);
return m_nrv2b;
}
@ -202,7 +197,7 @@ void PackCom::pack(OutputFile *fo)
ft.addvalue = getCallTrickOffset();
// compress
const unsigned overlap_range = ph.u_len < 0xFE00 - ft.addvalue ? 32 : 0;
compressWithFilters(&ft, overlap_range);
compressWithFilters(&ft, overlap_range, NULL_cconf);
const int lsize = getLoaderSize();
MemBuffer loader(lsize);

View File

@ -325,7 +325,7 @@ void PackDjgpp2::pack(OutputFile *fo)
upx_compress_config_t cconf; cconf.reset();
// limit stack size needed for runtime decompression
cconf.conf_lzma.max_num_probs = 1846 + (768 << 4); // ushort: ~28KB stack
compressWithFilters(&ft, 512, 0, NULL, &cconf);
compressWithFilters(&ft, 512, &cconf);
// patch coff header #2
const unsigned lsize = getLoaderSize();

View File

@ -112,7 +112,7 @@ void PackElks8086::pack(OutputFile *fo)
ft.buf_len = ph.u_len;
ft.addvalue = kernel_entry;
// compress
compressWithFilters(&ft, overlap_range);
compressWithFilters(&ft, overlap_range, NULL_cconf);
const unsigned lsize = getLoaderSize();
MemBuffer loader(lsize);

View File

@ -58,17 +58,16 @@ PackExe::PackExe(InputFile *f) :
const int *PackExe::getCompressionMethods(int method, int level) const
{
static const int m_nrv2b[] = { M_NRV2B_8, M_NRV2D_8, M_NRV2E_8, M_END };
static const int m_nrv2d[] = { M_NRV2D_8, M_NRV2B_8, M_NRV2E_8, M_END };
static const int m_nrv2e[] = { M_NRV2E_8, M_NRV2B_8, M_NRV2D_8, M_END };
static const int m_all[] = { M_NRV2B_8, M_NRV2D_8, M_NRV2E_8, M_END };
static const int m_nrv2b[] = { M_NRV2B_8, M_END };
static const int m_nrv2d[] = { M_NRV2D_8, M_END };
static const int m_nrv2e[] = { M_NRV2E_8, M_END };
if (method == -1) return m_all;
if (M_IS_NRV2B(method)) return m_nrv2b;
if (M_IS_NRV2D(method)) return m_nrv2d;
if (M_IS_NRV2E(method)) return m_nrv2e;
bool small = ih_imagesize <= 256*1024;
if (M_IS_NRV2B(method))
return m_nrv2b;
if (M_IS_NRV2D(method))
return m_nrv2d;
if (M_IS_NRV2E(method))
return m_nrv2e;
if (level == 1 || small)
return m_nrv2b;
return m_nrv2e;
@ -430,7 +429,7 @@ void PackExe::pack(OutputFile *fo)
// compress (max_match = 8192)
upx_compress_config_t cconf; cconf.reset();
cconf.conf_ucl.max_match = MAXMATCH;
compressWithFilters(&ft, 32, 0, NULL, &cconf);
compressWithFilters(&ft, 32, &cconf);
if (ph.max_run_found + ph.max_match_found > 0x8000)
throwCantPack("decompressor limit exceeded, send a bugreport");

View File

@ -164,9 +164,9 @@ void PackLinuxElf32x86interp::pack3(OutputFile *fo, Filter &/*ft*/)
ph.method = M_NRV2E_LE32; addLoader(getDecompressorSections(), NULL);
addLoader("LXPTI090", NULL);
addLoader("LXPTI043", NULL);
ph.method = M_CL1B_LE32; addLoader(getDecompressorSections(), NULL);
addLoader("LXPTI090", NULL);
//addLoader("LXPTI043", NULL);
//ph.method = M_CL1B_LE32; addLoader(getDecompressorSections(), NULL);
//addLoader("LXPTI090", NULL);
addLoader("LXPTI091", NULL);

View File

@ -53,7 +53,7 @@ PackMachPPC32::~PackMachPPC32()
const int *PackMachPPC32::getCompressionMethods(int /*method*/, int /*level*/) const
{
// There really is no LE bias in M_NRV2E_LE32.
static const int m_nrv2e[] = { M_NRV2E_LE32, -1 };
static const int m_nrv2e[] = { M_NRV2E_LE32, M_END };
return m_nrv2e;
}

View File

@ -491,7 +491,7 @@ void PackPs1::pack(OutputFile *fo)
upx_compress_config_t cconf; cconf.reset();
cconf.conf_ucl.max_match = 65535;
cconf.conf_lzma.max_num_probs = 1846 + (768 << 4); // ushort: ~28KB stack
compressWithFilters(&ft, sa_cnt, 0, NULL, &cconf);
compressWithFilters(&ft, sa_cnt, &cconf);
if (overlap)
{

View File

@ -249,7 +249,10 @@ void PackTmt::pack(OutputFile *fo)
Filter ft(ph.level);
ft.buf_len = usize;
// compress
compressWithFilters(&ft, 512);
upx_compress_config_t cconf; cconf.reset();
// limit stack size needed for runtime decompression
cconf.conf_lzma.max_num_probs = 1846 + (768 << 4); // ushort: ~28KB stack
compressWithFilters(&ft, 512, &cconf);
const unsigned lsize = getLoaderSize();
const unsigned s_point = getLoaderSection("TMTMAIN1");

View File

@ -508,7 +508,7 @@ void PackTos::pack(OutputFile *fo)
upx_compress_config_t cconf; cconf.reset();
cconf.conf_ucl.max_match = 65535;
cconf.conf_lzma.max_num_probs = 1846 + (768 << 4); // ushort: ~28KB stack
compressWithFilters(&ft, 512, 0, NULL, &cconf);
compressWithFilters(&ft, 512, &cconf);
//
// multipass buildLoader()

View File

@ -125,8 +125,8 @@ int PackUnix::getStrategy(Filter &/*ft*/)
// Called just before reading and compressing each block.
// Might want to adjust blocksize, etc.
// If user specified the filter, then use it (-2==strategy).
// Else try the first two filters, and pick the better (2==strategy).
// If user specified the filter, then use it (-2==filter_strategy).
// Else try the first two filters, and pick the better (2==filter_strategy).
return (opt->no_filter ? -3 : ((opt->filter > 0) ? -2 : 2));
}
@ -151,9 +151,9 @@ void PackUnix::pack2(OutputFile *fo, Filter &ft)
// which assumes it has free choice on each call [block].
// And if the choices aren't the same on each block,
// then un-filtering will give incorrect results.
int strategy = getStrategy(ft);
int filter_strategy = getStrategy(ft);
if (file_size > (off_t)blocksize)
strategy = -3; // no filters
filter_strategy = -3; // no filters
int l = fi->readx(ibuf, UPX_MIN(blocksize, remaining));
remaining -= l;
@ -170,7 +170,7 @@ void PackUnix::pack2(OutputFile *fo, Filter &ft)
// that is, AFTER filtering. We want BEFORE filtering,
// so that decompression checks the end-to-end checksum.
unsigned const end_u_adler = upx_adler32(ibuf, ph.u_len, ph.u_adler);
compressWithFilters(&ft, OVERHEAD, strategy);
compressWithFilters(&ft, OVERHEAD, NULL_cconf, filter_strategy);
if (ph.c_len < ph.u_len) {
ph.overlap_overhead = OVERHEAD;
@ -318,7 +318,7 @@ void PackUnix::packExtent(
}
fi->seek(x.offset, SEEK_SET);
for (off_t rest = x.size; 0 != rest; ) {
int const strategy = getStrategy(*ft);
int const filter_strategy = getStrategy(*ft);
int l = fi->readx(ibuf, UPX_MIN(rest, (off_t)blocksize));
if (l == 0) {
break;
@ -345,9 +345,8 @@ void PackUnix::packExtent(
ft->id = 0;
ft->cto = 0;
compressWithFilters(ft, OVERHEAD, strategy,
NULL, NULL, 0, 0, // those 4 args are the defaults
hdr_ibuf, hdr_u_len);
compressWithFilters(ft, OVERHEAD, NULL_cconf, filter_strategy,
0, 0, hdr_ibuf, hdr_u_len);
}
else {
(void) compress(ibuf, obuf); // ignore return value

View File

@ -78,8 +78,8 @@ int PackVmlinuxI386::getStrategy(Filter &/*ft*/)
// Called just before reading and compressing each block.
// Might want to adjust blocksize, etc.
// If user specified the filter, then use it (-2==strategy).
// Else try the first two filters, and pick the better (2==strategy).
// If user specified the filter, then use it (-2==filter_strategy).
// Else try the first two filters, and pick the better (2==filter_strategy).
return (opt->no_filter ? -3 : ((opt->filter > 0) ? -2 : 2));
}
@ -309,7 +309,7 @@ void PackVmlinuxI386::pack(OutputFile *fo)
upx_compress_config_t cconf; cconf.reset();
// limit stack size needed for runtime decompression
cconf.conf_lzma.max_num_probs = 1846 + (768 << 4); // ushort: ~28KB stack
compressWithFilters(&ft, 512, getStrategy(ft), getFilters(), &cconf);
compressWithFilters(&ft, 512, &cconf, getStrategy(ft));
const unsigned lsize = getLoaderSize();

View File

@ -316,7 +316,7 @@ void PackVmlinuzI386::pack(OutputFile *fo)
upx_compress_config_t cconf; cconf.reset();
// limit stack size needed for runtime decompression
cconf.conf_lzma.max_num_probs = 1846 + (768 << 4); // ushort: ~28KB stack
compressWithFilters(&ft, 512, 0, NULL, &cconf);
compressWithFilters(&ft, 512, &cconf);
const unsigned lsize = getLoaderSize();
@ -401,7 +401,7 @@ void PackBvmlinuzI386::pack(OutputFile *fo)
upx_compress_config_t cconf; cconf.reset();
// limit stack size needed for runtime decompression
cconf.conf_lzma.max_num_probs = 1846 + (768 << 4); // ushort: ~28KB stack
compressWithFilters(&ft, 512, 0, NULL, &cconf);
compressWithFilters(&ft, 512, &cconf);
// align everything to dword boundary - it is easier to handle
unsigned c_len = ph.c_len;

View File

@ -794,17 +794,17 @@ void PackW32Pe::pack(OutputFile *fo)
ft.buf_len = ih.codesize;
ft.addvalue = ih.codebase - rvamin;
// compress
int strategy = allow_filter ? 0 : -3;
int filter_strategy = allow_filter ? 0 : -3;
// disable filters for files with broken headers
if (ih.codebase + ih.codesize > ph.u_len)
{
ft.buf_len = 1;
strategy = -3;
filter_strategy = -3;
}
compressWithFilters(&ft, 2048, strategy,
NULL, NULL, ih.codebase, rvamin);
compressWithFilters(&ft, 2048, NULL_cconf, filter_strategy,
ih.codebase, rvamin);
// info: see buildLoader()
newvsize = (ph.u_len + rvamin + ph.overlap_overhead + oam1) &~ oam1;
if (tlsindex && ((newvsize - ph.c_len - 1024 + oam1) &~ oam1) > tlsindex + 4)

View File

@ -1142,7 +1142,7 @@ void Packer::relocateLoader()
// - ibuf[] is restored to the original unfiltered version
// - obuf[] contains the best compressed version
//
// strategy:
// filter_strategy:
// n: try the first N filters, use best one
// -1: try all filters, use first working one
// -2: try only the opt->filter filter
@ -1172,19 +1172,104 @@ void Packer::relocateLoader()
// is OK because of the simplicity of not having two output arrays.
**************************************************************************/
static int prepareMethods(int *methods, int ph_method, const int *all_methods)
{
int nmethods = 0;
if (!opt->all_methods || all_methods == NULL)
{
methods[nmethods++] = ph_method;
return nmethods;
}
for (int mm = 0; all_methods[mm] != M_END; ++mm)
{
int method = all_methods[mm];
if (method == M_ULTRA_BRUTE && !opt->ultra_brute)
break;
if (method == M_SKIP || method == M_ULTRA_BRUTE)
continue;
if (opt->all_methods && !opt->all_methods_use_lzma && M_IS_LZMA(method))
continue;
// use this method
assert(Packer::isValidCompressionMethod(method));
methods[nmethods++] = method;
}
return nmethods;
}
static int prepareFilters(int *filters, int &filter_strategy,
const int *all_filters)
{
int nfilters = 0;
// setup filter filter_strategy
if (filter_strategy == 0)
{
if (opt->all_filters)
// choose best from all available filters
filter_strategy = INT_MAX;
else if (opt->filter >= 0 && Filter::isValidFilter(opt->filter, all_filters))
// try opt->filter
filter_strategy = -2;
else
// try the first working filter
filter_strategy = -1;
}
assert(filter_strategy != 0);
if (filter_strategy == -3)
goto done;
if (filter_strategy == -2)
{
if (opt->filter >= 0 && Filter::isValidFilter(opt->filter, all_filters))
{
filters[nfilters++] = opt->filter;
goto done;
}
filter_strategy = -1;
}
assert(filter_strategy >= -1);
const int *filter_list;
filter_list = all_filters;
while (filter_list && *filter_list != FT_END)
{
int filter_id = *filter_list++;
if (filter_id == FT_ULTRA_BRUTE && !opt->ultra_brute)
break;
if (filter_id == FT_SKIP || filter_id == FT_ULTRA_BRUTE)
continue;
if (filter_id == 0)
continue;
// use this filter
assert(Filter::isValidFilter(filter_id));
filters[nfilters++] = filter_id;
if (filter_strategy >= 0 && nfilters >= filter_strategy)
break;
}
done:
// filter_strategy now only means "stop after first successful filter"
filter_strategy = (filter_strategy < 0) ? -1 : 0;
// make sure that we have a "no filter" fallback
for (int i = 0; i < nfilters; i++)
if (filters[i] == 0)
return nfilters;
filters[nfilters++] = 0;
return nfilters;
}
void Packer::compressWithFilters(Filter *parm_ft,
const unsigned overlap_range,
int strategy, const int *parm_filters,
const upx_compress_config_t *cconf,
int filter_strategy,
unsigned filter_off, unsigned compress_buf_off,
unsigned char *hdr_buf,
unsigned hdr_u_len)
const upx_bytep hdr_buf, unsigned hdr_u_len)
{
const int *f;
//
// struct copies
const PackHeader orig_ph = this->ph;
PackHeader best_ph = this->ph;
//
const Filter orig_ft = *parm_ft;
Filter best_ft = *parm_ft;
//
@ -1201,109 +1286,42 @@ void Packer::compressWithFilters(Filter *parm_ft,
assert(orig_ft.id == 0);
assert(filter_off + filter_len <= compress_buf_off + compress_buf_len);
// setup filter strategy
if (strategy == 0)
{
if (opt->all_filters)
// choose best from all available filters
strategy = INT_MAX;
else if (opt->filter >= 0 && isValidFilter(opt->filter))
// try opt->filter
strategy = -2;
else
// try the first working filter
strategy = -1;
}
assert(strategy != 0);
// prepare methods and filters
int methods[256];
int nmethods = prepareMethods(methods, ph.method, getCompressionMethods(-1, ph.level));
assert(nmethods > 0); assert(nmethods < 256);
int filters[256];
int nfilters = prepareFilters(filters, filter_strategy, getFilters());
assert(nfilters > 0); assert(nfilters < 256);
#if 1
printf("compressWithFilters: m(%d):", nmethods);
for (int i = 0; i < nmethods; i++) printf(" %d", methods[i]);
printf(" f(%d):", nfilters);
for (int i = 0; i < nfilters; i++) printf(" %d", filters[i]);
printf("\n");
#endif
// setup raw_filters
int tmp_filters[] = { 0, -1 };
const int *raw_filters = NULL;
if (strategy == -3)
raw_filters = tmp_filters;
else if (strategy == -2 && opt->filter >= 0)
{
tmp_filters[0] = opt->filter;
raw_filters = tmp_filters;
}
// update total_passes; previous (ui_total_passes > 0) means incremental
if (uip->ui_total_passes > 0)
uip->ui_total_passes -= 1;
if (filter_strategy < 0)
uip->ui_total_passes += nmethods;
else
{
raw_filters = parm_filters;
if (raw_filters == NULL)
raw_filters = getFilters();
if (raw_filters == NULL)
raw_filters = tmp_filters;
}
// first pass - count number of filters
int raw_nfilters = 0;
for (f = raw_filters; *f >= 0; f++)
{
assert(isValidFilter(*f));
raw_nfilters++;
}
// copy filters, add a 0
int nfilters = 0;
bool zero_seen = false;
Array(int, filters, raw_nfilters + 2);
for (f = raw_filters; *f >= 0; f++)
{
if (*f == 0)
zero_seen = true;
filters[nfilters++] = *f;
if (nfilters == strategy)
break;
}
if (!zero_seen)
filters[nfilters++] = 0;
filters[nfilters] = -1;
// methods
int tmp_methods[] = { ph.method, M_END };
const int *methods = NULL;
if (opt->all_methods)
methods = getCompressionMethods(-1, ph.level);
if (methods == NULL)
methods = tmp_methods;
int nmethods = 0;
for (int mm = 0; methods[mm] != M_END; ++mm)
{
if (methods[mm] == M_ULTRA_BRUTE && !opt->ultra_brute)
break;
if (methods[mm] == M_SKIP || methods[mm] == M_ULTRA_BRUTE)
continue;
if (opt->all_methods && !opt->all_methods_use_lzma && M_IS_LZMA(methods[mm]))
continue;
assert(isValidCompressionMethod(methods[mm]));
nmethods++;
}
assert(nmethods > 0);
// update total_passes; previous (0 < ui_total_passes) means incremental
if (strategy < 0)
uip->ui_total_passes += 1 * nmethods - (0 < uip->ui_total_passes);
else
uip->ui_total_passes += nfilters * nmethods - (0 < uip->ui_total_passes);
uip->ui_total_passes += nfilters * nmethods;
// Working buffer for compressed data. Don't waste memory.
MemBuffer *otemp = &obuf;
MemBuffer otemp_buf;
// compress
int nfilters_success = 0;
for (int mm = 0; methods[mm] != M_END; ++mm) // for all methods
// compress using all methods/filters
int nfilters_success_total = 0;
for (int mm = 0; mm < nmethods; mm++) // for all methods
{
if (methods[mm] == M_ULTRA_BRUTE && !opt->ultra_brute)
break;
if (methods[mm] == M_SKIP || methods[mm] == M_ULTRA_BRUTE)
continue;
if (opt->all_methods && !opt->all_methods_use_lzma && M_IS_LZMA(methods[mm]))
continue;
assert(isValidCompressionMethod(methods[mm]));
unsigned hdr_c_len = 0;
if (hdr_buf && hdr_u_len)
{
if (nfilters_success != 0 && otemp == &obuf)
if (nfilters_success_total != 0 && otemp == &obuf)
{
// do not overwrite obuf
otemp_buf.allocForCompression(compress_buf_len);
@ -1316,21 +1334,22 @@ void Packer::compressWithFilters(Filter *parm_ft,
if (hdr_c_len >= hdr_u_len)
throwInternalError("header compression size increase");
}
for (int i = 0; i < nfilters; i++) // for all filters
int nfilters_success_mm = 0;
for (int ff = 0; ff < nfilters; ff++) // for all filters
{
assert(isValidFilter(filters[ff]));
ibuf.checkState();
obuf.checkState();
// get fresh packheader
ph = orig_ph;
ph.method = methods[mm];
ph.filter = filters[i];
ph.filter = filters[ff];
ph.overlap_overhead = 0;
// get fresh filter
Filter ft = orig_ft;
ft.init(ph.filter, orig_ft.addvalue);
// filter
optimizeFilter(&ft, ibuf + filter_off, filter_len);
bool success = ft.filter(ibuf + filter_off, filter_len);
if (ft.id != 0 && ft.calls == 0)
{
@ -1340,9 +1359,9 @@ void Packer::compressWithFilters(Filter *parm_ft,
if (!success)
{
// filter failed or was useless
if (strategy > 0)
if (filter_strategy >= 0)
{
// adjust passes
// adjust ui passes
if (uip->ui_pass >= 0)
uip->ui_pass++;
}
@ -1353,12 +1372,13 @@ void Packer::compressWithFilters(Filter *parm_ft,
printf("filter: id 0x%02x size %6d, calls %5d/%5d/%3d/%5d/%5d, cto 0x%02x\n",
ft.id, ft.buf_len, ft.calls, ft.noncalls, ft.wrongcalls, ft.firstcall, ft.lastcall, ft.cto);
#endif
if (nfilters_success != 0 && otemp == &obuf)
if (nfilters_success_total != 0 && otemp == &obuf)
{
otemp_buf.allocForCompression(compress_buf_len);
otemp = &otemp_buf;
}
nfilters_success++;
nfilters_success_total++;
nfilters_success_mm++;
ph.filter_cto = ft.cto;
ph.n_mru = ft.n_mru;
// compress
@ -1413,13 +1433,14 @@ void Packer::compressWithFilters(Filter *parm_ft,
obuf.checkState();
otemp->checkState();
//
if (strategy < 0)
if (filter_strategy < 0)
break;
}
assert(nfilters_success_mm > 0);
}
// postconditions 1)
assert(nfilters_success > 0);
assert(nfilters_success_total > 0);
assert(best_ph.u_len == orig_ph.u_len);
assert(best_ph.filter == best_ft.id);
assert(best_ph.filter_cto == best_ft.cto);

View File

@ -180,12 +180,11 @@ protected:
// high-level compression drivers
void compressWithFilters(Filter *ft,
const unsigned overlap_range,
int strategy = 0,
const int *filters = NULL,
const upx_compress_config_t *cconf = NULL,
const upx_compress_config_t *cconf,
int filter_strategy = 0,
unsigned filter_buf_off = 0,
unsigned compress_buf_off = 0,
unsigned char *header_buffer = 0,
const upx_bytep header_buffer = NULL,
unsigned header_length = 0);
// util for verifying overlapping decompresion

View File

@ -53,25 +53,21 @@ const int *Packer::getDefaultCompressionMethods_8(int method, int level, int sma
{
#define M_LZMA_003 (M_LZMA | 0x00300)
#define M_LZMA_407 (M_LZMA | 0x40700)
static const int m_nrv2b[] = { M_NRV2B_8, M_NRV2D_8, M_NRV2E_8, M_LZMA, M_ULTRA_BRUTE, M_LZMA_003, M_LZMA_407, M_END };
static const int m_nrv2d[] = { M_NRV2D_8, M_NRV2B_8, M_NRV2E_8, M_LZMA, M_ULTRA_BRUTE, M_LZMA_003, M_LZMA_407, M_END };
static const int m_nrv2e[] = { M_NRV2E_8, M_NRV2B_8, M_NRV2D_8, M_LZMA, M_ULTRA_BRUTE, M_LZMA_003, M_LZMA_407, M_END };
static const int m_cl1b[] = { M_CL1B_8, M_END };
static const int m_all[] = { M_NRV2B_8, M_NRV2D_8, M_NRV2E_8, M_LZMA, M_ULTRA_BRUTE, M_LZMA_003, M_LZMA_407, M_END };
//static const int m_cl1b[] = { M_CL1B_8, M_END };
static const int m_lzma[] = { M_LZMA, M_END };
static const int m_nrv2b[] = { M_NRV2B_8, M_END };
static const int m_nrv2d[] = { M_NRV2D_8, M_END };
static const int m_nrv2e[] = { M_NRV2E_8, M_END };
if (method == -1) return m_all;
//if (M_IS_CL1B(method)) return m_cl1b;
if (M_IS_LZMA(method)) return m_lzma;
if (M_IS_NRV2B(method)) return m_nrv2b;
if (M_IS_NRV2D(method)) return m_nrv2d;
if (M_IS_NRV2E(method)) return m_nrv2e;
if (small < 0)
small = file_size <= 512*1024;
if (M_IS_NRV2B(method))
return m_nrv2b;
if (M_IS_NRV2D(method))
return m_nrv2d;
if (M_IS_NRV2E(method))
return m_nrv2e;
if (M_IS_CL1B(method))
return m_cl1b;
if (M_IS_LZMA(method))
return m_lzma;
assert(method == -1); // --all-methods
if (level == 1 || small)
return m_nrv2b;
return m_nrv2e;
@ -80,25 +76,21 @@ const int *Packer::getDefaultCompressionMethods_8(int method, int level, int sma
const int *Packer::getDefaultCompressionMethods_le32(int method, int level, int small) const
{
static const int m_nrv2b[] = { M_NRV2B_LE32, M_NRV2D_LE32, M_NRV2E_LE32, M_LZMA, M_ULTRA_BRUTE, M_LZMA_003, M_LZMA_407, M_END };
static const int m_nrv2d[] = { M_NRV2D_LE32, M_NRV2B_LE32, M_NRV2E_LE32, M_LZMA, M_ULTRA_BRUTE, M_LZMA_003, M_LZMA_407, M_END };
static const int m_nrv2e[] = { M_NRV2E_LE32, M_NRV2B_LE32, M_NRV2D_LE32, M_LZMA, M_ULTRA_BRUTE, M_LZMA_003, M_LZMA_407, M_END };
static const int m_cl1b[] = { M_CL1B_LE32, M_END };
static const int m_all[] = { M_NRV2B_LE32, M_NRV2D_LE32, M_NRV2E_LE32, M_LZMA, M_ULTRA_BRUTE, M_LZMA_003, M_LZMA_407, M_END };
//static const int m_cl1b[] = { M_CL1B_LE32, M_END };
static const int m_lzma[] = { M_LZMA, M_END };
static const int m_nrv2b[] = { M_NRV2B_LE32, M_END };
static const int m_nrv2d[] = { M_NRV2D_LE32, M_END };
static const int m_nrv2e[] = { M_NRV2E_LE32, M_END };
if (method == -1) return m_all;
//if (M_IS_CL1B(method)) return m_cl1b;
if (M_IS_LZMA(method)) return m_lzma;
if (M_IS_NRV2B(method)) return m_nrv2b;
if (M_IS_NRV2D(method)) return m_nrv2d;
if (M_IS_NRV2E(method)) return m_nrv2e;
if (small < 0)
small = file_size <= 512*1024;
if (M_IS_NRV2B(method))
return m_nrv2b;
if (M_IS_NRV2D(method))
return m_nrv2d;
if (M_IS_NRV2E(method))
return m_nrv2e;
if (M_IS_CL1B(method))
return m_cl1b;
if (M_IS_LZMA(method))
return m_lzma;
assert(method == -1); // --all-methods
if (level == 1 || small)
return m_nrv2b;
return m_nrv2e;
@ -135,6 +127,7 @@ const char *Packer::getDecompressorSections() const
"N2EFAS10,+80CXXXX,N2EFAS11,N2EDEC10,N2EFAS20,"
"N2EDEC20,N2EFAS30,N2EDEC30,N2EFAS40,N2EFAS50,"
"N2EDEC50,N2EFAS60,+40CXXXX,N2EFAS61,N2EDEC60";
#if 0
static const char cl1b_le32_small[] =
"CL1ENTER,CL1SMA10,CL1RLOAD,"
"CL1WID01,CL1SMA1B,"
@ -193,6 +186,7 @@ const char *Packer::getDecompressorSections() const
"CL1LEN01,CL1FAS1B,"
"CL1LEN02,"
"CL1COPY0";
#endif
static const char lzma_small[] =
"LZMA_DEC00,LZMA_DEC10,LZMA_DEC30";
static const char lzma_fast[] =
@ -208,8 +202,8 @@ const char *Packer::getDecompressorSections() const
return opt->small ? nrv2d_le32_small : nrv2d_le32_fast;
if (ph.method == M_NRV2E_LE32)
return opt->small ? nrv2e_le32_small : nrv2e_le32_fast;
if (ph.method == M_CL1B_LE32)
return opt->small ? cl1b_le32_small : cl1b_le32_fast;
// if (ph.method == M_CL1B_LE32)
// return opt->small ? cl1b_le32_small : cl1b_le32_fast;
if (M_IS_LZMA(ph.method)) {
if (UPX_F_LINUX_ELF_i386 ==ph.format
|| UPX_F_LINUX_ELFI_i386 ==ph.format

View File

@ -37,16 +37,7 @@
bool Packer::isValidFilter(int filter_id) const
{
if (!Filter::isValidFilter(filter_id))
return false;
if (filter_id == 0)
return true;
for (const int *f = getFilters(); f && *f >= 0; f++)
{
if (*f == filter_id)
return true;
}
return false;
return Filter::isValidFilter(filter_id, getFilters());
}
@ -106,19 +97,19 @@ void Packer::scanFilters(Filter *ft, const upx_byte *buf, unsigned buf_len,
#define FNOMRU 1 // filter, but not using mru
#define MRUFLT 2 // mru filter
static inline unsigned f80_call(int fid)
static inline unsigned f80_call(int filter_id)
{
return (1+ (0x0f & fid)) % 3;
return (1+ (0x0f & filter_id)) % 3;
}
static inline unsigned f80_jmp1(int fid)
static inline unsigned f80_jmp1(int filter_id)
{
return ((1+ (0x0f & fid)) / 3) % 3;
return ((1+ (0x0f & filter_id)) / 3) % 3;
}
static inline unsigned f80_jcc2(int fid)
static inline unsigned f80_jcc2(int filter_id)
{
return f80_jmp1(fid);
return f80_jmp1(filter_id);
}