f17d9967c2
modified: main.cpp
1595 lines
45 KiB
C++
1595 lines
45 KiB
C++
/* main.cpp --
|
|
|
|
This file is part of the UPX executable compressor.
|
|
|
|
Copyright (C) 1996-2021 Markus Franz Xaver Johannes Oberhumer
|
|
Copyright (C) 1996-2021 Laszlo Molnar
|
|
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>
|
|
*/
|
|
|
|
#include "conf.h"
|
|
#include "compress.h"
|
|
#include "file.h"
|
|
#include "packer.h"
|
|
#include "p_elf.h"
|
|
|
|
/*************************************************************************
|
|
// options
|
|
**************************************************************************/
|
|
|
|
void options_t::reset() {
|
|
options_t *o = this;
|
|
mem_clear(o, sizeof(*o));
|
|
o->crp.reset();
|
|
|
|
o->cmd = CMD_NONE;
|
|
o->method = M_NONE;
|
|
o->level = -1;
|
|
o->filter = FT_NONE;
|
|
|
|
o->backup = -1;
|
|
o->overlay = -1;
|
|
o->preserve_mode = true;
|
|
o->preserve_ownership = true;
|
|
o->preserve_timestamp = true;
|
|
|
|
o->console = CON_FILE;
|
|
#if (ACC_OS_DOS32) && defined(__DJGPP__)
|
|
o->console = CON_INIT;
|
|
#elif (USE_SCREEN_WIN32)
|
|
o->console = CON_INIT;
|
|
#elif 1 && defined(__linux__)
|
|
o->console = CON_INIT;
|
|
#endif
|
|
o->verbose = 2;
|
|
|
|
o->win32_pe.compress_exports = 1;
|
|
o->win32_pe.compress_icons = 2;
|
|
o->win32_pe.compress_resources = -1;
|
|
for (unsigned i = 0; i < TABLESIZE(o->win32_pe.compress_rt); i++)
|
|
o->win32_pe.compress_rt[i] = -1;
|
|
o->win32_pe.compress_rt[24] = false; // 24 == RT_MANIFEST
|
|
o->win32_pe.strip_relocs = -1;
|
|
o->win32_pe.keep_resource = "";
|
|
}
|
|
|
|
static options_t global_options;
|
|
options_t *opt = &global_options;
|
|
|
|
static int done_output_name = 0;
|
|
|
|
const char *argv0 = "";
|
|
const char *progname = "";
|
|
|
|
static acc_getopt_t mfx_getopt;
|
|
#define mfx_optarg mfx_getopt.optarg
|
|
#define mfx_optind mfx_getopt.optind
|
|
#define mfx_option acc_getopt_longopt_t
|
|
static void handle_opterr(acc_getopt_p g, const char *f, void *v) {
|
|
struct A {
|
|
va_list ap;
|
|
};
|
|
struct A *a = (struct A *) v;
|
|
fprintf(stderr, "%s: ", g->progname);
|
|
vfprintf(stderr, f, a->ap);
|
|
fprintf(stderr, "\n");
|
|
}
|
|
|
|
/*************************************************************************
|
|
// exit handlers
|
|
**************************************************************************/
|
|
|
|
static int exit_code = EXIT_OK;
|
|
|
|
#if (WITH_GUI)
|
|
__acc_static_noinline void do_exit(void) { throw exit_code; }
|
|
#else
|
|
#if defined(__GNUC__)
|
|
static void do_exit(void) __attribute__((__noreturn__));
|
|
#endif
|
|
static void do_exit(void) {
|
|
static bool in_exit = false;
|
|
|
|
if (in_exit)
|
|
exit(exit_code);
|
|
in_exit = true;
|
|
|
|
fflush(con_term);
|
|
fflush(stderr);
|
|
exit(exit_code);
|
|
}
|
|
#endif
|
|
|
|
#define EXIT_FATAL 3
|
|
|
|
static bool set_eec(int ec, int *eec) {
|
|
if (ec == EXIT_FATAL) {
|
|
*eec = EXIT_ERROR;
|
|
return 1;
|
|
} else if (ec < 0 || ec == EXIT_ERROR) {
|
|
*eec = EXIT_ERROR;
|
|
} else if (ec == EXIT_WARN) {
|
|
if (!opt->ignorewarn)
|
|
if (*eec == EXIT_OK)
|
|
*eec = ec;
|
|
} else if (ec == EXIT_OK) {
|
|
/* do nothing */
|
|
} else {
|
|
assert(0);
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
bool set_exit_code(int ec) { return set_eec(ec, &exit_code); }
|
|
|
|
static void e_exit(int ec) {
|
|
(void) set_exit_code(ec);
|
|
do_exit();
|
|
}
|
|
|
|
static void e_usage(void) {
|
|
show_usage();
|
|
e_exit(EXIT_USAGE);
|
|
}
|
|
|
|
#if 0 // UNUSED
|
|
static void e_memory(void)
|
|
{
|
|
show_head();
|
|
fflush(con_term);
|
|
fprintf(stderr,"%s: out of memory\n", argv0);
|
|
e_exit(EXIT_MEMORY);
|
|
}
|
|
#endif // UNUSED
|
|
|
|
static void e_method(int m, int l) {
|
|
fflush(con_term);
|
|
fprintf(stderr, "%s: illegal method option -- %d/%d\n", argv0, m, l);
|
|
e_usage();
|
|
}
|
|
|
|
static void e_optarg(const char *n) {
|
|
fflush(con_term);
|
|
fprintf(stderr, "%s: invalid argument in option '%s'\n", argv0, n);
|
|
e_exit(EXIT_USAGE);
|
|
}
|
|
|
|
static void e_optval(const char *n) {
|
|
fflush(con_term);
|
|
fprintf(stderr, "%s: invalid value for option '%s'\n", argv0, n);
|
|
e_exit(EXIT_USAGE);
|
|
}
|
|
|
|
#if defined(OPTIONS_VAR)
|
|
static void e_envopt(const char *n) {
|
|
fflush(con_term);
|
|
if (n)
|
|
fprintf(stderr, "%s: invalid string '%s' in environment variable '%s'\n", argv0, n,
|
|
OPTIONS_VAR);
|
|
else
|
|
fprintf(stderr, "%s: illegal option in environment variable '%s'\n", argv0, OPTIONS_VAR);
|
|
e_exit(EXIT_USAGE);
|
|
}
|
|
#endif /* defined(OPTIONS_VAR) */
|
|
|
|
#if 0 // UNUSED
|
|
static void __acc_cdecl_sighandler e_sighandler(int signum)
|
|
{
|
|
UNUSED(signum);
|
|
e_exit(EXIT_FATAL);
|
|
}
|
|
#endif // UNUSED
|
|
|
|
/*************************************************************************
|
|
// check options
|
|
**************************************************************************/
|
|
|
|
static void check_not_both(bool e1, bool e2, const char *c1, const char *c2) {
|
|
if (e1 && e2) {
|
|
fprintf(stderr, "%s: ", argv0);
|
|
fprintf(stderr, "cannot use both '%s' and '%s'\n", c1, c2);
|
|
e_usage();
|
|
}
|
|
}
|
|
|
|
static void check_options(int i, int argc) {
|
|
assert(i <= argc);
|
|
|
|
if (opt->cmd != CMD_COMPRESS) {
|
|
// invalidate compression options
|
|
opt->method = 0;
|
|
opt->level = 0;
|
|
opt->exact = 0;
|
|
opt->small = 0;
|
|
opt->crp.reset();
|
|
}
|
|
|
|
// set default overlay action
|
|
if (!(opt->cmd == CMD_COMPRESS || opt->cmd == CMD_DECOMPRESS))
|
|
opt->overlay = opt->COPY_OVERLAY;
|
|
else if (opt->overlay < 0)
|
|
opt->overlay = opt->COPY_OVERLAY;
|
|
|
|
check_not_both(opt->exact, opt->overlay == opt->STRIP_OVERLAY, "--exact", "--overlay=strip");
|
|
|
|
// set default backup option
|
|
if (opt->backup < 0)
|
|
opt->backup = 0;
|
|
if (!(opt->cmd == CMD_COMPRESS || opt->cmd == CMD_DECOMPRESS))
|
|
opt->backup = 1;
|
|
|
|
check_not_both(opt->to_stdout, opt->output_name != nullptr, "--stdout", "-o");
|
|
if (opt->to_stdout && opt->cmd == CMD_COMPRESS) {
|
|
fprintf(stderr, "%s: cannot use '--stdout' when compressing\n", argv0);
|
|
e_usage();
|
|
}
|
|
if (opt->to_stdout || opt->output_name) {
|
|
if (i + 1 != argc) {
|
|
fprintf(stderr, "%s: need exactly one argument when using '%s'\n", argv0,
|
|
opt->to_stdout ? "--stdout" : "-o");
|
|
e_usage();
|
|
}
|
|
}
|
|
}
|
|
|
|
/*************************************************************************
|
|
// misc
|
|
**************************************************************************/
|
|
|
|
static void e_help(void) {
|
|
show_help();
|
|
e_exit(EXIT_USAGE);
|
|
}
|
|
|
|
static void set_term(FILE *f) {
|
|
if (f)
|
|
con_term = f;
|
|
else
|
|
con_term = acc_isatty(STDIN_FILENO) ? stderr : stdout;
|
|
}
|
|
|
|
static void set_cmd(int cmd) {
|
|
if (cmd > opt->cmd)
|
|
opt->cmd = cmd;
|
|
}
|
|
|
|
static bool set_method(int m, int l) {
|
|
if (m > 0) {
|
|
if (!Packer::isValidCompressionMethod(m))
|
|
return false;
|
|
// something like "--brute --lzma" should not disable "--brute"
|
|
if (!opt->all_methods)
|
|
opt->method = m;
|
|
}
|
|
if (l > 0)
|
|
opt->level = l;
|
|
set_cmd(CMD_COMPRESS);
|
|
return true;
|
|
}
|
|
|
|
static void set_output_name(const char *n, bool allow_m) {
|
|
#if 1
|
|
if (done_output_name > 0) {
|
|
fprintf(stderr, "%s: option '-o' more than once given\n", argv0);
|
|
e_usage();
|
|
}
|
|
#endif
|
|
if (!n || !n[0] || (!allow_m && n[0] == '-')) {
|
|
fprintf(stderr, "%s: missing output name\n", argv0);
|
|
e_usage();
|
|
}
|
|
if (strlen(n) >= ACC_FN_PATH_MAX - 4) {
|
|
fprintf(stderr, "%s: output name too long\n", argv0);
|
|
e_usage();
|
|
}
|
|
opt->output_name = n;
|
|
done_output_name++;
|
|
}
|
|
|
|
/*************************************************************************
|
|
// get options
|
|
**************************************************************************/
|
|
|
|
static char *prepare_shortopts(char *buf, const char *n, const struct mfx_option *longopts) {
|
|
char *o = buf;
|
|
|
|
for (; n && *n; n++)
|
|
if (*n != ' ')
|
|
*o++ = *n;
|
|
*o = 0;
|
|
for (; longopts && longopts->name; longopts++) {
|
|
int v = longopts->val;
|
|
#if !defined(NDEBUG)
|
|
assert(longopts->name[0] != '\0');
|
|
assert(longopts->name[0] != '-');
|
|
if (longopts->has_arg & 0x20)
|
|
assert((longopts->has_arg & 0xf) == 1);
|
|
#endif
|
|
#if 0
|
|
static char vopts[1024];
|
|
if (v > 0 && v < 1024)
|
|
{
|
|
if (vopts[v] && strchr(buf,v) == nullptr)
|
|
printf("warning: duplicate option %d ('%c')!\n", v, v & 127);
|
|
vopts[v] = 1;
|
|
}
|
|
#endif
|
|
if (v > 0 && v < 256 && strchr(buf, v) == nullptr) {
|
|
*o++ = (char) v;
|
|
if ((longopts->has_arg & 0xf) >= 1)
|
|
*o++ = ':';
|
|
if ((longopts->has_arg & 0xf) >= 2)
|
|
*o++ = ':';
|
|
*o = 0;
|
|
}
|
|
if (longopts->has_arg & 0x20)
|
|
assert((longopts->has_arg & 0xf) == 1);
|
|
}
|
|
return buf;
|
|
}
|
|
|
|
template <class T>
|
|
static int getoptvar(T *var, const T min_value, const T max_value, const char *arg_fatal) {
|
|
const char *p = mfx_optarg;
|
|
char *endptr;
|
|
int r = 0;
|
|
long n;
|
|
T v;
|
|
|
|
if (!p || !p[0]) {
|
|
r = -1;
|
|
goto error;
|
|
}
|
|
// avoid interpretation as octal value
|
|
while (p[0] == '0' && isdigit(p[1]))
|
|
p++;
|
|
n = strtol(p, &endptr, 0);
|
|
if (*endptr != '\0') {
|
|
r = -2;
|
|
goto error;
|
|
}
|
|
v = (T) n;
|
|
if (v < min_value) {
|
|
r = -3;
|
|
goto error;
|
|
}
|
|
if (v > max_value) {
|
|
r = -4;
|
|
goto error;
|
|
}
|
|
*var = v;
|
|
goto done;
|
|
error:
|
|
if (arg_fatal != nullptr)
|
|
e_optval(arg_fatal);
|
|
done:
|
|
return r;
|
|
}
|
|
|
|
template <class T, T default_value, T min_value, T max_value>
|
|
static int getoptvar(OptVar<T, default_value, min_value, max_value> *var, const char *arg_fatal) {
|
|
T v = default_value;
|
|
int r = getoptvar(&v, min_value, max_value, arg_fatal);
|
|
if (r == 0)
|
|
*var = v;
|
|
return r;
|
|
}
|
|
|
|
static int do_option(int optc, const char *arg) {
|
|
int i = 0;
|
|
|
|
switch (optc) {
|
|
#if 0
|
|
// FIXME: to_stdout doesn't work because of console code mess
|
|
//case 'c':
|
|
case 517:
|
|
opt->to_stdout = true;
|
|
break;
|
|
#endif
|
|
case 'd':
|
|
set_cmd(CMD_DECOMPRESS);
|
|
break;
|
|
case 'D':
|
|
opt->debug.debug_level++;
|
|
break;
|
|
case 'f':
|
|
opt->force++;
|
|
break;
|
|
case 909:
|
|
set_cmd(CMD_FILEINFO);
|
|
break;
|
|
case 'h':
|
|
case 'H':
|
|
case '?':
|
|
set_cmd(CMD_HELP);
|
|
break;
|
|
case 'h' + 256:
|
|
#if 1
|
|
if (!acc_isatty(STDOUT_FILENO)) {
|
|
/* according to GNU standards */
|
|
set_term(stdout);
|
|
opt->console = CON_FILE;
|
|
}
|
|
#endif
|
|
show_help(1);
|
|
e_exit(EXIT_OK);
|
|
break;
|
|
case 'i':
|
|
opt->info_mode++;
|
|
break;
|
|
case 'l':
|
|
set_cmd(CMD_LIST);
|
|
break;
|
|
case 'L':
|
|
set_cmd(CMD_LICENSE);
|
|
break;
|
|
case 'o':
|
|
set_output_name(mfx_optarg, 1);
|
|
break;
|
|
case 'q':
|
|
opt->verbose = (opt->verbose > 1 ? 1 : opt->verbose - 1);
|
|
break;
|
|
case 't':
|
|
set_cmd(CMD_TEST);
|
|
break;
|
|
case 'v':
|
|
opt->verbose = (opt->verbose < 3 ? 3 : opt->verbose + 1);
|
|
break;
|
|
case 'V':
|
|
set_cmd(CMD_VERSION);
|
|
break;
|
|
case 'V' + 256:
|
|
/* according to GNU standards */
|
|
set_term(stdout);
|
|
opt->console = CON_FILE;
|
|
show_version(0);
|
|
e_exit(EXIT_OK);
|
|
break;
|
|
|
|
// method
|
|
case 702:
|
|
opt->method_nrv2b_seen = true;
|
|
if (!set_method(M_NRV2B_LE32, -1))
|
|
e_method(M_NRV2B_LE32, opt->level);
|
|
break;
|
|
case 704:
|
|
opt->method_nrv2d_seen = true;
|
|
if (!set_method(M_NRV2D_LE32, -1))
|
|
e_method(M_NRV2D_LE32, opt->level);
|
|
break;
|
|
case 705:
|
|
opt->method_nrv2e_seen = true;
|
|
if (!set_method(M_NRV2E_LE32, -1))
|
|
e_method(M_NRV2E_LE32, opt->level);
|
|
break;
|
|
case 721:
|
|
opt->method_lzma_seen = true;
|
|
opt->all_methods_use_lzma = true;
|
|
if (!set_method(M_LZMA, -1))
|
|
e_method(M_LZMA, opt->level);
|
|
break;
|
|
case 722:
|
|
opt->method_lzma_seen = false;
|
|
opt->all_methods_use_lzma = false;
|
|
if (M_IS_LZMA(opt->method))
|
|
opt->method = -1;
|
|
break;
|
|
case 723:
|
|
opt->prefer_ucl = false;
|
|
break;
|
|
case 724:
|
|
opt->prefer_ucl = true;
|
|
break;
|
|
|
|
// compression level
|
|
case '1':
|
|
case '2':
|
|
case '3':
|
|
case '4':
|
|
case '5':
|
|
case '6':
|
|
case '7':
|
|
case '8':
|
|
case '9':
|
|
if (!set_method(-1, optc - '0'))
|
|
e_method(opt->method, optc);
|
|
break;
|
|
|
|
case 902: // --ultra-brute
|
|
opt->ultra_brute = true;
|
|
/* fallthrough */
|
|
case 901: // --brute
|
|
opt->all_methods = true;
|
|
opt->all_methods_use_lzma = true;
|
|
opt->method = -1;
|
|
opt->all_filters = true;
|
|
opt->filter = -1;
|
|
opt->crp.crp_ucl.m_size = 999999;
|
|
/* fallthrough */
|
|
case 900: // --best
|
|
if (!set_method(-1, 10))
|
|
e_method(opt->method, 10);
|
|
break;
|
|
|
|
// debug
|
|
case 542:
|
|
if (!mfx_optarg || strlen(mfx_optarg) != 4)
|
|
e_optarg(arg);
|
|
memcpy(opt->debug.fake_stub_version, mfx_optarg, 4);
|
|
break;
|
|
case 543:
|
|
if (!mfx_optarg || strlen(mfx_optarg) != 4)
|
|
e_optarg(arg);
|
|
memcpy(opt->debug.fake_stub_year, mfx_optarg, 4);
|
|
break;
|
|
case 544:
|
|
if (!mfx_optarg || !mfx_optarg[0])
|
|
e_optarg(arg);
|
|
opt->debug.dump_stub_loader = mfx_optarg;
|
|
break;
|
|
case 545:
|
|
opt->debug.disable_random_id = true;
|
|
break;
|
|
|
|
// mp (meta)
|
|
case 501:
|
|
getoptvar(&opt->mp_compress_task, 1, 999999, arg);
|
|
break;
|
|
case 502:
|
|
opt->mp_query_format = true;
|
|
break;
|
|
case 503:
|
|
opt->mp_query_num_tasks = true;
|
|
break;
|
|
|
|
// misc
|
|
case 512:
|
|
opt->console = CON_FILE;
|
|
break;
|
|
case 513:
|
|
opt->console = CON_ANSI_MONO;
|
|
break;
|
|
case 514:
|
|
opt->console = CON_ANSI_COLOR;
|
|
break;
|
|
case 516:
|
|
opt->no_progress = true;
|
|
break;
|
|
case 519:
|
|
opt->no_env = true;
|
|
break;
|
|
case 526:
|
|
opt->preserve_mode = false;
|
|
break;
|
|
case 527:
|
|
opt->preserve_ownership = false;
|
|
break;
|
|
case 528:
|
|
opt->preserve_timestamp = false;
|
|
break;
|
|
// compression settings
|
|
case 520: // --small
|
|
if (opt->small < 0)
|
|
opt->small = 0;
|
|
opt->small++;
|
|
break;
|
|
case 521: // --filter=
|
|
getoptvar(&opt->filter, 0, 255, arg);
|
|
opt->all_filters = false;
|
|
break;
|
|
case 522: // --no-filter
|
|
opt->filter = 0;
|
|
opt->all_filters = false;
|
|
opt->no_filter = true;
|
|
break;
|
|
case 523: // --all-filters
|
|
opt->all_filters = true;
|
|
opt->filter = -1;
|
|
break;
|
|
case 524: // --all-methods
|
|
opt->all_methods = true;
|
|
opt->all_methods_use_lzma = true;
|
|
opt->method = -1;
|
|
break;
|
|
case 525: // --exact
|
|
opt->exact = true;
|
|
break;
|
|
// compression runtime parameters
|
|
case 801:
|
|
getoptvar(&opt->crp.crp_ucl.c_flags, 0, 3, arg);
|
|
break;
|
|
case 802:
|
|
getoptvar(&opt->crp.crp_ucl.s_level, 0, 2, arg);
|
|
break;
|
|
case 803:
|
|
getoptvar(&opt->crp.crp_ucl.h_level, 0, 1, arg);
|
|
break;
|
|
case 804:
|
|
getoptvar(&opt->crp.crp_ucl.p_level, 0, 7, arg);
|
|
break;
|
|
case 805:
|
|
getoptvar(&opt->crp.crp_ucl.max_offset, 256u, ~0u, arg);
|
|
break;
|
|
case 806:
|
|
getoptvar(&opt->crp.crp_ucl.max_match, 16u, ~0u, arg);
|
|
break;
|
|
case 807:
|
|
getoptvar(&opt->crp.crp_ucl.m_size, 10000u, 999999u, arg);
|
|
break;
|
|
case 811:
|
|
getoptvar(&opt->crp.crp_lzma.pos_bits, arg);
|
|
break;
|
|
case 812:
|
|
getoptvar(&opt->crp.crp_lzma.lit_pos_bits, arg);
|
|
break;
|
|
case 813:
|
|
getoptvar(&opt->crp.crp_lzma.lit_context_bits, arg);
|
|
break;
|
|
case 814:
|
|
getoptvar(&opt->crp.crp_lzma.dict_size, arg);
|
|
break;
|
|
case 816:
|
|
getoptvar(&opt->crp.crp_lzma.num_fast_bytes, arg);
|
|
break;
|
|
case 821:
|
|
getoptvar(&opt->crp.crp_zlib.mem_level, arg);
|
|
break;
|
|
case 822:
|
|
getoptvar(&opt->crp.crp_zlib.window_bits, arg);
|
|
break;
|
|
case 823:
|
|
getoptvar(&opt->crp.crp_zlib.strategy, arg);
|
|
break;
|
|
// backup
|
|
case 'k':
|
|
opt->backup = 1;
|
|
break;
|
|
case 541:
|
|
if (opt->backup != 1) // do not overide '--backup'
|
|
opt->backup = 0;
|
|
break;
|
|
// overlay
|
|
case 551:
|
|
if (mfx_optarg && strcmp(mfx_optarg, "skip") == 0)
|
|
opt->overlay = opt->SKIP_OVERLAY;
|
|
else if (mfx_optarg && strcmp(mfx_optarg, "copy") == 0)
|
|
opt->overlay = opt->COPY_OVERLAY;
|
|
else if (mfx_optarg && strcmp(mfx_optarg, "strip") == 0)
|
|
opt->overlay = opt->STRIP_OVERLAY;
|
|
else
|
|
e_optarg(arg);
|
|
break;
|
|
case 552:
|
|
opt->overlay = opt->SKIP_OVERLAY;
|
|
break;
|
|
case 553:
|
|
opt->overlay = opt->COPY_OVERLAY;
|
|
break;
|
|
case 554:
|
|
opt->overlay = opt->STRIP_OVERLAY;
|
|
break;
|
|
// CPU
|
|
case 560:
|
|
if (mfx_optarg && strcmp(mfx_optarg, "8086") == 0)
|
|
opt->cpu = opt->CPU_8086;
|
|
else if (mfx_optarg && strcmp(mfx_optarg, "386") == 0)
|
|
opt->cpu = opt->CPU_386;
|
|
else if (mfx_optarg && strcmp(mfx_optarg, "486") == 0)
|
|
opt->cpu = opt->CPU_486;
|
|
else
|
|
e_optarg(arg);
|
|
break;
|
|
case 561:
|
|
opt->cpu = opt->CPU_8086;
|
|
break;
|
|
case 563:
|
|
opt->cpu = opt->CPU_386;
|
|
break;
|
|
case 564:
|
|
opt->cpu = opt->CPU_486;
|
|
break;
|
|
//
|
|
case 600:
|
|
opt->dos_exe.force_stub = true;
|
|
break;
|
|
case 601:
|
|
opt->dos_exe.no_reloc = true;
|
|
break;
|
|
case 610:
|
|
opt->djgpp2_coff.coff = true;
|
|
break;
|
|
case 620:
|
|
opt->watcom_le.le = true;
|
|
break;
|
|
case 630:
|
|
opt->win32_pe.compress_exports = 1;
|
|
if (mfx_optarg && mfx_optarg[0])
|
|
getoptvar(&opt->win32_pe.compress_exports, 0, 1, arg);
|
|
// printf("compress_exports: %d\n", opt->win32_pe.compress_exports);
|
|
break;
|
|
case 631:
|
|
opt->win32_pe.compress_icons = 1;
|
|
if (mfx_optarg && mfx_optarg[0])
|
|
getoptvar(&opt->win32_pe.compress_icons, 0, 3, arg);
|
|
// printf("compress_icons: %d\n", opt->win32_pe.compress_icons);
|
|
break;
|
|
case 632:
|
|
opt->win32_pe.compress_resources = 1;
|
|
if (mfx_optarg && mfx_optarg[0])
|
|
getoptvar(&opt->win32_pe.compress_resources, 0, 1, arg);
|
|
// printf("compress_resources: %d\n", opt->win32_pe.compress_resources);
|
|
break;
|
|
case 633:
|
|
// opt->win32_pe.strip_loadconf - OBSOLETE - IGNORED
|
|
break;
|
|
case 634:
|
|
opt->win32_pe.strip_relocs = 1;
|
|
if (mfx_optarg && mfx_optarg[0])
|
|
getoptvar(&opt->win32_pe.strip_relocs, 0, 1, arg);
|
|
// printf("strip_relocs: %d\n", opt->win32_pe.strip_relocs);
|
|
break;
|
|
case 635:
|
|
if (!mfx_optarg || !mfx_optarg[0])
|
|
e_optarg(arg);
|
|
opt->win32_pe.keep_resource = mfx_optarg;
|
|
break;
|
|
case 650:
|
|
opt->atari_tos.split_segments = true;
|
|
break;
|
|
case 660:
|
|
getoptvar(&opt->o_unix.blocksize, 8192u, ~0u, arg);
|
|
break;
|
|
case 661:
|
|
opt->o_unix.force_execve = true;
|
|
break;
|
|
case 663:
|
|
opt->o_unix.is_ptinterp = true;
|
|
break;
|
|
case 664:
|
|
opt->o_unix.use_ptinterp = true;
|
|
break;
|
|
case 665:
|
|
opt->o_unix.make_ptinterp = true;
|
|
break;
|
|
case 666: // Linux
|
|
opt->o_unix.osabi0 = Elf32_Ehdr::ELFOSABI_LINUX;
|
|
break;
|
|
case 667: // FreeBSD
|
|
opt->o_unix.osabi0 = Elf32_Ehdr::ELFOSABI_FREEBSD;
|
|
break;
|
|
case 668: // NetBSD
|
|
opt->o_unix.osabi0 = Elf32_Ehdr::ELFOSABI_NETBSD;
|
|
break;
|
|
case 669: // OpenBSD
|
|
opt->o_unix.osabi0 = Elf32_Ehdr::ELFOSABI_OPENBSD;
|
|
break;
|
|
case 670:
|
|
opt->ps1_exe.boot_only = true;
|
|
break;
|
|
case 671:
|
|
opt->ps1_exe.no_align = true;
|
|
opt->ps1_exe.boot_only = false;
|
|
break;
|
|
case 672:
|
|
opt->ps1_exe.do_8bit = true;
|
|
break;
|
|
case 673:
|
|
opt->ps1_exe.do_8mib = false;
|
|
break;
|
|
case 674:
|
|
opt->o_unix.unmap_all_pages = true; // val ?
|
|
break;
|
|
case 675:
|
|
opt->o_unix.preserve_build_id = true;
|
|
break;
|
|
case 676:
|
|
opt->o_unix.android_shlib = true;
|
|
break;
|
|
case 677:
|
|
opt->o_unix.force_pie = true;
|
|
break;
|
|
|
|
case '\0':
|
|
return -1;
|
|
case ':':
|
|
return -2;
|
|
default:
|
|
fprintf(stderr, "%s: internal error in getopt (%d)\n", argv0, optc);
|
|
return -3;
|
|
}
|
|
|
|
UNUSED(i);
|
|
return 0;
|
|
}
|
|
|
|
static int get_options(int argc, char **argv) {
|
|
constexpr int *N = nullptr;
|
|
|
|
static const struct mfx_option longopts[] = {
|
|
// commands
|
|
{"best", 0x10, N, 900}, // compress best
|
|
{"brute", 0x10, N, 901}, // compress best, brute force
|
|
{"ultra-brute", 0x10, N, 902}, // compress best, brute force
|
|
{"decompress", 0, N, 'd'}, // decompress
|
|
{"fast", 0x10, N, '1'}, // compress faster
|
|
{"fileinfo", 0x10, N, 909}, // display info about file
|
|
{"file-info", 0x10, N, 909}, // display info about file
|
|
{"help", 0, N, 'h' + 256}, // give help
|
|
{"license", 0, N, 'L'}, // display software license
|
|
{"list", 0, N, 'l'}, // list compressed exe
|
|
{"test", 0, N, 't'}, // test compressed file integrity
|
|
{"uncompress", 0, N, 'd'}, // decompress
|
|
{"version", 0, N, 'V' + 256}, // display version number
|
|
|
|
// options
|
|
{"force", 0, N, 'f'}, // force overwrite of output files
|
|
{"force-compress", 0, N, 'f'}, // and compression of suspicious files
|
|
{"info", 0, N, 'i'}, // info mode
|
|
{"no-env", 0x10, N, 519}, // no environment var
|
|
{"no-mode", 0x10, N, 526}, // do not preserve mode (permissions)
|
|
{"no-owner", 0x10, N, 527}, // do not preserve ownership
|
|
{"no-progress", 0, N, 516}, // no progress bar
|
|
{"no-time", 0x10, N, 528}, // do not preserve timestamp
|
|
{"output", 0x21, N, 'o'},
|
|
{"quiet", 0, N, 'q'}, // quiet mode
|
|
{"silent", 0, N, 'q'}, // quiet mode
|
|
#if 0
|
|
// FIXME: to_stdout doesn't work because of console code mess
|
|
{"stdout", 0x10, N, 517}, // write output on standard output
|
|
{"to-stdout", 0x10, N, 517}, // write output on standard output
|
|
#endif
|
|
{"verbose", 0, N, 'v'}, // verbose mode
|
|
|
|
// debug options
|
|
{"debug", 0x10, N, 'D'},
|
|
{"dump-stub-loader", 0x31, N, 544}, // for internal debugging
|
|
{"fake-stub-version", 0x31, N, 542}, // for internal debugging
|
|
{"fake-stub-year", 0x31, N, 543}, // for internal debugging
|
|
{"disable-random-id", 0x10, N, 545}, // for internal debugging
|
|
|
|
// backup options
|
|
{"backup", 0x10, N, 'k'},
|
|
{"keep", 0x10, N, 'k'},
|
|
{"no-backup", 0x10, N, 541},
|
|
|
|
// overlay options
|
|
{"overlay", 0x31, N, 551}, // --overlay=
|
|
{"skip-overlay", 0x10, N, 552},
|
|
{"no-overlay", 0x10, N, 552}, // old name
|
|
{"copy-overlay", 0x10, N, 553},
|
|
{"strip-overlay", 0x10, N, 554},
|
|
|
|
// CPU options
|
|
{"cpu", 0x31, N, 560}, // --cpu=
|
|
{"8086", 0x10, N, 561},
|
|
{"386", 0x10, N, 563},
|
|
{"486", 0x10, N, 564},
|
|
|
|
// color options
|
|
{"no-color", 0x10, N, 512},
|
|
{"mono", 0x10, N, 513},
|
|
{"color", 0x10, N, 514},
|
|
|
|
// compression method
|
|
{"nrv2b", 0x10, N, 702}, // --nrv2b
|
|
{"nrv2d", 0x10, N, 704}, // --nrv2d
|
|
{"nrv2e", 0x10, N, 705}, // --nrv2e
|
|
{"lzma", 0x10, N, 721}, // --lzma
|
|
{"no-lzma", 0x10, N, 722}, // disable all_methods_use_lzma
|
|
{"prefer-nrv", 0x10, N, 723},
|
|
{"prefer-ucl", 0x10, N, 724},
|
|
// compression settings
|
|
{"all-filters", 0x10, N, 523},
|
|
{"all-methods", 0x10, N, 524},
|
|
{"exact", 0x10, N, 525}, // user requires byte-identical decompression
|
|
{"filter", 0x31, N, 521}, // --filter=
|
|
{"no-filter", 0x10, N, 522},
|
|
{"small", 0x10, N, 520},
|
|
// compression runtime parameters
|
|
{"crp-nrv-cf", 0x31, N, 801},
|
|
{"crp-nrv-sl", 0x31, N, 802},
|
|
{"crp-nrv-hl", 0x31, N, 803},
|
|
{"crp-nrv-pl", 0x31, N, 804},
|
|
{"crp-nrv-mo", 0x31, N, 805},
|
|
{"crp-nrv-mm", 0x31, N, 806},
|
|
{"crp-nrv-ms", 0x31, N, 807},
|
|
{"crp-ucl-cf", 0x31, N, 801},
|
|
{"crp-ucl-sl", 0x31, N, 802},
|
|
{"crp-ucl-hl", 0x31, N, 803},
|
|
{"crp-ucl-pl", 0x31, N, 804},
|
|
{"crp-ucl-mo", 0x31, N, 805},
|
|
{"crp-ucl-mm", 0x31, N, 806},
|
|
{"crp-ucl-ms", 0x31, N, 807},
|
|
{"crp-lzma-pb", 0x31, N, 811},
|
|
{"crp-lzma-lp", 0x31, N, 812},
|
|
{"crp-lzma-lc", 0x31, N, 813},
|
|
{"crp-lzma-ds", 0x31, N, 814},
|
|
{"crp-lzma-fb", 0x31, N, 816},
|
|
{"crp-zlib-ml", 0x31, N, 821},
|
|
{"crp-zlib-wb", 0x31, N, 822},
|
|
{"crp-zlib-st", 0x31, N, 823},
|
|
// [deprecated - only for compatibility with UPX 2.0x]
|
|
{"crp-ms", 0x31, N, 807},
|
|
|
|
// atari/tos
|
|
{"split-segments", 0x10, N, 650},
|
|
// djgpp2/coff
|
|
{"coff", 0x10, N, 610}, // produce COFF output
|
|
// dos/com
|
|
// dos/exe
|
|
//{"force-stub", 0x10, 0, 600},
|
|
{"no-reloc", 0x10, N, 601}, // no reloc. record into packer dos/exe
|
|
// dos/sys
|
|
// unix
|
|
{"blocksize", 0x31, N, 660}, // --blocksize=
|
|
{"force-execve", 0x10, N, 661}, // force linux/386 execve format
|
|
{"is_ptinterp", 0x10, N, 663}, // linux/elf386 PT_INTERP program
|
|
{"use_ptinterp", 0x10, N, 664}, // linux/elf386 PT_INTERP program
|
|
{"make_ptinterp", 0x10, N, 665}, // linux/elf386 PT_INTERP program
|
|
{"Linux", 0x10, N, 666},
|
|
{"linux", 0x10, N, 666},
|
|
{"FreeBSD", 0x10, N, 667},
|
|
{"freebsd", 0x10, N, 667},
|
|
{"NetBSD", 0x10, N, 668},
|
|
{"netbsd", 0x10, N, 668},
|
|
{"OpenBSD", 0x10, N, 669},
|
|
{"openbsd", 0x10, N, 669},
|
|
{"unmap-all-pages", 0x10, N, 674}, // linux /proc/self/exe vanishes
|
|
{"preserve-build-id", 0, N, 675},
|
|
{"android-shlib", 0, N, 676},
|
|
{"force-pie", 0, N, 677},
|
|
// watcom/le
|
|
{"le", 0x10, N, 620}, // produce LE output
|
|
// win32/pe
|
|
{"compress-exports", 2, N, 630},
|
|
{"compress-icons", 2, N, 631},
|
|
{"compress-resources", 2, N, 632},
|
|
{"strip-loadconf", 0x12, N, 633}, // OBSOLETE - IGNORED
|
|
{"strip-relocs", 0x12, N, 634},
|
|
{"keep-resource", 0x31, N, 635},
|
|
// ps1/exe
|
|
{"boot-only", 0x10, N, 670},
|
|
{"no-align", 0x10, N, 671},
|
|
{"8-bit", 0x10, N, 672},
|
|
{"8mib-ram", 0x10, N, 673},
|
|
{"8mb-ram", 0x10, N, 673},
|
|
|
|
// mp (meta) options
|
|
{"mp-compress-task", 0x31, N, 501},
|
|
{"mp-query-format", 0x10, N, 502},
|
|
{"mp-query-num-tasks", 0x10, N, 503},
|
|
|
|
{nullptr, 0, nullptr, 0}
|
|
};
|
|
|
|
int optc, longind;
|
|
char shortopts[256];
|
|
|
|
prepare_shortopts(shortopts, "123456789hH?V", longopts),
|
|
acc_getopt_init(&mfx_getopt, 1, argc, argv);
|
|
mfx_getopt.progname = progname;
|
|
mfx_getopt.opterr = handle_opterr;
|
|
opt->o_unix.osabi0 = Elf32_Ehdr::ELFOSABI_LINUX;
|
|
while ((optc = acc_getopt(&mfx_getopt, shortopts, longopts, &longind)) >= 0) {
|
|
if (do_option(optc, argv[mfx_optind - 1]) != 0)
|
|
e_usage();
|
|
}
|
|
|
|
return mfx_optind;
|
|
}
|
|
|
|
#if defined(OPTIONS_VAR)
|
|
static void get_envoptions(int argc, char **argv) {
|
|
constexpr int *N = nullptr;
|
|
|
|
/* only some options are allowed in the environment variable */
|
|
|
|
static const struct mfx_option longopts[] = {
|
|
// commands
|
|
{"best", 0x10, N, 900}, // compress best
|
|
{"brute", 0x10, N, 901}, // compress best, brute force
|
|
{"ultra-brute", 0x10, N, 902}, // compress best, brute force
|
|
{"fast", 0x10, N, '1'}, // compress faster
|
|
|
|
// options
|
|
{"info", 0, N, 'i'}, // info mode
|
|
{"no-progress", 0, N, 516}, // no progress bar
|
|
{"quiet", 0, N, 'q'}, // quiet mode
|
|
{"silent", 0, N, 'q'}, // quiet mode
|
|
{"verbose", 0, N, 'v'}, // verbose mode
|
|
|
|
// debug options
|
|
{"disable-random-id", 0x10, N, 545}, // for internal debugging
|
|
|
|
// backup options
|
|
{"backup", 0x10, N, 'k'},
|
|
{"keep", 0x10, N, 'k'},
|
|
{"no-backup", 0x10, N, 541},
|
|
|
|
// overlay options
|
|
{"overlay", 0x31, N, 551}, // --overlay=
|
|
{"skip-overlay", 0x10, N, 552},
|
|
{"no-overlay", 0x10, N, 552}, // old name
|
|
{"copy-overlay", 0x10, N, 553},
|
|
{"strip-overlay", 0x10, N, 554},
|
|
|
|
// CPU options
|
|
{"cpu", 0x31, N, 560}, // --cpu=
|
|
{"8086", 0x10, N, 561},
|
|
{"386", 0x10, N, 563},
|
|
{"486", 0x10, N, 564},
|
|
|
|
// color options
|
|
{"no-color", 0x10, N, 512},
|
|
{"mono", 0x10, N, 513},
|
|
{"color", 0x10, N, 514},
|
|
|
|
// compression settings
|
|
{"exact", 0x10, N, 525}, // user requires byte-identical decompression
|
|
|
|
// compression method
|
|
{"nrv2b", 0x10, N, 702}, // --nrv2b
|
|
{"nrv2d", 0x10, N, 704}, // --nrv2d
|
|
{"nrv2e", 0x10, N, 705}, // --nrv2e
|
|
{"lzma", 0x10, N, 721}, // --lzma
|
|
{"no-lzma", 0x10, N, 722}, // disable all_methods_use_lzma
|
|
{"prefer-nrv", 0x10, N, 723},
|
|
{"prefer-ucl", 0x10, N, 724},
|
|
// compression settings
|
|
// compression runtime parameters
|
|
|
|
// win32/pe
|
|
{"compress-exports", 2, N, 630},
|
|
{"compress-icons", 2, N, 631},
|
|
{"compress-resources", 2, N, 632},
|
|
{"strip-loadconf", 0x12, N, 633}, // OBSOLETE - IGNORED
|
|
{"strip-relocs", 0x12, N, 634},
|
|
{"keep-resource", 0x31, N, 635},
|
|
|
|
{nullptr, 0, nullptr, 0}};
|
|
|
|
char *env, *p;
|
|
const char *var;
|
|
int i, optc, longind;
|
|
int targc;
|
|
char **targv = nullptr;
|
|
static const char sep[] = " \t";
|
|
char shortopts[256];
|
|
|
|
var = getenv(OPTIONS_VAR);
|
|
if (var == nullptr || !var[0])
|
|
return;
|
|
env = strdup(var);
|
|
if (env == nullptr)
|
|
return;
|
|
|
|
/* count arguments */
|
|
for (p = env, targc = 1;;) {
|
|
while (*p && strchr(sep, *p))
|
|
p++;
|
|
if (*p == '\0')
|
|
break;
|
|
targc++;
|
|
while (*p && !strchr(sep, *p))
|
|
p++;
|
|
if (*p == '\0')
|
|
break;
|
|
p++;
|
|
}
|
|
|
|
/* alloc temp argv */
|
|
if (targc > 1)
|
|
targv = (char **) calloc(targc + 1, sizeof(char *));
|
|
if (targv == nullptr) {
|
|
free(env);
|
|
return;
|
|
}
|
|
|
|
/* fill temp argv */
|
|
targv[0] = argv[0];
|
|
for (p = env, targc = 1;;) {
|
|
while (*p && strchr(sep, *p))
|
|
p++;
|
|
if (*p == '\0')
|
|
break;
|
|
targv[targc++] = p;
|
|
while (*p && !strchr(sep, *p))
|
|
p++;
|
|
if (*p == '\0')
|
|
break;
|
|
*p++ = '\0';
|
|
}
|
|
targv[targc] = nullptr;
|
|
|
|
/* check that only options are in temp argv */
|
|
for (i = 1; i < targc; i++)
|
|
if (targv[i][0] != '-' || !targv[i][1] || strcmp(targv[i], "--") == 0)
|
|
e_envopt(targv[i]);
|
|
|
|
/* handle options */
|
|
prepare_shortopts(shortopts, "123456789", longopts);
|
|
acc_getopt_init(&mfx_getopt, 1, targc, targv);
|
|
mfx_getopt.progname = progname;
|
|
mfx_getopt.opterr = handle_opterr;
|
|
while ((optc = acc_getopt(&mfx_getopt, shortopts, longopts, &longind)) >= 0) {
|
|
if (do_option(optc, targv[mfx_optind - 1]) != 0)
|
|
e_envopt(nullptr);
|
|
}
|
|
|
|
if (mfx_optind < targc)
|
|
e_envopt(targv[mfx_optind]);
|
|
|
|
/* clean up */
|
|
free(targv);
|
|
free(env);
|
|
UNUSED(argc);
|
|
}
|
|
#endif /* defined(OPTIONS_VAR) */
|
|
|
|
static void first_options(int argc, char **argv) {
|
|
int i;
|
|
int n = argc;
|
|
|
|
for (i = 1; i < n; i++) {
|
|
if (strcmp(argv[i], "--") == 0) {
|
|
n = i;
|
|
break;
|
|
}
|
|
if (strcmp(argv[i], "--version") == 0)
|
|
do_option('V' + 256, argv[i]);
|
|
}
|
|
for (i = 1; i < n; i++)
|
|
if (strcmp(argv[i], "--help") == 0)
|
|
do_option('h' + 256, argv[i]);
|
|
for (i = 1; i < n; i++)
|
|
if (strcmp(argv[i], "--no-env") == 0)
|
|
do_option(519, argv[i]);
|
|
}
|
|
|
|
/*************************************************************************
|
|
// assert a sane architecture and compiler
|
|
**************************************************************************/
|
|
|
|
template <class T>
|
|
struct TestBELE {
|
|
__acc_static_noinline bool test(void) {
|
|
COMPILE_TIME_ASSERT_ALIGNED1(T)
|
|
struct alignas(1) test1_t {
|
|
char a;
|
|
T b;
|
|
};
|
|
struct alignas(1) test2_t {
|
|
char a;
|
|
T b[3];
|
|
};
|
|
test1_t t1[7];
|
|
UNUSED(t1);
|
|
test2_t t2[7];
|
|
UNUSED(t2);
|
|
COMPILE_TIME_ASSERT(sizeof(test1_t) == 1 + sizeof(T))
|
|
COMPILE_TIME_ASSERT_ALIGNED1(test1_t)
|
|
COMPILE_TIME_ASSERT(sizeof(t1) == 7 + 7 * sizeof(T))
|
|
COMPILE_TIME_ASSERT(sizeof(test2_t) == 1 + 3 * sizeof(T))
|
|
COMPILE_TIME_ASSERT_ALIGNED1(test2_t)
|
|
COMPILE_TIME_ASSERT(sizeof(t2) == 7 + 21 * sizeof(T))
|
|
#if defined(__acc_alignof)
|
|
COMPILE_TIME_ASSERT(__acc_alignof(t1) == 1)
|
|
COMPILE_TIME_ASSERT(__acc_alignof(t2) == 1)
|
|
#endif
|
|
#if 1
|
|
T allbits;
|
|
allbits = 0;
|
|
allbits += 1;
|
|
allbits -= 2;
|
|
T v1;
|
|
v1 = 1;
|
|
v1 *= 2;
|
|
v1 -= 1;
|
|
T v2;
|
|
v2 = 1;
|
|
assert((v1 == v2));
|
|
assert(!(v1 != v2));
|
|
assert((v1 <= v2));
|
|
assert((v1 >= v2));
|
|
assert(!(v1 < v2));
|
|
assert(!(v1 > v2));
|
|
v2 ^= allbits;
|
|
assert(!(v1 == v2));
|
|
assert((v1 != v2));
|
|
assert((v1 <= v2));
|
|
assert(!(v1 >= v2));
|
|
assert((v1 < v2));
|
|
assert(!(v1 > v2));
|
|
v2 += 2;
|
|
assert(v1 == 1);
|
|
assert(v2 == 0);
|
|
v1 <<= 1;
|
|
v1 |= v2;
|
|
v1 >>= 1;
|
|
v2 &= v1;
|
|
v2 /= v1;
|
|
v2 *= v1;
|
|
assert(v1 == 1);
|
|
assert(v2 == 0);
|
|
if ((v1 ^ v2) != 1)
|
|
return false;
|
|
#endif
|
|
return true;
|
|
}
|
|
};
|
|
|
|
template <class A, class B>
|
|
struct TestNoAliasingStruct {
|
|
__acc_static_noinline bool test(A *a, B *b) {
|
|
*a = 0;
|
|
*b = 0;
|
|
*b -= 3;
|
|
return *a != 0;
|
|
}
|
|
};
|
|
template <class A, class B>
|
|
__acc_static_forceinline bool testNoAliasing(A *a, B *b) {
|
|
return TestNoAliasingStruct<A, B>::test(a, b);
|
|
}
|
|
template <class T>
|
|
struct TestIntegerWrap {
|
|
static inline bool inc(T x) { return x + 1 > x; }
|
|
static inline bool dec(T x) { return x - 1 < x; }
|
|
};
|
|
|
|
#define ACC_WANT_ACC_CHK_CH 1
|
|
#undef ACCCHK_ASSERT
|
|
#include "miniacc.h"
|
|
|
|
void upx_compiler_sanity_check(void) {
|
|
#define ACC_WANT_ACC_CHK_CH 1
|
|
#undef ACCCHK_ASSERT
|
|
#define ACCCHK_ASSERT(expr) ACC_COMPILE_TIME_ASSERT(expr)
|
|
#include "miniacc.h"
|
|
#undef ACCCHK_ASSERT
|
|
|
|
COMPILE_TIME_ASSERT(sizeof(char) == 1)
|
|
COMPILE_TIME_ASSERT(sizeof(short) == 2)
|
|
COMPILE_TIME_ASSERT(sizeof(int) == 4)
|
|
COMPILE_TIME_ASSERT(sizeof(long) >= 4)
|
|
COMPILE_TIME_ASSERT(sizeof(void *) >= 4)
|
|
|
|
COMPILE_TIME_ASSERT(sizeof(BE16) == 2)
|
|
COMPILE_TIME_ASSERT(sizeof(BE32) == 4)
|
|
COMPILE_TIME_ASSERT(sizeof(BE64) == 8)
|
|
COMPILE_TIME_ASSERT(sizeof(LE16) == 2)
|
|
COMPILE_TIME_ASSERT(sizeof(LE32) == 4)
|
|
COMPILE_TIME_ASSERT(sizeof(LE64) == 8)
|
|
|
|
COMPILE_TIME_ASSERT_ALIGNED1(BE16)
|
|
COMPILE_TIME_ASSERT_ALIGNED1(BE32)
|
|
COMPILE_TIME_ASSERT_ALIGNED1(BE64)
|
|
COMPILE_TIME_ASSERT_ALIGNED1(LE16)
|
|
COMPILE_TIME_ASSERT_ALIGNED1(LE32)
|
|
COMPILE_TIME_ASSERT_ALIGNED1(LE64)
|
|
|
|
COMPILE_TIME_ASSERT(sizeof(UPX_VERSION_STRING4) == 4 + 1)
|
|
assert(strlen(UPX_VERSION_STRING4) == 4);
|
|
COMPILE_TIME_ASSERT(sizeof(UPX_VERSION_YEAR) == 4 + 1)
|
|
assert(strlen(UPX_VERSION_YEAR) == 4);
|
|
assert(memcmp(UPX_VERSION_DATE_ISO, UPX_VERSION_YEAR, 4) == 0);
|
|
assert(memcmp(&UPX_VERSION_DATE[sizeof(UPX_VERSION_DATE) - 1 - 4], UPX_VERSION_YEAR, 4) == 0);
|
|
if (gitrev[0]) {
|
|
size_t revlen = strlen(gitrev);
|
|
if (strncmp(gitrev, "ERROR", 5) == 0) {
|
|
assert(revlen == 5 || revlen == 6);
|
|
} else {
|
|
assert(revlen == 12 || revlen == 13);
|
|
}
|
|
if (revlen == 6 || revlen == 13) {
|
|
assert(gitrev[revlen - 1] == '+');
|
|
}
|
|
}
|
|
assert(UPX_RSIZE_MAX_MEM == 805306368);
|
|
|
|
#if 1
|
|
assert(TestBELE<LE16>::test());
|
|
assert(TestBELE<LE32>::test());
|
|
assert(TestBELE<LE64>::test());
|
|
assert(TestBELE<BE16>::test());
|
|
assert(TestBELE<BE32>::test());
|
|
assert(TestBELE<BE64>::test());
|
|
{
|
|
alignas(16) static const unsigned char dd[32] = {
|
|
0, 0, 0, 0, 0, 0, 0, 0xff, 0xfe, 0xfd, 0xfc, 0xfb, 0xfa, 0xf9, 0xf8, 0,
|
|
0, 0, 0, 0x7f, 0x7e, 0x7d, 0x7c, 0x7b, 0x7a, 0x79, 0x78, 0, 0, 0, 0, 0};
|
|
const unsigned char *d;
|
|
const N_BELE_RTP::AbstractPolicy *bele;
|
|
d = dd + 7;
|
|
assert(upx_adler32(d, 4) == 0x09f003f7);
|
|
assert(upx_adler32(d, 4, 0) == 0x09ec03f6);
|
|
assert(upx_adler32(d, 4, 1) == 0x09f003f7);
|
|
bele = &N_BELE_RTP::be_policy;
|
|
assert(get_be16(d) == 0xfffe);
|
|
assert(bele->get16(d) == 0xfffe);
|
|
assert(get_be16_signed(d) == -2);
|
|
assert(get_be24(d) == 0xfffefd);
|
|
assert(bele->get24(d) == 0xfffefd);
|
|
assert(get_be24_signed(d) == -259);
|
|
assert(get_be32(d) == 0xfffefdfc);
|
|
assert(bele->get32(d) == 0xfffefdfc);
|
|
assert(get_be32_signed(d) == -66052);
|
|
bele = &N_BELE_RTP::le_policy;
|
|
assert(get_le16(d) == 0xfeff);
|
|
assert(bele->get16(d) == 0xfeff);
|
|
assert(get_le16_signed(d) == -257);
|
|
assert(get_le24(d) == 0xfdfeff);
|
|
assert(bele->get24(d) == 0xfdfeff);
|
|
assert(get_le24_signed(d) == -131329);
|
|
assert(get_le32(d) == 0xfcfdfeff);
|
|
assert(bele->get32(d) == 0xfcfdfeff);
|
|
assert(get_le32_signed(d) == -50462977);
|
|
assert(get_le64_signed(d) == -506097522914230529LL);
|
|
assert(find_be16(d, 2, 0xfffe) == 0);
|
|
assert(find_le16(d, 2, 0xfeff) == 0);
|
|
assert(find_be32(d, 4, 0xfffefdfc) == 0);
|
|
assert(find_le32(d, 4, 0xfcfdfeff) == 0);
|
|
d += 12;
|
|
assert(get_be16_signed(d) == 32638);
|
|
assert(get_be24_signed(d) == 8355453);
|
|
assert(get_be32_signed(d) == 2138996092);
|
|
assert(get_be64_signed(d) == 9186918263483431288LL);
|
|
}
|
|
{
|
|
unsigned dd;
|
|
void *const d = ⅆ
|
|
dd = ne32_to_le32(0xf7f6f5f4);
|
|
assert(get_le26(d) == 0x03f6f5f4);
|
|
set_le26(d, 0);
|
|
assert(get_le26(d) == 0);
|
|
assert(dd == ne32_to_le32(0xf4000000));
|
|
set_le26(d, 0xff020304);
|
|
assert(get_le26(d) == 0x03020304);
|
|
assert(dd == ne32_to_le32(0xf7020304));
|
|
}
|
|
#endif
|
|
union {
|
|
short v_short;
|
|
int v_int;
|
|
long v_long;
|
|
long long v_llong;
|
|
BE16 b16;
|
|
BE32 b32;
|
|
BE64 b64;
|
|
LE16 l16;
|
|
LE32 l32;
|
|
LE64 l64;
|
|
} u;
|
|
assert(testNoAliasing(&u.v_short, &u.b32));
|
|
assert(testNoAliasing(&u.v_short, &u.l32));
|
|
assert(testNoAliasing(&u.v_int, &u.b64));
|
|
assert(testNoAliasing(&u.v_int, &u.l64));
|
|
#if 1
|
|
// check working -fno-strict-aliasing
|
|
assert(testNoAliasing(&u.v_short, &u.v_int));
|
|
assert(testNoAliasing(&u.v_int, &u.v_long));
|
|
assert(testNoAliasing(&u.v_int, &u.v_llong));
|
|
assert(testNoAliasing(&u.v_long, &u.v_llong));
|
|
#endif
|
|
|
|
assert(TestIntegerWrap<int>::inc(0));
|
|
assert(!TestIntegerWrap<int>::inc(INT_MAX));
|
|
assert(TestIntegerWrap<int>::dec(0));
|
|
assert(!TestIntegerWrap<int>::dec(INT_MIN));
|
|
assert(TestIntegerWrap<unsigned>::inc(0));
|
|
assert(!TestIntegerWrap<unsigned>::inc(UINT_MAX));
|
|
assert(TestIntegerWrap<unsigned>::dec(1));
|
|
assert(!TestIntegerWrap<unsigned>::dec(0));
|
|
}
|
|
|
|
/*************************************************************************
|
|
// main entry point
|
|
**************************************************************************/
|
|
|
|
int upx_main(int argc, char *argv[]) {
|
|
int i;
|
|
static char default_argv0[] = "upx";
|
|
|
|
upx_compiler_sanity_check();
|
|
// Allow serial re-use of upx_main() as a subroutine
|
|
done_output_name = 0;
|
|
opt->reset();
|
|
|
|
if (!argv[0] || !argv[0][0])
|
|
argv[0] = default_argv0;
|
|
argv0 = argv[0];
|
|
#if (ACC_OS_CYGWIN || ACC_OS_DOS16 || ACC_OS_DOS32 || ACC_OS_EMX || ACC_OS_TOS || ACC_OS_WIN16 || \
|
|
ACC_OS_WIN32 || ACC_OS_WIN64)
|
|
{
|
|
char *prog = fn_basename(argv0);
|
|
char *p;
|
|
bool allupper = true;
|
|
for (p = prog; *p; p++)
|
|
if (islower((unsigned char) *p))
|
|
allupper = false;
|
|
if (allupper)
|
|
fn_strlwr(prog);
|
|
if (p - prog > 4) {
|
|
p -= 4;
|
|
if (fn_strcmp(p, ".exe") == 0 || fn_strcmp(p, ".ttp") == 0)
|
|
*p = 0;
|
|
}
|
|
progname = prog;
|
|
}
|
|
#else
|
|
progname = fn_basename(argv0);
|
|
#endif
|
|
while (progname[0] == '.' && progname[1] == '/' && progname[2])
|
|
progname += 2;
|
|
|
|
set_term(stderr);
|
|
|
|
if (upx_ucl_init() != 0) {
|
|
show_head();
|
|
fprintf(stderr, "ucl_init() failed - check your UCL installation !\n");
|
|
if (UCL_VERSION != ucl_version())
|
|
fprintf(stderr, "library version conflict (%lx, %lx) - check your UCL installation !\n",
|
|
(long) UCL_VERSION, (long) ucl_version());
|
|
e_exit(EXIT_INIT);
|
|
}
|
|
assert(upx_lzma_init() == 0);
|
|
assert(upx_zlib_init() == 0);
|
|
#if (WITH_NRV)
|
|
assert(upx_nrv_init() == 0);
|
|
#endif
|
|
|
|
/* get options */
|
|
first_options(argc, argv);
|
|
#if defined(OPTIONS_VAR)
|
|
if (!opt->no_env)
|
|
get_envoptions(argc, argv);
|
|
#endif
|
|
i = get_options(argc, argv);
|
|
assert(i <= argc);
|
|
|
|
set_term(nullptr);
|
|
switch (opt->cmd) {
|
|
case CMD_NONE:
|
|
/* default - compress */
|
|
set_cmd(CMD_COMPRESS);
|
|
break;
|
|
case CMD_COMPRESS:
|
|
break;
|
|
case CMD_DECOMPRESS:
|
|
break;
|
|
case CMD_TEST:
|
|
break;
|
|
case CMD_LIST:
|
|
break;
|
|
case CMD_FILEINFO:
|
|
break;
|
|
case CMD_LICENSE:
|
|
show_license();
|
|
e_exit(EXIT_OK);
|
|
break;
|
|
case CMD_HELP:
|
|
show_help(1);
|
|
e_exit(EXIT_OK);
|
|
break;
|
|
case CMD_VERSION:
|
|
show_version(1);
|
|
e_exit(EXIT_OK);
|
|
break;
|
|
default:
|
|
/* ??? */
|
|
break;
|
|
}
|
|
|
|
/* check options */
|
|
if (argc == 1)
|
|
e_help();
|
|
set_term(stderr);
|
|
check_options(i, argc);
|
|
int num_files = argc - i;
|
|
if (num_files < 1) {
|
|
if (opt->verbose >= 2)
|
|
e_help();
|
|
else
|
|
e_usage();
|
|
}
|
|
|
|
/* start work */
|
|
set_term(stdout);
|
|
if (do_files(i, argc, argv) != 0)
|
|
return exit_code;
|
|
|
|
if (gitrev[0]) {
|
|
bool warn = true;
|
|
const char *ee = getenv("UPX_DISABLE_GITREV_WARNING");
|
|
if (ee && ee[0] && strcmp(ee, "1") == 0)
|
|
warn = false;
|
|
if (warn) {
|
|
FILE *f = stdout;
|
|
int fg = con_fg(f, FG_RED);
|
|
con_fprintf(
|
|
f, "\nWARNING: this is an unstable beta version - use for testing only! Really.\n");
|
|
fg = con_fg(f, fg);
|
|
UNUSED(fg);
|
|
}
|
|
}
|
|
|
|
return exit_code;
|
|
}
|
|
|
|
/*************************************************************************
|
|
// real entry point
|
|
**************************************************************************/
|
|
|
|
#if !(WITH_GUI)
|
|
|
|
#if 1 && (ACC_OS_DOS32) && defined(__DJGPP__)
|
|
#include <crt0.h>
|
|
int _crt0_startup_flags = _CRT0_FLAG_UNIX_SBRK;
|
|
#endif
|
|
#if (ACC_ARCH_M68K && ACC_OS_TOS && ACC_CC_GNUC) && defined(__MINT__)
|
|
extern "C" {
|
|
extern long _stksize;
|
|
long _stksize = 256 * 1024L;
|
|
}
|
|
#endif
|
|
#if (ACC_OS_WIN32 || ACC_OS_WIN64) && (defined(__MINGW32__) || defined(__MINGW64__))
|
|
extern "C" {
|
|
extern int _dowildcard;
|
|
int _dowildcard = -1;
|
|
}
|
|
#endif
|
|
|
|
int __acc_cdecl_main main(int argc, char *argv[]) {
|
|
#if 0 && (ACC_OS_DOS32) && defined(__DJGPP__)
|
|
// LFN=n may cause problems with 2.03's _rename and mkdir under WinME
|
|
putenv("LFN=y");
|
|
#endif
|
|
#if (ACC_OS_WIN32 || ACC_OS_WIN64) && (ACC_CC_MSC) && defined(_WRITE_ABORT_MSG) && \
|
|
defined(_CALL_REPORTFAULT)
|
|
_set_abort_behavior(_WRITE_ABORT_MSG, _WRITE_ABORT_MSG | _CALL_REPORTFAULT);
|
|
#endif
|
|
acc_wildargv(&argc, &argv);
|
|
// srand((int) time(nullptr));
|
|
srand((int) clock());
|
|
|
|
#if defined(_WIN32) || 1
|
|
// runtime check that Win32/MinGW <stdio.h> works as expected
|
|
{
|
|
long long ll = argc < 0 ? 0 : -1;
|
|
unsigned long long llu = (unsigned long long) ll;
|
|
char buf[256];
|
|
snprintf(buf, sizeof(buf), ".%d.%ld.%lld.%u.%lu.%llu", -3, -2L, ll, 3U, 2LU, llu);
|
|
assert(strcmp(buf, ".-3.-2.-1.3.2.18446744073709551615") == 0);
|
|
}
|
|
#endif
|
|
|
|
int r = upx_main(argc, argv);
|
|
|
|
#if 0 && defined(__GLIBC__)
|
|
//malloc_stats();
|
|
#endif
|
|
return r;
|
|
}
|
|
|
|
#endif /* !(WITH_GUI) */
|
|
|
|
/* vim:set ts=4 sw=4 et: */
|