diff --git a/asm/directiv.dat b/asm/directiv.dat index 966494881..185568a6b 100644 --- a/asm/directiv.dat +++ b/asm/directiv.dat @@ -93,6 +93,7 @@ gprefix gsuffix lprefix lsuffix +limit ; --- Pragma operations subsections_via_symbols ; macho diff --git a/asm/error.c b/asm/error.c index 1f91cd788..3fdaa027c 100644 --- a/asm/error.c +++ b/asm/error.c @@ -1,6 +1,6 @@ /* ----------------------------------------------------------------------- * * - * Copyright 1996-2017 The NASM Authors - All Rights Reserved + * Copyright 1996-2018 The NASM Authors - All Rights Reserved * See the file AUTHORS included with the NASM distribution for * the specific copyright holders. * @@ -68,6 +68,7 @@ const struct warning warnings[ERR_WARN_ALL+1] = { {"unknown-pragma", "unknown %pragma facility or directive", false}, {"not-my-pragma", "%pragma not applicable to this compilation", false}, {"unknown-warning", "unknown warning in -W/-w or warning directive", false}, + {"negative-rep", "regative %rep count", true}, /* THIS ENTRY MUST COME LAST */ {"all", "all possible warnings", false} diff --git a/asm/eval.c b/asm/eval.c index 72d6a0e2b..582f95030 100644 --- a/asm/eval.c +++ b/asm/eval.c @@ -1,6 +1,6 @@ /* ----------------------------------------------------------------------- * * - * Copyright 1996-2017 The NASM Authors - All Rights Reserved + * Copyright 1996-2018 The NASM Authors - All Rights Reserved * See the file AUTHORS included with the NASM distribution for * the specific copyright holders. * @@ -72,6 +72,7 @@ static void *scpriv; static int *opflags; static struct eval_hints *hint; +static int deadman; /* @@ -769,6 +770,11 @@ static expr *expr6(int critical) bool rn_warn; const char *scope; + if (++deadman > nasm_limit[LIMIT_EVAL]) { + nasm_error(ERR_NONFATAL, "expression too long"); + return NULL; + } + switch (i) { case '-': i = scan(scpriv, tokval); @@ -954,6 +960,8 @@ expr *evaluate(scanner sc, void *scprivate, struct tokenval *tv, expr *e; expr *f = NULL; + deadman = 0; + hint = hints; if (hint) hint->type = EAH_NOHINT; diff --git a/asm/nasm.c b/asm/nasm.c index 6db5cce29..f7f02ac89 100644 --- a/asm/nasm.c +++ b/asm/nasm.c @@ -82,6 +82,7 @@ static void nasm_verror_gnu(int severity, const char *fmt, va_list args); static void nasm_verror_vc(int severity, const char *fmt, va_list args); static void nasm_verror_common(int severity, const char *fmt, va_list args); static void usage(void); +static void help(char xopt); static bool using_debug_info, opt_verbose_info; static const char *debug_format; @@ -153,6 +154,60 @@ static char *quote_for_pmake(const char *str); static char *quote_for_wmake(const char *str); static char *(*quote_for_make)(const char *) = quote_for_pmake; +/* + * Execution limits that can be set via a command-line option or %pragma + */ + +#define LIMIT_MAX_VAL (INT_MAX >> 1) /* Effectively unlimited */ + +int nasm_limit[LIMIT_MAX+1] = +{ LIMIT_MAX_VAL, 1000, 1000000, 1000000, 1000000 }; + +struct limit_info { + const char *name; + const char *help; +}; +static const struct limit_info limit_info[LIMIT_MAX+1] = { + { "passes", "total number of passes" }, + { "stalled-passes", "number of passes without forward progress" }, + { "macro-levels", "levels of macro expansion"}, + { "rep", "%rep count" }, + { "eval", "expression evaluation descent"} +}; + +enum directive_result nasm_set_limit(const char *limit, const char *valstr) +{ + int i; + int64_t val; + bool rn_error; + + for (i = 0; i <= LIMIT_MAX; i++) { + if (!nasm_stricmp(limit, limit_info[i].name)) + break; + } + if (i > LIMIT_MAX) { + nasm_error(ERR_WARNING|ERR_PASS1|ERR_WARN_UNKNOWN_PRAGMA, + "unknown limit: `%s'", limit); + return DIRR_ERROR; + } + + if (!nasm_stricmp(valstr, "unlimited")) { + val = LIMIT_MAX_VAL; + } else { + val = readnum(valstr, &rn_error); + if (rn_error || val < 0) { + nasm_error(ERR_WARNING|ERR_PASS1|ERR_WARN_BAD_PRAGMA, + "invalid limit value: `%s'", limit); + return DIRR_ERROR; + } else if (val > LIMIT_MAX_VAL) { + val = LIMIT_MAX_VAL; + } + } + + nasm_limit[i] = val; + return DIRR_OK; +} + int64_t switch_segment(int32_t segment) { location.segment = segment; @@ -717,11 +772,13 @@ static char *quote_for_wmake(const char *str) enum text_options { OPT_BOGUS, OPT_VERSION, + OPT_HELP, OPT_ABORT_ON_PANIC, OPT_MANGLE, OPT_INCLUDE, OPT_PRAGMA, - OPT_BEFORE + OPT_BEFORE, + OPT_LIMIT }; struct textargs { const char *label; @@ -732,6 +789,7 @@ struct textargs { static const struct textargs textopts[] = { {"v", OPT_VERSION, false, 0}, {"version", OPT_VERSION, false, 0}, + {"help", OPT_HELP, false, 0}, {"abort-on-panic", OPT_ABORT_ON_PANIC, false, 0}, {"prefix", OPT_MANGLE, true, LM_GPREFIX}, {"postfix", OPT_MANGLE, true, LM_GSUFFIX}, @@ -742,6 +800,7 @@ static const struct textargs textopts[] = { {"include", OPT_INCLUDE, true, 0}, {"pragma", OPT_PRAGMA, true, 0}, {"before", OPT_BEFORE, true, 0}, + {"limit-", OPT_LIMIT, true, 0}, {NULL, OPT_BOGUS, false, 0} }; @@ -756,7 +815,6 @@ static bool stopoptions = false; static bool process_arg(char *p, char *q, int pass) { char *param; - int i; bool advance = false; if (!p || !p[0]) @@ -900,71 +958,7 @@ static bool process_arg(char *p, char *q, int pass) break; case 'h': - printf - ("usage: nasm [-@ response file] [-o outfile] [-f format] " - "[-l listfile]\n" - " [options...] [--] filename\n" - " or nasm -v (or --v) for version info\n\n" - " -t assemble in SciTech TASM compatible mode\n"); - printf - (" -E (or -e) preprocess only (writes output to stdout by default)\n" - " -a don't preprocess (assemble only)\n" - " -M generate Makefile dependencies on stdout\n" - " -MG d:o, missing files assumed generated\n" - " -MF file set Makefile dependency file\n" - " -MD file assemble and generate dependencies\n" - " -MT file dependency target name\n" - " -MQ file dependency target name (quoted)\n" - " -MP emit phony target\n\n" - " -Zfile redirect error messages to file\n" - " -s redirect error messages to stdout\n\n" - " -g generate debugging information\n\n" - " -F format select a debugging format\n\n" - " -gformat same as -g -F format\n\n" - " -o outfile write output to an outfile\n\n" - " -f format select an output format\n\n" - " -l listfile write listing to a listfile\n\n" - " -Ipath add a pathname to the include file path\n"); - printf - (" -Olevel optimize opcodes, immediates and branch offsets\n" - " -O0 no optimization\n" - " -O1 minimal optimization\n" - " -Ox multipass optimization (default)\n" - " -Pfile pre-include a file (also --include)\n" - " -Dmacro[=str] pre-define a macro\n" - " -Umacro undefine a macro\n" - " -Xformat specifiy error reporting format (gnu or vc)\n" - " -w+foo enable warning foo (equiv. -Wfoo)\n" - " -w-foo disable warning foo (equiv. -Wno-foo)\n" - " -w[+-]error[=foo]\n" - " promote [specific] warnings to errors\n" - " -h show invocation summary and exit\n\n" - " --pragma str pre-executes a specific %%pragma\n" - " --before str add line (usually a preprocessor statement) before the input\n" - " --prefix str prepend the given string to all the given string\n" - " to all extern, common and global symbols\n" - " --suffix str append the given string to all the given string\n" - " to all extern, common and global symbols\n" - " --lprefix str prepend the given string to all other symbols\n" - "\n" - "Response files should contain command line parameters,\n" - "one per line.\n" - "\n" - "Warnings for the -W/-w options:\n"); - for (i = 0; i <= ERR_WARN_ALL; i++) - printf(" %-23s %s%s\n", - warnings[i].name, warnings[i].help, - i == ERR_WARN_ALL ? "\n" : - warnings[i].enabled ? " (default on)" : - " (default off)"); - if (p[2] == 'f') { - printf("valid output formats for -f are" - " (`*' denotes default):\n"); - ofmt_list(ofmt, stdout); - } else { - printf("For a list of valid output formats, use -hf.\n"); - printf("For a list of debug formats, use -f