1
0
mirror of https://github.com/upx/upx.git synced 2025-08-11 22:52:30 +08:00

WIP: clarify compressWithFilters; reduce size of obuf for PackLinuxElf64

modified:   p_lx_elf.cpp
	modified:   packer.cpp
	modified:   packer.h
This commit is contained in:
John Reiser
2022-03-21 13:49:46 -07:00
committed by Markus F.X.J. Oberhumer
parent 0e2a9de2b2
commit 663d6b466b
3 changed files with 92 additions and 44 deletions

View File

@ -2276,8 +2276,8 @@ bool PackLinuxElf32::canPack()
if (r_va == user_init_ava) { // found the Elf32_Rel
unsigned r_info = get_te32(&rp->r_info);
unsigned r_type = ELF32_R_TYPE(r_info);
if (Elf32_Ehdr::EM_ARM == e_machine
&& R_ARM_RELATIVE == r_type) {
if ((Elf32_Ehdr::EM_ARM == e_machine && R_ARM_RELATIVE == r_type)
|| (Elf32_Ehdr::EM_386 == e_machine && R_386_RELATIVE == r_type) ) {
user_init_va = get_te32(&file_image[user_init_off]);
}
else {
@ -2464,7 +2464,7 @@ PackLinuxElf64::canPack()
return false;
}
// The first PT_LOAD64 must cover the beginning of the file (0==p_offset).
upx_uint64_t max_LOADsz = 0, max_offset = 0;
Elf64_Phdr const *phdr = phdri;
for (unsigned j=0; j < e_phnum; ++phdr, ++j) {
if (j >= 14) {
@ -2472,23 +2472,27 @@ PackLinuxElf64::canPack()
return false;
}
unsigned const p_type = get_te32(&phdr->p_type);
if (1!=exetype && PT_LOAD64 == p_type) { // 1st PT_LOAD
exetype = 1;
load_va = get_te64(&phdr->p_vaddr); // class data member
upx_uint64_t const p_offset = get_te64(&phdr->p_offset);
upx_uint64_t const off = ~page_mask & load_va;
if (off && off == p_offset) { // specific hint
throwCantPack("Go-language PT_LOAD: try hemfix.c, or try '--force-execve'");
// Fixing it inside upx fails because packExtent() reads original file.
return false;
if (PT_LOAD64 == p_type) {
// The first PT_LOAD64 must cover the beginning of the file (0==p_offset).
if (1!= exetype) {
exetype = 1;
load_va = get_te64(&phdr->p_vaddr); // class data member
upx_uint64_t const p_offset = get_te64(&phdr->p_offset);
upx_uint64_t const off = ~page_mask & load_va;
if (off && off == p_offset) { // specific hint
throwCantPack("Go-language PT_LOAD: try hemfix.c, or try '--force-execve'");
// Fixing it inside upx fails because packExtent() reads original file.
return false;
}
if (0 != p_offset) { // 1st PT_LOAD must cover Ehdr and Phdr
throwCantPack("first PT_LOAD.p_offset != 0; try '--force-execve'");
return false;
}
// FIXME: bad for shlib!
hatch_off = ~3ul & (3+ get_te64(&phdr->p_memsz));
}
if (0 != p_offset) { // 1st PT_LOAD must cover Ehdr and Phdr
throwCantPack("first PT_LOAD.p_offset != 0; try '--force-execve'");
return false;
}
// FIXME: bad for shlib!
hatch_off = ~3ul & (3+ get_te64(&phdr->p_memsz));
break;
max_LOADsz = UPX_MAX(max_LOADsz, get_te64(&phdr->p_filesz));
max_offset = UPX_MAX(max_offset, get_te64(&phdr->p_filesz) + get_te64(&phdr->p_offset));
}
}
// We want to compress position-independent executable (gcc -pie)
@ -2804,7 +2808,8 @@ proceed: ;
exetype = 0;
// set options
opt->o_unix.blocksize = blocksize = file_size;
// .blocksize: avoid over-allocating
opt->o_unix.blocksize = blocksize = UPX_MAX(max_LOADsz, file_size - max_offset);
return true;
}
@ -3689,6 +3694,18 @@ void PackLinuxElf64::pack1(OutputFile *fo, Filter & /*ft*/)
assert(e_phoff == sizeof(Elf64_Ehdr)); // checked by canPack()
sz_phdrs = e_phnum * get_te16(&ehdri.e_phentsize);
// We compress separate pieces (usually each PT_LOAD, plus the gaps in the file
// that are not covered by any PT_LOAD), but currently at run time there can be
// only one decompressor method.
// Therefore we must plan ahead because Packer::compressWithFilters tries
// to find the smallest result among the available methods.
// In the future we may allow more than one decompression method at run time,
// but for now we must choose just one, and force compressWithFilters to use it.
int methods[256];
int nmethods = prepareMethods(methods, ph.method, getCompressionMethods(M_ALL, ph.level));
if (1 < nmethods) {
}
Elf64_Phdr *phdr = phdri;
note_size = 0;
for (unsigned j=0; j < e_phnum; ++phdr, ++j) {

View File

@ -1091,6 +1091,7 @@ void Packer::relocateLoader() {
}
/*************************************************************************
// void Packer::compressWithFilters():
// Try compression with several methods and filters, choose the best
/ or first working one. Needs buildLoader().
//
@ -1137,7 +1138,7 @@ 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 Packer::prepareMethods(int *methods, int ph_method, const int *all_methods) const {
int nmethods = 0;
if (!opt->all_methods || all_methods == nullptr) {
methods[nmethods++] = ph_method;
@ -1212,11 +1213,18 @@ done:
return nfilters;
}
void Packer::compressWithFilters(upx_bytep i_ptr, unsigned i_len, upx_bytep o_ptr, upx_bytep f_ptr,
unsigned f_len, const upx_bytep hdr_ptr, unsigned hdr_len,
Filter *parm_ft, const unsigned overlap_range,
const upx_compress_config_t *cconf, int filter_strategy,
bool inhibit_compression_check) {
void Packer::compressWithFilters(
upx_bytep i_ptr, unsigned const i_len, // written and restored by filters
upx_bytep const o_ptr, // where to put compressed output
upx_bytep f_ptr, unsigned const f_len, // subset of [*i_ptr, +i_len)
upx_bytep const hdr_ptr, unsigned const hdr_len,
Filter *const parm_ft, // updated
unsigned const overlap_range,
upx_compress_config_t const *const cconf,
int filter_strategy, // in+out for prepareFilters
bool const inhibit_compression_check
)
{
parm_ft->buf_len = f_len;
// struct copies
const PackHeader orig_ph = this->ph;
@ -1404,18 +1412,26 @@ void Packer::compressWithFilters(upx_bytep i_ptr, unsigned i_len, upx_bytep o_pt
//
**************************************************************************/
void Packer::compressWithFilters(Filter *ft, const unsigned overlap_range,
const upx_compress_config_t *cconf, int filter_strategy,
bool inhibit_compression_check) {
compressWithFilters(ft, overlap_range, cconf, filter_strategy, 0, 0, 0, nullptr, 0,
inhibit_compression_check);
void Packer::compressWithFilters(
Filter *ft, const unsigned overlap_range,
const upx_compress_config_t *cconf, int filter_strategy,
bool inhibit_compression_check)
{
compressWithFilters( // call the subroutine immediately below
ft, overlap_range,
cconf, filter_strategy,
0, 0, 0,
nullptr, 0,
inhibit_compression_check);
}
void Packer::compressWithFilters(Filter *ft, const unsigned overlap_range,
const upx_compress_config_t *cconf, int filter_strategy,
unsigned filter_off, unsigned ibuf_off, unsigned obuf_off,
const upx_bytep hdr_ptr, unsigned hdr_len,
bool inhibit_compression_check) {
void Packer::compressWithFilters(
Filter *ft, const unsigned overlap_range,
upx_compress_config_t const *cconf, int filter_strategy,
unsigned filter_off, unsigned ibuf_off, unsigned obuf_off,
upx_bytep const hdr_ptr, unsigned hdr_len,
bool inhibit_compression_check)
{
ibuf.checkState();
obuf.checkState();
@ -1427,8 +1443,13 @@ void Packer::compressWithFilters(Filter *ft, const unsigned overlap_range,
assert(f_ptr + f_len <= i_ptr + i_len);
compressWithFilters(i_ptr, i_len, o_ptr, f_ptr, f_len, hdr_ptr, hdr_len, ft, overlap_range,
cconf, filter_strategy, inhibit_compression_check);
compressWithFilters( // call the first one in this file
i_ptr, i_len,
o_ptr,
f_ptr, f_len,
hdr_ptr, hdr_len,
ft, overlap_range,
cconf, filter_strategy, inhibit_compression_check);
ibuf.checkState();
obuf.checkState();

View File

@ -177,14 +177,23 @@ protected:
bool inhibit_compression_check = false);
void compressWithFilters(Filter *ft, const unsigned overlap_range,
const upx_compress_config_t *cconf, int filter_strategy,
unsigned filter_buf_off, unsigned compress_ibuf_off,
unsigned compress_obuf_off, const upx_bytep hdr_ptr, unsigned hdr_len,
unsigned filter_buf_off,
unsigned compress_ibuf_off,
unsigned compress_obuf_off,
upx_bytep const hdr_ptr, unsigned hdr_len,
bool inhibit_compression_check = false);
// real compression driver
void compressWithFilters(upx_bytep i_ptr, unsigned i_len, upx_bytep o_ptr, upx_bytep f_ptr,
unsigned f_len, const upx_bytep hdr_ptr, unsigned hdr_len, Filter *ft,
const unsigned overlap_range, const upx_compress_config_t *cconf,
int filter_strategy, bool inhibit_compression_check = false);
void compressWithFilters(
upx_bytep i_ptr, unsigned i_len, // written and restored by filters
upx_bytep o_ptr,
upx_bytep f_ptr, unsigned f_len, // subset of [*i_ptr, +i_len)
upx_bytep const hdr_ptr, unsigned hdr_len,
Filter *parm_ft, // updated
unsigned overlap_range,
upx_compress_config_t const *cconf,
int filter_strategy,
bool inhibit_compression_check = false
);
// util for verifying overlapping decompresion
// non-destructive test
@ -239,6 +248,7 @@ public:
protected:
const int *getDefaultCompressionMethods_8(int method, int level, int small = -1) const;
const int *getDefaultCompressionMethods_le32(int method, int level, int small = -1) const;
int prepareMethods(int *methods, int ph_method, const int *all_methods) const;
virtual const char *getDecompressorSections() const;
virtual unsigned getDecompressorWrkmemSize() const;
virtual void defineDecompressorSymbols();