mirror of
https://github.com/netwide-assembler/nasm.git
synced 2025-10-10 00:25:06 -04:00
Additional listing options, improve help output, fix macro limits
Additional listing options: -Ld to display counts in decimal -Lp to output a list file in every pass (to make sure one exists) Clean up the help output and make it comprehensive. The -hf and -y options are no longer necessary, although they are supported for backwards compatiblity. Fix macro-levels so it actually count descent levels; a new macro-tokens limit introduced for the actual token limit. Slightly simplify the limits code. Signed-off-by: H. Peter Anvin <hpa@zytor.com>
This commit is contained in:
@@ -200,6 +200,20 @@ static void list_address(int64_t offset, const char *brackets,
|
|||||||
list_out(offset, q);
|
list_out(offset, q);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void list_size(int64_t offset, const char *tag, uint64_t size)
|
||||||
|
{
|
||||||
|
char buf[64];
|
||||||
|
const char *fmt;
|
||||||
|
|
||||||
|
if (list_option('d'))
|
||||||
|
fmt = "<%s %"PRIu64">";
|
||||||
|
else
|
||||||
|
fmt = "<%s %"PRIX64">";
|
||||||
|
|
||||||
|
snprintf(buf, sizeof buf, fmt, tag, size);
|
||||||
|
list_out(offset, buf);
|
||||||
|
}
|
||||||
|
|
||||||
static void list_output(const struct out_data *data)
|
static void list_output(const struct out_data *data)
|
||||||
{
|
{
|
||||||
char q[24];
|
char q[24];
|
||||||
@@ -214,8 +228,7 @@ static void list_output(const struct out_data *data)
|
|||||||
switch (data->type) {
|
switch (data->type) {
|
||||||
case OUT_ZERODATA:
|
case OUT_ZERODATA:
|
||||||
if (size > 16) {
|
if (size > 16) {
|
||||||
snprintf(q, sizeof(q), "<zero %08"PRIX64">", size);
|
list_size(offset, "zero", size);
|
||||||
list_out(offset, q);
|
|
||||||
break;
|
break;
|
||||||
} else {
|
} else {
|
||||||
p = zero_buffer;
|
p = zero_buffer;
|
||||||
@@ -223,13 +236,19 @@ static void list_output(const struct out_data *data)
|
|||||||
/* fall through */
|
/* fall through */
|
||||||
case OUT_RAWDATA:
|
case OUT_RAWDATA:
|
||||||
{
|
{
|
||||||
if (size == 0 && !listdata[0])
|
if (size == 0) {
|
||||||
listoffset = data->offset;
|
if (!listdata[0])
|
||||||
while (size--) {
|
listoffset = data->offset;
|
||||||
HEX(q, *p);
|
} else if (p) {
|
||||||
q[2] = '\0';
|
while (size--) {
|
||||||
list_out(offset++, q);
|
HEX(q, *p);
|
||||||
p++;
|
q[2] = '\0';
|
||||||
|
list_out(offset++, q);
|
||||||
|
p++;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
/* Used for listing on non-code generation passes with -Lp */
|
||||||
|
list_size(offset, "len", size);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@@ -249,8 +268,8 @@ static void list_output(const struct out_data *data)
|
|||||||
break;
|
break;
|
||||||
case OUT_RESERVE:
|
case OUT_RESERVE:
|
||||||
{
|
{
|
||||||
snprintf(q, sizeof(q), "<res %"PRIX64">", size);
|
if (size)
|
||||||
list_out(offset, q);
|
list_size(offset, "res", size);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
default:
|
default:
|
||||||
@@ -295,22 +314,18 @@ static void mistack_push(bool inhibiting)
|
|||||||
|
|
||||||
static void list_uplevel(int type, int64_t size)
|
static void list_uplevel(int type, int64_t size)
|
||||||
{
|
{
|
||||||
char str[64];
|
|
||||||
|
|
||||||
if (!listp)
|
if (!listp)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
switch (type) {
|
switch (type) {
|
||||||
case LIST_INCBIN:
|
case LIST_INCBIN:
|
||||||
suppress |= 1;
|
suppress |= 1;
|
||||||
snprintf(str, sizeof str, "<bin %"PRIX64">", size);
|
list_size(listoffset, "bin", size);
|
||||||
list_out(listoffset, str);
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case LIST_TIMES:
|
case LIST_TIMES:
|
||||||
suppress |= 2;
|
suppress |= 2;
|
||||||
snprintf(str, sizeof str, "<rep %"PRIX64">", size);
|
list_size(listoffset, "rep", size);
|
||||||
list_out(listoffset, str);
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case LIST_INCLUDE:
|
case LIST_INCLUDE:
|
||||||
|
279
asm/nasm.c
279
asm/nasm.c
@@ -69,12 +69,14 @@ struct forwrefinfo { /* info held on forward refs. */
|
|||||||
int operand;
|
int operand;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const char *_progname;
|
||||||
|
|
||||||
static void parse_cmdline(int, char **, int);
|
static void parse_cmdline(int, char **, int);
|
||||||
static void assemble_file(const char *, struct strlist *);
|
static void assemble_file(const char *, struct strlist *);
|
||||||
static bool skip_this_pass(errflags severity);
|
static bool skip_this_pass(errflags severity);
|
||||||
static void nasm_verror_asm(errflags severity, const char *fmt, va_list args);
|
static void nasm_verror_asm(errflags severity, const char *fmt, va_list args);
|
||||||
static void usage(void);
|
static void usage(void);
|
||||||
static void help(char xopt);
|
static void help(FILE *);
|
||||||
|
|
||||||
struct error_format {
|
struct error_format {
|
||||||
const char *beforeline; /* Before line number, if present */
|
const char *beforeline; /* Before line number, if present */
|
||||||
@@ -172,24 +174,38 @@ static char *(*quote_for_make)(const char *) = quote_for_pmake;
|
|||||||
* Execution limits that can be set via a command-line option or %pragma
|
* Execution limits that can be set via a command-line option or %pragma
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#define LIMIT_MAX_VAL (INT64_MAX >> 1) /* Effectively unlimited */
|
/*
|
||||||
|
* This is really unlimited; it would take far longer than the
|
||||||
|
* current age of the universe for this limit to be reached even on
|
||||||
|
* much faster CPUs than currently exist.
|
||||||
|
*/
|
||||||
|
#define LIMIT_MAX_VAL (INT64_MAX >> 1)
|
||||||
|
|
||||||
int64_t nasm_limit[LIMIT_MAX+1] =
|
int64_t nasm_limit[LIMIT_MAX+1];
|
||||||
{ LIMIT_MAX_VAL, 1000, 1000000, 1000000, 1000000, 2000000000 };
|
|
||||||
|
|
||||||
struct limit_info {
|
struct limit_info {
|
||||||
const char *name;
|
const char *name;
|
||||||
const char *help;
|
const char *help;
|
||||||
|
int64_t default_val;
|
||||||
};
|
};
|
||||||
|
/* The order here must match enum nasm_limit in nasm.h */
|
||||||
static const struct limit_info limit_info[LIMIT_MAX+1] = {
|
static const struct limit_info limit_info[LIMIT_MAX+1] = {
|
||||||
{ "passes", "total number of passes" },
|
{ "passes", "total number of passes", LIMIT_MAX_VAL },
|
||||||
{ "stalled-passes", "number of passes without forward progress" },
|
{ "stalled-passes", "number of passes without forward progress", 1000 },
|
||||||
{ "macro-levels", "levels of macro expansion"},
|
{ "macro-levels", "levels of macro expansion", 10000 },
|
||||||
{ "rep", "%rep count" },
|
{ "macro-tokens", "tokens processed during macro expansion", 10000000 },
|
||||||
{ "eval", "expression evaluation descent"},
|
{ "rep", "%rep count", 1000000 },
|
||||||
{ "lines", "total source lines processed"}
|
{ "eval", "expression evaluation descent", 1000000},
|
||||||
|
{ "lines", "total source lines processed", 2000000000 }
|
||||||
};
|
};
|
||||||
|
|
||||||
|
static void set_default_limits(void)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
for (i = 0; i <= LIMIT_MAX; i++)
|
||||||
|
nasm_limit[i] = limit_info[i].default_val;
|
||||||
|
}
|
||||||
|
|
||||||
enum directive_result
|
enum directive_result
|
||||||
nasm_set_limit(const char *limit, const char *valstr)
|
nasm_set_limit(const char *limit, const char *valstr)
|
||||||
{
|
{
|
||||||
@@ -382,7 +398,7 @@ static void emit_dependencies(struct strlist *list)
|
|||||||
linepos += len+1;
|
linepos += len+1;
|
||||||
nasm_free(file);
|
nasm_free(file);
|
||||||
}
|
}
|
||||||
fprintf(deps, "\n\n");
|
fputs("\n\n", deps);
|
||||||
|
|
||||||
strlist_for_each(l, list) {
|
strlist_for_each(l, list) {
|
||||||
if (depend_emit_phony) {
|
if (depend_emit_phony) {
|
||||||
@@ -453,6 +469,10 @@ static void timestamp(void)
|
|||||||
|
|
||||||
int main(int argc, char **argv)
|
int main(int argc, char **argv)
|
||||||
{
|
{
|
||||||
|
_progname = argv[0];
|
||||||
|
if (!_progname || !_progname[0])
|
||||||
|
_progname = "nasm";
|
||||||
|
|
||||||
timestamp();
|
timestamp();
|
||||||
|
|
||||||
error_file = stderr;
|
error_file = stderr;
|
||||||
@@ -460,6 +480,8 @@ int main(int argc, char **argv)
|
|||||||
iflag_set_default_cpu(&cpu);
|
iflag_set_default_cpu(&cpu);
|
||||||
iflag_set_default_cpu(&cmd_cpu);
|
iflag_set_default_cpu(&cmd_cpu);
|
||||||
|
|
||||||
|
set_default_limits();
|
||||||
|
|
||||||
include_path = strlist_alloc(true);
|
include_path = strlist_alloc(true);
|
||||||
|
|
||||||
_pass_type = PASS_INIT;
|
_pass_type = PASS_INIT;
|
||||||
@@ -998,6 +1020,10 @@ static bool process_arg(char *p, char *q, int pass)
|
|||||||
list_options |= (UINT64_C(1) << p);
|
list_options |= (UINT64_C(1) << p);
|
||||||
param++;
|
param++;
|
||||||
}
|
}
|
||||||
|
if (list_options & (UINT64_C(1) << ('p' - '@'))) {
|
||||||
|
/* Do listings for every pass */
|
||||||
|
active_list_options = list_options;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
@@ -1033,14 +1059,13 @@ static bool process_arg(char *p, char *q, int pass)
|
|||||||
break;
|
break;
|
||||||
|
|
||||||
case 'h':
|
case 'h':
|
||||||
help(p[2]);
|
help(stdout);
|
||||||
exit(0); /* never need usage message here */
|
exit(0); /* never need usage message here */
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 'y':
|
case 'y':
|
||||||
printf("\nvalid debug formats for '%s' output format are"
|
/* legacy option */
|
||||||
" ('*' denotes default):\n", ofmt->shortname);
|
dfmt_list(stdout);
|
||||||
dfmt_list(ofmt, stdout);
|
|
||||||
exit(0);
|
exit(0);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
@@ -1238,7 +1263,7 @@ static bool process_arg(char *p, char *q, int pass)
|
|||||||
debug_nasm = param ? strtoul(param, NULL, 10) : debug_nasm+1;
|
debug_nasm = param ? strtoul(param, NULL, 10) : debug_nasm+1;
|
||||||
break;
|
break;
|
||||||
case OPT_HELP:
|
case OPT_HELP:
|
||||||
help(0);
|
help(stdout);
|
||||||
exit(0);
|
exit(0);
|
||||||
default:
|
default:
|
||||||
panic();
|
panic();
|
||||||
@@ -1495,7 +1520,20 @@ static void process_insn(insn *instruction)
|
|||||||
for (n = 1; n <= instruction->times; n++) {
|
for (n = 1; n <= instruction->times; n++) {
|
||||||
l = insn_size(location.segment, location.offset,
|
l = insn_size(location.segment, location.offset,
|
||||||
globalbits, instruction);
|
globalbits, instruction);
|
||||||
if (l != -1) /* l == -1 -> invalid instruction */
|
|
||||||
|
if (list_option('p')) {
|
||||||
|
if (l > 0) {
|
||||||
|
struct out_data dummy;
|
||||||
|
memset(&dummy, 0, sizeof dummy);
|
||||||
|
dummy.type = OUT_RESERVE;
|
||||||
|
dummy.offset = location.offset;
|
||||||
|
dummy.size = l;
|
||||||
|
lfmt->output(&dummy);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* l == -1 -> invalid instruction */
|
||||||
|
if (l != -1)
|
||||||
increment_offset(l);
|
increment_offset(l);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
@@ -1566,7 +1604,7 @@ static void assemble_file(const char *fname, struct strlist *depend_list)
|
|||||||
|
|
||||||
globalbits = cmd_sb; /* set 'bits' to command line default */
|
globalbits = cmd_sb; /* set 'bits' to command line default */
|
||||||
cpu = cmd_cpu;
|
cpu = cmd_cpu;
|
||||||
if (pass_final()) {
|
if (pass_final() || list_option('p')) {
|
||||||
active_list_options = list_options;
|
active_list_options = list_options;
|
||||||
lfmt->init(listname);
|
lfmt->init(listname);
|
||||||
}
|
}
|
||||||
@@ -1933,95 +1971,136 @@ static void usage(void)
|
|||||||
fputs("type `nasm -h' for help\n", error_file);
|
fputs("type `nasm -h' for help\n", error_file);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void help(const char xopt)
|
static void help(FILE *out)
|
||||||
{
|
{
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
printf
|
fprintf(out,
|
||||||
("usage: nasm [-@ response file] [-o outfile] [-f format] "
|
"Usage: %s [-@ response file] [options...] [--] filename\n"
|
||||||
"[-l listfile]\n"
|
" %s -v (or --v)\n"
|
||||||
" [options...] [--] filename\n"
|
"\n",
|
||||||
" or nasm -v (or --v) for version info\n\n"
|
_progname, _progname);
|
||||||
"\n"
|
fputs(
|
||||||
"Response files should contain command line parameters,\n"
|
"\n"
|
||||||
"one per line.\n"
|
"Response files should contain command line parameters,\n"
|
||||||
"\n"
|
"one per line.\n"
|
||||||
" -t assemble in SciTech TASM compatible mode\n");
|
"\n"
|
||||||
printf
|
"Values in brackets indicate defaults\n"
|
||||||
(" -E (or -e) preprocess only (writes output to stdout by default)\n"
|
"\n"
|
||||||
" -a don't preprocess (assemble only)\n"
|
" -h show this text and exit (also --help)\n"
|
||||||
" -M generate Makefile dependencies on stdout\n"
|
" -v print the NASM version number and exit\n"
|
||||||
" -MG d:o, missing files assumed generated\n"
|
"\n"
|
||||||
" -MF file set Makefile dependency file\n"
|
" -o outfile write output to outfile\n"
|
||||||
" -MD file assemble and generate dependencies\n"
|
" --keep-all output files will not be removed even if an error happens\n"
|
||||||
" -MT file dependency target name\n"
|
"\n"
|
||||||
" -MQ file dependency target name (quoted)\n"
|
" -Xformat specifiy error reporting format (gnu or vc)\n"
|
||||||
" -MP emit phony target\n\n"
|
" -s redirect error messages to stdout\n"
|
||||||
" -Zfile redirect error messages to file\n"
|
" -Zfile redirect error messages to file\n"
|
||||||
" -s redirect error messages to stdout\n\n"
|
"\n"
|
||||||
" -g generate debugging information\n\n"
|
" -M generate Makefile dependencies on stdout\n"
|
||||||
" -F format select a debugging format\n\n"
|
" -MG d:o, missing files assumed generated\n"
|
||||||
" -gformat same as -g -F format\n\n"
|
" -MF file set Makefile dependency file\n"
|
||||||
" -o outfile write output to an outfile\n\n"
|
" -MD file assemble and generate dependencies\n"
|
||||||
" -f format select an output format\n\n"
|
" -MT file dependency target name\n"
|
||||||
" -l listfile write listing to a list file\n"
|
" -MQ file dependency target name (quoted)\n"
|
||||||
" -Lflags... add optional information to the list file\n"
|
" -MP emit phony targets\n"
|
||||||
" -Le show the preprocessed output\n\n"
|
"\n"
|
||||||
" -Lm show all single-line macro definitions\n\n"
|
" -f format select output file format\n"
|
||||||
" -Ipath add a pathname to the include file path\n");
|
, out);
|
||||||
printf
|
ofmt_list(ofmt, out);
|
||||||
(" -Oflags... optimize opcodes, immediates and branch offsets\n"
|
fputs(
|
||||||
" -O0 no optimization\n"
|
"\n"
|
||||||
" -O1 minimal optimization\n"
|
" -g generate debugging information\n"
|
||||||
" -Ox multipass optimization (default)\n"
|
" -F format select a debugging format (output format dependent)\n"
|
||||||
" -Ov display the number of passes executed at the end\n"
|
" -gformat same as -g -F format\n"
|
||||||
" -Pfile pre-include a file (also --include)\n"
|
, out);
|
||||||
" -Dmacro[=str] pre-define a macro\n"
|
dfmt_list(out);
|
||||||
" -Umacro undefine a macro\n"
|
fputs(
|
||||||
" -Xformat specifiy error reporting format (gnu or vc)\n"
|
"\n"
|
||||||
" -w+foo enable warning foo (equiv. -Wfoo)\n"
|
" -l listfile write listing to a list file\n"
|
||||||
" -w-foo disable warning foo (equiv. -Wno-foo)\n"
|
" -Lflags... add optional information to the list file\n"
|
||||||
" -w[+-]error[=foo]\n"
|
" -Ld show byte and repeat counts in decimal, not hex\n"
|
||||||
" promote [specific] warnings to errors\n"
|
" -Le show the preprocessed output\n"
|
||||||
" -h show invocation summary and exit (also --help)\n\n"
|
" -Lm show all single-line macro definitions\n"
|
||||||
" --pragma str pre-executes a specific %%pragma\n"
|
" -Lp output a list file every pass, in case of errors\n"
|
||||||
" --before str add line (usually a preprocessor statement) before the input\n"
|
"\n"
|
||||||
" --prefix str prepend the given string to all the given string\n"
|
" -Oflags... optimize opcodes, immediates and branch offsets\n"
|
||||||
" to all extern, common and global symbols (also --gprefix)\n"
|
" -O0 no optimization\n"
|
||||||
" --postfix str append the given string to all the given string\n"
|
" -O1 minimal optimization\n"
|
||||||
" to all extern, common and global symbols (also --gpostfix)\n"
|
" -Ox multipass optimization (default)\n"
|
||||||
" --lprefix str prepend the given string to all other symbols\n"
|
" -Ov display the number of passes executed at the end\n"
|
||||||
" --lpostfix str append the given string to all other symbols\n"
|
" -t assemble in limited SciTech TASM compatible mode\n"
|
||||||
" --keep-all output files will not be removed even if an error happens\n"
|
"\n"
|
||||||
" --no-line ignore %%line directives in input\n"
|
" -E (or -e) preprocess only (writes output to stdout by default)\n"
|
||||||
" --limit-X val set execution limit X\n");
|
" -a don't preprocess (assemble only)\n"
|
||||||
|
" -Ipath add a pathname to the include file path\n"
|
||||||
|
" -Pfile pre-include a file (also --include)\n"
|
||||||
|
" -Dmacro[=str] pre-define a macro\n"
|
||||||
|
" -Umacro undefine a macro\n"
|
||||||
|
" --pragma str pre-executes a specific %%pragma\n"
|
||||||
|
" --before str add line (usually a preprocessor statement) before the input\n"
|
||||||
|
" --no-line ignore %line directives in input\n"
|
||||||
|
"\n"
|
||||||
|
" --prefix str prepend the given string to the names of all extern,\n"
|
||||||
|
" common and global symbols (also --gprefix)\n"
|
||||||
|
" --suffix str append the given string to the names of all extern,\n"
|
||||||
|
" common and global symbols (also --gprefix)\n"
|
||||||
|
" --lprefix str prepend the given string to local symbols\n"
|
||||||
|
" --lpostfix str append the given string to local symbols\n"
|
||||||
|
"\n"
|
||||||
|
" -w+x enable warning x (also -Wx)\n"
|
||||||
|
" -w-x disable warning x (also -Wno-x)\n"
|
||||||
|
" -w[+-]error promote all warnings to errors (also -Werror)\n"
|
||||||
|
" -w[+-]error=x promote warning x to errors (also -Werror=x)\n"
|
||||||
|
, out);
|
||||||
|
|
||||||
|
fprintf(out, " %-20s %s\n",
|
||||||
|
warning_name[WARN_IDX_ALL], warning_help[WARN_IDX_ALL]);
|
||||||
|
|
||||||
|
for (i = 1; i < WARN_IDX_ALL; i++) {
|
||||||
|
const char *me = warning_name[i];
|
||||||
|
const char *prev = warning_name[i-1];
|
||||||
|
const char *next = warning_name[i+1];
|
||||||
|
|
||||||
|
if (prev) {
|
||||||
|
int prev_len = strlen(prev);
|
||||||
|
const char *dash = me;
|
||||||
|
|
||||||
|
while ((dash = strchr(dash+1, '-'))) {
|
||||||
|
int prefix_len = dash - me; /* Not including final dash */
|
||||||
|
if (strncmp(next, me, prefix_len+1)) {
|
||||||
|
/* Only one or last option with this prefix */
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (prefix_len >= prev_len ||
|
||||||
|
strncmp(prev, me, prefix_len) ||
|
||||||
|
(prev[prefix_len] != '-' && prev[prefix_len] != '\0')) {
|
||||||
|
/* This prefix is different from the previous option */
|
||||||
|
fprintf(out, " %-20.*s all warnings prefixed with \"%.*s\"\n",
|
||||||
|
prefix_len, me, prefix_len+1, me);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fprintf(out, " %-20s %s%s\n",
|
||||||
|
warning_name[i], warning_help[i],
|
||||||
|
(warning_default[i] & WARN_ST_ERROR) ? " [error]" :
|
||||||
|
(warning_default[i] & WARN_ST_ENABLED) ? " [on]" : " [off]");
|
||||||
|
}
|
||||||
|
|
||||||
|
fputs(
|
||||||
|
"\n"
|
||||||
|
" --limit-X val set execution limit X\n"
|
||||||
|
, out);
|
||||||
|
|
||||||
|
|
||||||
for (i = 0; i <= LIMIT_MAX; i++) {
|
for (i = 0; i <= LIMIT_MAX; i++) {
|
||||||
printf(" %-15s %s (default ",
|
fprintf(out, " %-20s %s [",
|
||||||
limit_info[i].name, limit_info[i].help);
|
limit_info[i].name, limit_info[i].help);
|
||||||
if (nasm_limit[i] < LIMIT_MAX_VAL) {
|
if (nasm_limit[i] < LIMIT_MAX_VAL) {
|
||||||
printf("%"PRId64")\n", nasm_limit[i]);
|
fprintf(out, "%"PRId64"]\n", nasm_limit[i]);
|
||||||
} else {
|
} else {
|
||||||
printf("unlimited)\n");
|
fputs("unlimited]\n", out);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
printf("\nWarnings for the -W/-w options: (defaults in brackets)\n");
|
|
||||||
|
|
||||||
for (i = 1; i <= WARN_IDX_ALL; i++) {
|
|
||||||
printf(" %-23s %s%s\n",
|
|
||||||
warning_name[i], warning_help[i],
|
|
||||||
i == WARN_IDX_ALL ? "\n" :
|
|
||||||
(warning_default[i] & WARN_ST_ERROR) ? " [error]" :
|
|
||||||
(warning_default[i] & WARN_ST_ENABLED) ? " [on]" : " [off]");
|
|
||||||
}
|
|
||||||
|
|
||||||
if (xopt == '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 <format> -y.\n");
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@@ -342,9 +342,6 @@ enum {
|
|||||||
#define NO_DIRECTIVE_FOUND 0
|
#define NO_DIRECTIVE_FOUND 0
|
||||||
#define DIRECTIVE_FOUND 1
|
#define DIRECTIVE_FOUND 1
|
||||||
|
|
||||||
/* max reps */
|
|
||||||
#define REP_LIMIT ((INT64_C(1) << 62))
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Condition codes. Note that we use c_ prefix not C_ because C_ is
|
* Condition codes. Note that we use c_ prefix not C_ because C_ is
|
||||||
* used in nasm.h for the "real" condition codes. At _this_ level,
|
* used in nasm.h for the "real" condition codes. At _this_ level,
|
||||||
@@ -3000,8 +2997,7 @@ issue_error:
|
|||||||
return DIRECTIVE_FOUND;
|
return DIRECTIVE_FOUND;
|
||||||
}
|
}
|
||||||
defining = nasm_zalloc(sizeof(MMacro));
|
defining = nasm_zalloc(sizeof(MMacro));
|
||||||
defining->max_depth = ((i == PP_RMACRO) || (i == PP_IRMACRO))
|
defining->max_depth = nasm_limit[LIMIT_MACRO_LEVELS];
|
||||||
? nasm_limit[LIMIT_MACROS] : 0;
|
|
||||||
defining->casesense = casesense;
|
defining->casesense = casesense;
|
||||||
if (!parse_mmacro_spec(tline, defining, dname)) {
|
if (!parse_mmacro_spec(tline, defining, dname)) {
|
||||||
nasm_free(defining);
|
nasm_free(defining);
|
||||||
@@ -4312,6 +4308,13 @@ static Token *expand_mmac_params(Token * tline)
|
|||||||
return thead;
|
return thead;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static Token *expand_smacro_noreset(Token * tline);
|
||||||
|
static struct {
|
||||||
|
int64_t tokens;
|
||||||
|
int64_t levels;
|
||||||
|
bool triggered;
|
||||||
|
} smacro_deadman;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Expand *one* single-line macro instance. If the first token is not
|
* Expand *one* single-line macro instance. If the first token is not
|
||||||
* a macro at all, it is simply copied to the output and the pointer
|
* a macro at all, it is simply copied to the output and the pointer
|
||||||
@@ -4323,15 +4326,9 @@ static Token *expand_mmac_params(Token * tline)
|
|||||||
* If the expansion is empty, *tpp will be unchanged but **tpp will
|
* If the expansion is empty, *tpp will be unchanged but **tpp will
|
||||||
* be advanced past the macro call.
|
* be advanced past the macro call.
|
||||||
*
|
*
|
||||||
* The return value equals **tpp.
|
* Return the macro expanded, or NULL if no expansion took place.
|
||||||
*
|
|
||||||
* Return false if no expansion took place; true if it did.
|
|
||||||
*
|
|
||||||
*/
|
*/
|
||||||
static Token *expand_smacro_noreset(Token * tline);
|
static SMacro *expand_one_smacro(Token ***tpp)
|
||||||
static int64_t smacro_deadman;
|
|
||||||
|
|
||||||
static bool expand_one_smacro(Token ***tpp)
|
|
||||||
{
|
{
|
||||||
Token **params = NULL;
|
Token **params = NULL;
|
||||||
const char *mname;
|
const char *mname;
|
||||||
@@ -4347,9 +4344,14 @@ static bool expand_one_smacro(Token ***tpp)
|
|||||||
|
|
||||||
mname = tline->text;
|
mname = tline->text;
|
||||||
|
|
||||||
if (--smacro_deadman <= 0) {
|
smacro_deadman.tokens--;
|
||||||
if (smacro_deadman == 0)
|
smacro_deadman.levels--;
|
||||||
|
|
||||||
|
if (unlikely(smacro_deadman.tokens < 0 || smacro_deadman.levels < 0)) {
|
||||||
|
if (unlikely(!smacro_deadman.triggered)) {
|
||||||
nasm_nonfatal("interminable macro recursion");
|
nasm_nonfatal("interminable macro recursion");
|
||||||
|
smacro_deadman.triggered = true;
|
||||||
|
}
|
||||||
goto not_a_macro;
|
goto not_a_macro;
|
||||||
} else if (tline->type == TOK_ID) {
|
} else if (tline->type == TOK_ID) {
|
||||||
head = (SMacro *)hash_findix(&smacros, mname);
|
head = (SMacro *)hash_findix(&smacros, mname);
|
||||||
@@ -4652,17 +4654,21 @@ static bool expand_one_smacro(Token ***tpp)
|
|||||||
|
|
||||||
/* Don't do this until after expansion or we will clobber mname */
|
/* Don't do this until after expansion or we will clobber mname */
|
||||||
free_tlist(mstart);
|
free_tlist(mstart);
|
||||||
free_tlist_array(params, nparam);
|
goto done;
|
||||||
return true;
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* No macro expansion needed; roll back to mstart (if necessary)
|
* No macro expansion needed; roll back to mstart (if necessary)
|
||||||
* and then advance to the next input token.
|
* and then advance to the next input token. Note that this is
|
||||||
|
* by far the common case!
|
||||||
*/
|
*/
|
||||||
not_a_macro:
|
not_a_macro:
|
||||||
*tpp = &mstart->next;
|
*tpp = &mstart->next;
|
||||||
free_tlist_array(params, nparam);
|
m = NULL;
|
||||||
return false;
|
done:
|
||||||
|
smacro_deadman.levels++;
|
||||||
|
if (unlikely(params))
|
||||||
|
free_tlist_array(params, nparam);
|
||||||
|
return m;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -4674,7 +4680,9 @@ not_a_macro:
|
|||||||
*/
|
*/
|
||||||
static Token *expand_smacro(Token *tline)
|
static Token *expand_smacro(Token *tline)
|
||||||
{
|
{
|
||||||
smacro_deadman = nasm_limit[LIMIT_MACROS];
|
smacro_deadman.tokens = nasm_limit[LIMIT_MACRO_TOKENS];
|
||||||
|
smacro_deadman.levels = nasm_limit[LIMIT_MACRO_LEVELS];
|
||||||
|
smacro_deadman.triggered = false;
|
||||||
return expand_smacro_noreset(tline);
|
return expand_smacro_noreset(tline);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -4718,10 +4726,8 @@ static Token *expand_smacro_noreset(Token * tline)
|
|||||||
};
|
};
|
||||||
|
|
||||||
tail = &thead;
|
tail = &thead;
|
||||||
while ((t = *tail)) { /* main token loop */
|
while ((t = *tail)) /* main token loop */
|
||||||
|
expanded |= !!expand_one_smacro(&tail);
|
||||||
expanded |= expand_one_smacro(&tail);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!expanded) {
|
if (!expanded) {
|
||||||
tline = thead;
|
tline = thead;
|
||||||
|
@@ -54,6 +54,9 @@
|
|||||||
#include "srcfile.h"
|
#include "srcfile.h"
|
||||||
#include "error.h"
|
#include "error.h"
|
||||||
|
|
||||||
|
/* Program name for error messages etc. */
|
||||||
|
extern const char *_progname;
|
||||||
|
|
||||||
/* Time stamp for the official start of compilation */
|
/* Time stamp for the official start of compilation */
|
||||||
struct compile_time {
|
struct compile_time {
|
||||||
time_t t;
|
time_t t;
|
||||||
@@ -748,7 +751,8 @@ struct pragma {
|
|||||||
enum nasm_limit {
|
enum nasm_limit {
|
||||||
LIMIT_PASSES,
|
LIMIT_PASSES,
|
||||||
LIMIT_STALLED,
|
LIMIT_STALLED,
|
||||||
LIMIT_MACROS,
|
LIMIT_MACRO_LEVELS,
|
||||||
|
LIMIT_MACRO_TOKENS,
|
||||||
LIMIT_REP,
|
LIMIT_REP,
|
||||||
LIMIT_EVAL,
|
LIMIT_EVAL,
|
||||||
LIMIT_LINES
|
LIMIT_LINES
|
||||||
|
@@ -59,7 +59,7 @@ static void cv8_output(int type, void *param);
|
|||||||
static void cv8_cleanup(void);
|
static void cv8_cleanup(void);
|
||||||
|
|
||||||
const struct dfmt df_cv8 = {
|
const struct dfmt df_cv8 = {
|
||||||
"Codeview 8", /* .fullname */
|
"Codeview 8+", /* .fullname */
|
||||||
"cv8", /* .shortname */
|
"cv8", /* .shortname */
|
||||||
cv8_init, /* .init */
|
cv8_init, /* .init */
|
||||||
cv8_linenum, /* .linenum */
|
cv8_linenum, /* .linenum */
|
||||||
|
@@ -43,6 +43,7 @@
|
|||||||
|
|
||||||
#define BUILD_DRIVERS_ARRAY
|
#define BUILD_DRIVERS_ARRAY
|
||||||
#include "outform.h"
|
#include "outform.h"
|
||||||
|
#include "outlib.h"
|
||||||
|
|
||||||
const struct ofmt *ofmt_find(const char *name,
|
const struct ofmt *ofmt_find(const char *name,
|
||||||
const struct ofmt_alias **ofmt_alias)
|
const struct ofmt_alias **ofmt_alias)
|
||||||
@@ -90,29 +91,45 @@ void ofmt_list(const struct ofmt *deffmt, FILE * fp)
|
|||||||
|
|
||||||
/* primary targets first */
|
/* primary targets first */
|
||||||
for (ofp = drivers; (of = *ofp); ofp++) {
|
for (ofp = drivers; (of = *ofp); ofp++) {
|
||||||
fprintf(fp, " %c %-10s%s\n",
|
fprintf(fp, " %-20s %s%s\n",
|
||||||
of == deffmt ? '*' : ' ',
|
of->shortname,
|
||||||
of->shortname, of->fullname);
|
of->fullname,
|
||||||
|
of == deffmt ? " [default]" : "");
|
||||||
}
|
}
|
||||||
|
|
||||||
/* lets walk through aliases then */
|
/* lets walk through aliases then */
|
||||||
for (i = 0; i < ARRAY_SIZE(ofmt_aliases); i++) {
|
for (i = 0; i < ARRAY_SIZE(ofmt_aliases); i++) {
|
||||||
if (!ofmt_aliases[i].shortname)
|
if (!ofmt_aliases[i].shortname)
|
||||||
continue;
|
continue;
|
||||||
fprintf(fp, " %-10s%s\n",
|
fprintf(fp, " %-20s %s\n",
|
||||||
ofmt_aliases[i].shortname,
|
ofmt_aliases[i].shortname,
|
||||||
ofmt_aliases[i].fullname);
|
ofmt_aliases[i].fullname);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void dfmt_list(const struct ofmt *ofmt, FILE *fp)
|
void dfmt_list(FILE *fp)
|
||||||
{
|
{
|
||||||
|
const struct ofmt * const *ofp;
|
||||||
|
const struct ofmt *of;
|
||||||
const struct dfmt * const *dfp;
|
const struct dfmt * const *dfp;
|
||||||
const struct dfmt *df;
|
const struct dfmt *df;
|
||||||
|
char prefixbuf[32];
|
||||||
|
const char *prefix;
|
||||||
|
|
||||||
for (dfp = ofmt->debug_formats; (df = *dfp); dfp++) {
|
for (ofp = drivers; (of = *ofp); ofp++) {
|
||||||
fprintf(fp, " %c %-10s%s\n",
|
if (of->debug_formats && of->debug_formats != null_debug_arr) {
|
||||||
df == dfmt ? '*' : ' ',
|
snprintf(prefixbuf, sizeof prefixbuf, "%s:",
|
||||||
df->shortname, df->fullname);
|
of->shortname);
|
||||||
|
prefix = prefixbuf;
|
||||||
|
|
||||||
|
for (dfp = of->debug_formats; (df = *dfp); dfp++) {
|
||||||
|
if (df != &null_debug_form)
|
||||||
|
fprintf(fp, " %-10s %-9s %s%s\n",
|
||||||
|
prefix,
|
||||||
|
df->shortname, df->fullname,
|
||||||
|
df == of->default_dfmt ? " [default]" : "");
|
||||||
|
prefix = "";
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -373,7 +373,7 @@ static const struct ofmt_alias ofmt_aliases[] = {
|
|||||||
const struct ofmt *ofmt_find(const char *name, const struct ofmt_alias **ofmt_alias);
|
const struct ofmt *ofmt_find(const char *name, const struct ofmt_alias **ofmt_alias);
|
||||||
const struct dfmt *dfmt_find(const struct ofmt *, const char *);
|
const struct dfmt *dfmt_find(const struct ofmt *, const char *);
|
||||||
void ofmt_list(const struct ofmt *, FILE *);
|
void ofmt_list(const struct ofmt *, FILE *);
|
||||||
void dfmt_list(const struct ofmt *ofmt, FILE * fp);
|
void dfmt_list(FILE *);
|
||||||
extern const struct dfmt null_debug_form;
|
extern const struct dfmt null_debug_form;
|
||||||
|
|
||||||
#endif /* NASM_OUTFORM_H */
|
#endif /* NASM_OUTFORM_H */
|
||||||
|
Reference in New Issue
Block a user