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

Extra parameter for compressWithFilters and packExtent,

to fix 2-pass problem with --brute on linux/elf386.
Only one decompression method is allowed, chosen by
smallest output for .text; but Elf headers come first.
	packer.cpp packer.h p_unix.cpp p_unix.h p_lx_elf.cpp

committer: jreiser <jreiser> 1140241030 +0000
This commit is contained in:
John Reiser 2006-02-18 05:37:10 +00:00
parent d3bcba6a05
commit 268e322e1c
5 changed files with 80 additions and 39 deletions

View File

@ -738,14 +738,7 @@ void PackLinuxElf32::pack2(OutputFile *fo, Filter &ft)
unsigned total_in = 0;
unsigned total_out = 0;
ui_pass = -1; // Compressing Elf headers is invisible to UI.
x.offset = 0;
x.size = sizeof(Elf32_Ehdr) + sz_phdrs;
{
int const old_level = ph.level; ph.level = 10;
packExtent(x, total_in, total_out, 0, fo);
ph.level = old_level;
}
unsigned hdr_ulen = sizeof(Elf32_Ehdr) + sz_phdrs;
ui_pass = 0;
ft.addvalue = 0;
@ -770,7 +763,8 @@ void PackLinuxElf32::pack2(OutputFile *fo, Filter &ft)
// sometimes marks as PF_X anyway. So filter only first segment.
packExtent(x, total_in, total_out,
((0==nx && (Elf32_Phdr::PF_X & get_native32(&phdri[k].p_flags)))
? &ft : 0 ), fo );
? &ft : 0 ), fo, hdr_ulen);
hdr_ulen = 0;
++nx;
}
if (0!=ptload1sz && ptload0hi < ptload1lo) { // alignment hole?
@ -819,14 +813,7 @@ void PackLinuxElf64::pack2(OutputFile *fo, Filter &ft)
unsigned total_in = 0;
unsigned total_out = 0;
ui_pass = -1; // Compressing Elf headers is invisible to UI.
x.offset = 0;
x.size = sizeof(Elf64_Ehdr) + sz_phdrs;
{
int const old_level = ph.level; ph.level = 10;
packExtent(x, total_in, total_out, 0, fo);
ph.level = old_level;
}
unsigned hdr_ulen = sizeof(Elf64_Ehdr) + sz_phdrs;
ui_pass = 0;
ft.addvalue = 0;
@ -851,7 +838,8 @@ void PackLinuxElf64::pack2(OutputFile *fo, Filter &ft)
// sometimes marks as PF_X anyway. So filter only first segment.
packExtent(x, total_in, total_out,
((0==nx && (Elf64_Phdr::PF_X & get_native64(&phdri[k].p_flags)))
? &ft : 0 ), fo );
? &ft : 0 ), fo, hdr_ulen);
hdr_ulen = 0;
++nx;
}
if (0!=ptload1sz && ptload0hi < ptload1lo) { // alignment hole?
@ -1513,14 +1501,7 @@ void PackLinuxI386elf::pack2(OutputFile *fo, Filter &ft)
unsigned total_in = 0;
unsigned total_out = 0;
ui_pass = -1; // Compressing Elf headers is invisible to UI.
x.offset = 0;
x.size = sizeof(Elf32_Ehdr) + sz_phdrs;
{
int const old_level = ph.level; ph.level = 10;
packExtent(x, total_in, total_out, 0, fo);
ph.level = old_level;
}
unsigned hdr_ulen = sizeof(Elf32_Ehdr) + sz_phdrs;
ui_pass = 0;
ft.addvalue = 0;
@ -1542,7 +1523,8 @@ void PackLinuxI386elf::pack2(OutputFile *fo, Filter &ft)
}
packExtent(x, total_in, total_out,
((Elf32_Phdr::PF_X & phdri[k].p_flags)
? &ft : 0 ), fo );
? &ft : 0 ), fo, hdr_ulen);
hdr_ulen = 0;
++nx;
}
if (0!=ptload1sz && ptload0hi < ptload1lo) { // alignment hole?

View File

@ -304,9 +304,16 @@ void PackUnix::packExtent(
unsigned &total_in,
unsigned &total_out,
Filter *ft,
OutputFile *fo
OutputFile *fo,
unsigned hdr_ulen
)
{
MemBuffer hdr_ibuf;
if (hdr_ulen) {
hdr_ibuf.alloc(hdr_ulen);
fi->seek(0, SEEK_SET);
int l = fi->readx(hdr_ibuf, hdr_ulen);
}
fi->seek(x.offset, SEEK_SET);
for (off_t rest = x.size; 0 != rest; ) {
int const strategy = getStrategy(*ft);
@ -336,7 +343,9 @@ void PackUnix::packExtent(
ft->id = 0;
ft->cto = 0;
compressWithFilters(ft, OVERHEAD, strategy);
compressWithFilters(ft, OVERHEAD, strategy,
NULL, 0, 0, 0, 0, // those 5 args are the defaults
hdr_ibuf, hdr_ulen);
}
else {
(void) compress(ibuf, obuf); // ignore return value
@ -358,6 +367,24 @@ void PackUnix::packExtent(
// write block sizes
b_info tmp;
if (hdr_ulen) {
unsigned hdr_clen;
MemBuffer hdr_obuf;
unsigned result[16];
upx_compress_config_t conf;
memset(&conf, 0xff, sizeof(conf));
hdr_obuf.allocForCompression(hdr_ulen);
int r = upx_compress(hdr_ibuf, hdr_ulen, hdr_obuf, &hdr_clen, 0,
ph.method, 10, &conf, result);
memset(&tmp, 0, sizeof(tmp));
set_native32(&tmp.sz_unc, hdr_ulen);
set_native32(&tmp.sz_cpr, hdr_clen);
tmp.b_method = (unsigned char) ph.method;
fo->write(&tmp, sizeof(tmp));
b_len += sizeof(b_info);
fo->write(hdr_obuf, hdr_clen);
hdr_ulen = 0; // compress hdr one time only
}
memset(&tmp, 0, sizeof(tmp));
set_native32(&tmp.sz_unc, ph.u_len);
set_native32(&tmp.sz_cpr, ph.c_len);

View File

@ -81,7 +81,8 @@ protected:
off_t size;
};
virtual void packExtent(const Extent &x,
unsigned &total_in, unsigned &total_out, Filter *, OutputFile *);
unsigned &total_in, unsigned &total_out, Filter *, OutputFile *,
unsigned hdr_len = 0);
virtual void unpackExtent(unsigned wanted, OutputFile *fo,
unsigned &total_in, unsigned &total_out,
unsigned &c_adler, unsigned &u_adler,

View File

@ -1258,13 +1258,32 @@ const char *Packer::getDecompressor() const
// executable formats.
//
// It will replace the tryFilters() / compress() call sequence.
// 2006-02-15: hdr_buf and hdr_u_len are default empty input "header" array
// to fix a 2-pass problem with Elf headers. As of today there can be
// only one decompression method per executable output file, and that method
// is the one that gives best compression for .text and loader. However,
// the Elf headers precede .text in the output file, and are written first.
// "--brute" compression often compressed the Elf headers using nrv2b
// but the .text (and loader) with nrv2e. This often resulted in SIGSEGV
// during decompression.
// The workaround is for hdr_buf and hdr_u_len to describe the Elf headers
// (typically less than 512 bytes) when .text is passed in, and include
// them in the calculation of shortest output. Then the result
// this->ph.method will say which [single] method to use for everthing.
// The Elf headers are never filtered. They are short enough (< 512 bytes)
// that compressing them more than once per method (once here when choosing,
// once again just before writing [because compressWithFilters discards])
// is OK because of the simplicity of not having two output arrays.
**************************************************************************/
void Packer::compressWithFilters(Filter *parm_ft,
const unsigned overlap_range,
int strategy, const int *parm_filters,
unsigned max_offset, unsigned max_match,
unsigned filter_off, unsigned compress_buf_off)
unsigned filter_off, unsigned compress_buf_off,
unsigned char *hdr_buf,
unsigned hdr_u_len)
{
const int *f;
//
@ -1280,6 +1299,7 @@ void Packer::compressWithFilters(Filter *parm_ft,
best_ph.c_len = orig_ph.u_len;
best_ph.overlap_overhead = 0;
unsigned best_ph_lsize = 0;
unsigned best_hdr_clen = 0;
// preconditions
assert(orig_ph.filter == 0);
@ -1373,6 +1393,14 @@ void Packer::compressWithFilters(Filter *parm_ft,
int nfilters_success = 0;
for (int m = 0; m < nmethods; m++) // for all methods
{
unsigned hdr_clen = 0;
if (hdr_buf && hdr_u_len) {
unsigned result[16];
upx_compress_config_t conf;
memset(&conf, 0xff, sizeof(conf));
int r = upx_compress(hdr_buf, hdr_u_len, obuf, &hdr_clen,
0, methods[m], 10, &conf, result);
}
for (int i = 0; i < nfilters; i++) // for all filters
{
ibuf.checkState();
@ -1428,19 +1456,19 @@ void Packer::compressWithFilters(Filter *parm_ft,
lsize = buildLoader(&ft);
}
#if 0
printf("\n%2d %02x: %d +%4d = %d (best: %d +%4d = %d)\n", ph.method, ph.filter,
ph.c_len, lsize, ph.c_len + lsize,
best_ph.c_len, best_ph_lsize, best_ph.c_len + best_ph_lsize);
printf("\n%2d %02x: %d +%4d +%3d = %d (best: %d +%4d +%3d = %d)\n", ph.method, ph.filter,
ph.c_len, lsize, hdr_clen, ph.c_len + lsize + hdr_clen,
best_ph.c_len, best_ph_lsize, best_hdr_clen, best_ph.c_len + best_ph_lsize + best_hdr_clen);
#endif
bool update = false;
if (ph.c_len + lsize < best_ph.c_len + best_ph_lsize)
if (ph.c_len + lsize + hdr_clen < best_ph.c_len + best_ph_lsize + best_hdr_clen)
update = true;
else if (ph.c_len + lsize == best_ph.c_len + best_ph_lsize)
else if (ph.c_len + lsize + hdr_clen == best_ph.c_len + best_ph_lsize + best_hdr_clen)
{
// prefer smaller loaders
if (lsize < best_ph_lsize)
if (lsize + hdr_clen < best_ph_lsize + best_hdr_clen)
update = true;
else if (lsize == best_ph_lsize)
else if (lsize + hdr_clen == best_ph_lsize + best_hdr_clen)
{
// prefer less overlap_overhead
if (ph.overlap_overhead < best_ph.overlap_overhead)
@ -1455,6 +1483,7 @@ void Packer::compressWithFilters(Filter *parm_ft,
// save compression results
best_ph = ph;
best_ph_lsize = lsize;
best_hdr_clen = hdr_clen;
best_ft = ft;
}
}

View File

@ -172,7 +172,9 @@ protected:
const int *filters = NULL,
unsigned max_offset = 0, unsigned max_match = 0,
unsigned filter_buf_off = 0,
unsigned compress_buf_off = 0);
unsigned compress_buf_off = 0,
unsigned char *header_buffer = 0,
unsigned header_length = 0);
// util for verifying overlapping decompresion
// non-destructive test