mirror of
https://github.com/upx/upx
synced 2025-09-28 19:06:07 +08:00
pe: fined grain control over resource compression
This commit is contained in:
parent
9a3b7a4f3f
commit
3dfe0ad478
3
PROJECTS
3
PROJECTS
|
@ -66,8 +66,7 @@ Existing formats:
|
||||||
|
|
||||||
- win32/pe: display a nice dialog box in the stub in case
|
- win32/pe: display a nice dialog box in the stub in case
|
||||||
of problems (like importing a DLL or function fails)
|
of problems (like importing a DLL or function fails)
|
||||||
- win32/pe: finer control over resource compression, per section
|
- win32/pe: per section compression
|
||||||
compression
|
|
||||||
|
|
||||||
|
|
||||||
Compression ratio:
|
Compression ratio:
|
||||||
|
|
3
TODO
3
TODO
|
@ -105,9 +105,6 @@ FORMAT WIN32/PE
|
||||||
|
|
||||||
- decrease runtime memory overhead
|
- decrease runtime memory overhead
|
||||||
|
|
||||||
2 - easy - mfx + ml) new switch(es) : do not compress resource types x,y,z
|
|
||||||
or resource names a,b,c
|
|
||||||
|
|
||||||
3 - difficult) don't compress the BSS section and other holes.
|
3 - difficult) don't compress the BSS section and other holes.
|
||||||
|
|
||||||
4 - medium - ml) fix when objectalign < 0x1000
|
4 - medium - ml) fix when objectalign < 0x1000
|
||||||
|
|
16
doc/upx.pod
16
doc/upx.pod
|
@ -870,6 +870,22 @@ Extra options available for this executable format:
|
||||||
|
|
||||||
--compress-resources=0 Don't compress any resources at all.
|
--compress-resources=0 Don't compress any resources at all.
|
||||||
|
|
||||||
|
--keep-resource=list Don't compress resources specified by the list.
|
||||||
|
The members of the list are separated by commas.
|
||||||
|
A list member has the following format: I<type[/name]>.
|
||||||
|
I<Type> is the type of the resource. Standard types
|
||||||
|
must be specified as decimal numbers, user types can be
|
||||||
|
specified by decimal IDs or strings. I<Name> is the
|
||||||
|
identifier of the resource. It can be a decimal number
|
||||||
|
or a string. For example:
|
||||||
|
|
||||||
|
--keep-resource=2/MYBITMAP,5,6/12345
|
||||||
|
|
||||||
|
UPX won't compress the named bitmap resource "MYBITMAP",
|
||||||
|
it leaves every dialog (5) resource uncompressed, and
|
||||||
|
it won't touch the string table resource with identifier
|
||||||
|
12345.
|
||||||
|
|
||||||
--force Force compression even when there is an
|
--force Force compression even when there is an
|
||||||
unexpected value in a header field.
|
unexpected value in a header field.
|
||||||
Use with care.
|
Use with care.
|
||||||
|
|
|
@ -72,6 +72,7 @@ void init_options(struct options_t *o)
|
||||||
o->win32_pe.compress_rt[i] = -1;
|
o->win32_pe.compress_rt[i] = -1;
|
||||||
o->win32_pe.compress_rt[24] = false; // 24 == RT_MANIFEST
|
o->win32_pe.compress_rt[24] = false; // 24 == RT_MANIFEST
|
||||||
o->win32_pe.strip_relocs = -1;
|
o->win32_pe.strip_relocs = -1;
|
||||||
|
o->win32_pe.keep_resource = "";
|
||||||
}
|
}
|
||||||
|
|
||||||
static struct options_t global_options;
|
static struct options_t global_options;
|
||||||
|
@ -702,6 +703,11 @@ static int do_option(int optc, const char *arg)
|
||||||
opt->win32_pe.strip_relocs = 0;
|
opt->win32_pe.strip_relocs = 0;
|
||||||
//printf("strip_relocs: %d\n", opt->win32_pe.strip_relocs);
|
//printf("strip_relocs: %d\n", opt->win32_pe.strip_relocs);
|
||||||
break;
|
break;
|
||||||
|
case 635:
|
||||||
|
if (!mfx_optarg || !mfx_optarg[0])
|
||||||
|
e_optarg(arg);
|
||||||
|
opt->win32_pe.keep_resource = mfx_optarg;
|
||||||
|
break;
|
||||||
case 650:
|
case 650:
|
||||||
opt->atari_tos.split_segments = true;
|
opt->atari_tos.split_segments = true;
|
||||||
break;
|
break;
|
||||||
|
@ -859,6 +865,7 @@ static const struct mfx_option longopts[] =
|
||||||
{"compress-resources", 2, 0, 632},
|
{"compress-resources", 2, 0, 632},
|
||||||
{"strip-loadconf", 0x12, 0, 633}, // OBSOLETE - IGNORED
|
{"strip-loadconf", 0x12, 0, 633}, // OBSOLETE - IGNORED
|
||||||
{"strip-relocs", 0x12, 0, 634},
|
{"strip-relocs", 0x12, 0, 634},
|
||||||
|
{"keep-resource", 0x31, 0, 635},
|
||||||
// ps1/exe
|
// ps1/exe
|
||||||
{"boot-only", 0x10, 0, 670},
|
{"boot-only", 0x10, 0, 670},
|
||||||
{"no-align", 0x10, 0, 671},
|
{"no-align", 0x10, 0, 671},
|
||||||
|
@ -941,6 +948,7 @@ static const struct mfx_option longopts[] =
|
||||||
{"compress-resources", 2, 0, 632},
|
{"compress-resources", 2, 0, 632},
|
||||||
{"strip-loadconf", 0x12, 0, 633}, // OBSOLETE - IGNORED
|
{"strip-loadconf", 0x12, 0, 633}, // OBSOLETE - IGNORED
|
||||||
{"strip-relocs", 0x12, 0, 634},
|
{"strip-relocs", 0x12, 0, 634},
|
||||||
|
{"keep-resource", 0x31, 0, 635},
|
||||||
|
|
||||||
{ NULL, 0, NULL, 0 }
|
{ NULL, 0, NULL, 0 }
|
||||||
};
|
};
|
||||||
|
|
|
@ -139,6 +139,7 @@ struct options_t {
|
||||||
int compress_resources;
|
int compress_resources;
|
||||||
signed char compress_rt[25]; // 25 == RT_LAST
|
signed char compress_rt[25]; // 25 == RT_LAST
|
||||||
int strip_relocs;
|
int strip_relocs;
|
||||||
|
const char *keep_resource;
|
||||||
} win32_pe;
|
} win32_pe;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -1218,10 +1218,10 @@ public:
|
||||||
bool clear();
|
bool clear();
|
||||||
|
|
||||||
void dump() const { dump(root,0); }
|
void dump() const { dump(root,0); }
|
||||||
/*
|
|
||||||
unsigned iname() const {return current->parent->id;}
|
unsigned iname() const {return current->parent->id;}
|
||||||
const upx_byte *nname() const {return current->parent->name;}
|
const upx_byte *nname() const {return current->parent->name;}
|
||||||
|
|
||||||
|
/*
|
||||||
unsigned ilang() const {return current->id;}
|
unsigned ilang() const {return current->id;}
|
||||||
const upx_byte *nlang() const {return current->name;}
|
const upx_byte *nlang() const {return current->name;}
|
||||||
*/
|
*/
|
||||||
|
@ -1420,6 +1420,52 @@ void PackArmPe::processResources(Resource *res,unsigned newaddr)
|
||||||
delete [] p;
|
delete [] p;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static bool match(unsigned itype, const unsigned char *ntype,
|
||||||
|
unsigned iname, const unsigned char *nname,
|
||||||
|
const char *keep)
|
||||||
|
{
|
||||||
|
// format of string keep: type1[/name1],type2[/name2], ....
|
||||||
|
// typex and namex can be string or number
|
||||||
|
// hopefully resource names do not have '/' or ',' characters inside
|
||||||
|
|
||||||
|
struct helper
|
||||||
|
{
|
||||||
|
static bool match(unsigned num, const unsigned char *unistr,
|
||||||
|
const char *keep)
|
||||||
|
{
|
||||||
|
if (!unistr)
|
||||||
|
return (unsigned) atoi(keep) == num;
|
||||||
|
|
||||||
|
unsigned ic;
|
||||||
|
for (ic = 0; ic < get_le16(unistr); ic++)
|
||||||
|
if (unistr[2 + ic * 2] != (unsigned char) keep[ic])
|
||||||
|
return false;
|
||||||
|
return keep[ic] == 0 || keep[ic] == ',' || keep[ic] == '/';
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
// FIXME this comparison is not too exact
|
||||||
|
while (1)
|
||||||
|
{
|
||||||
|
char *delim1 = strchr(keep, '/');
|
||||||
|
char *delim2 = strchr(keep, ',');
|
||||||
|
if (helper::match(itype, ntype, keep))
|
||||||
|
{
|
||||||
|
if (!delim1)
|
||||||
|
return true;
|
||||||
|
if (delim2 && delim2 < delim1)
|
||||||
|
return true;
|
||||||
|
if (helper::match(iname, nname, delim1 + 1))
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (delim2 == NULL)
|
||||||
|
break;
|
||||||
|
keep = delim2 + 1;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
void PackArmPe::processResources(Resource *res)
|
void PackArmPe::processResources(Resource *res)
|
||||||
{
|
{
|
||||||
const unsigned vaddr = IDADDR(PEDIR_RESOURCE);
|
const unsigned vaddr = IDADDR(PEDIR_RESOURCE);
|
||||||
|
@ -1488,6 +1534,10 @@ void PackArmPe::processResources(Resource *res)
|
||||||
do_compress = false; // u"REGISTRY"
|
do_compress = false; // u"REGISTRY"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (do_compress && opt->win32_pe.keep_resource[0])
|
||||||
|
do_compress ^= match(res->itype(), res->ntype(), res->iname(),
|
||||||
|
res->nname(), opt->win32_pe.keep_resource);
|
||||||
|
|
||||||
if (do_compress)
|
if (do_compress)
|
||||||
{
|
{
|
||||||
csize += res->size();
|
csize += res->size();
|
||||||
|
|
|
@ -1178,10 +1178,10 @@ public:
|
||||||
bool clear();
|
bool clear();
|
||||||
|
|
||||||
void dump() const { dump(root,0); }
|
void dump() const { dump(root,0); }
|
||||||
/*
|
|
||||||
unsigned iname() const {return current->parent->id;}
|
unsigned iname() const {return current->parent->id;}
|
||||||
const upx_byte *nname() const {return current->parent->name;}
|
const upx_byte *nname() const {return current->parent->name;}
|
||||||
|
/*
|
||||||
unsigned ilang() const {return current->id;}
|
unsigned ilang() const {return current->id;}
|
||||||
const upx_byte *nlang() const {return current->name;}
|
const upx_byte *nlang() const {return current->name;}
|
||||||
*/
|
*/
|
||||||
|
@ -1380,6 +1380,52 @@ void PackW32Pe::processResources(Resource *res,unsigned newaddr)
|
||||||
delete [] p;
|
delete [] p;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static bool match(unsigned itype, const unsigned char *ntype,
|
||||||
|
unsigned iname, const unsigned char *nname,
|
||||||
|
const char *keep)
|
||||||
|
{
|
||||||
|
// format of string keep: type1[/name1],type2[/name2], ....
|
||||||
|
// typex and namex can be string or number
|
||||||
|
// hopefully resource names do not have '/' or ',' characters inside
|
||||||
|
|
||||||
|
struct helper
|
||||||
|
{
|
||||||
|
static bool match(unsigned num, const unsigned char *unistr,
|
||||||
|
const char *keep)
|
||||||
|
{
|
||||||
|
if (!unistr)
|
||||||
|
return (unsigned) atoi(keep) == num;
|
||||||
|
|
||||||
|
unsigned ic;
|
||||||
|
for (ic = 0; ic < get_le16(unistr); ic++)
|
||||||
|
if (unistr[2 + ic * 2] != (unsigned char) keep[ic])
|
||||||
|
return false;
|
||||||
|
return keep[ic] == 0 || keep[ic] == ',' || keep[ic] == '/';
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
// FIXME this comparison is not too exact
|
||||||
|
while (1)
|
||||||
|
{
|
||||||
|
char *delim1 = strchr(keep, '/');
|
||||||
|
char *delim2 = strchr(keep, ',');
|
||||||
|
if (helper::match(itype, ntype, keep))
|
||||||
|
{
|
||||||
|
if (!delim1)
|
||||||
|
return true;
|
||||||
|
if (delim2 && delim2 < delim1)
|
||||||
|
return true;
|
||||||
|
if (helper::match(iname, nname, delim1 + 1))
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (delim2 == NULL)
|
||||||
|
break;
|
||||||
|
keep = delim2 + 1;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
void PackW32Pe::processResources(Resource *res)
|
void PackW32Pe::processResources(Resource *res)
|
||||||
{
|
{
|
||||||
const unsigned vaddr = IDADDR(PEDIR_RESOURCE);
|
const unsigned vaddr = IDADDR(PEDIR_RESOURCE);
|
||||||
|
@ -1448,6 +1494,10 @@ void PackW32Pe::processResources(Resource *res)
|
||||||
do_compress = false; // u"REGISTRY"
|
do_compress = false; // u"REGISTRY"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (do_compress && opt->win32_pe.keep_resource[0])
|
||||||
|
do_compress ^= match(res->itype(), res->ntype(), res->iname(),
|
||||||
|
res->nname(), opt->win32_pe.keep_resource);
|
||||||
|
|
||||||
if (do_compress)
|
if (do_compress)
|
||||||
{
|
{
|
||||||
csize += res->size();
|
csize += res->size();
|
||||||
|
|
Loading…
Reference in New Issue
Block a user