aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorH. Peter Anvin (Intel) <hpa@zytor.com>2019-08-09 08:06:39 -0700
committerH. Peter Anvin (Intel) <hpa@zytor.com>2019-08-09 08:39:02 -0700
commitd6e817751e1a809a4e635bbe7ece7e059cbe5f63 (patch)
tree41b276a7c44d9350ec1fa4d2eb2daada09970541
parentd66927a677f75d3c3f5e835054f19f80b4b27179 (diff)
downloadnasm-d6e817751e1a809a4e635bbe7ece7e059cbe5f63.tar.gz
nasm-d6e817751e1a809a4e635bbe7ece7e059cbe5f63.tar.xz
nasm-d6e817751e1a809a4e635bbe7ece7e059cbe5f63.zip
listing: add -L option for additional listing info
Add an -L option for additional listing information. Currently supported is -Le, which emits each line after processing through the preprocessor, and -Lm, which displays each single-line macro defined or undefined. NASM doesn't preserve the names of unused arguments, nor does it have any technical reason to do so. Instead of adding complexity to save them, make unnamed parameters official by specifying an empty string in the argument list. This has the additional advantage that () is now simply considered a single empty argument, which means that NASM should now properly handle things like: %define myreg() eax mov edx,myreg() ... similar to how the C preprocessor allows an empty macro argument list which is distinct from a macro with no arguments whatsoever. Signed-off-by: H. Peter Anvin (Intel) <hpa@zytor.com>
-rw-r--r--asm/listing.c7
-rw-r--r--asm/listing.h11
-rw-r--r--asm/nasm.c25
-rw-r--r--asm/preproc.c205
-rw-r--r--include/strlist.h7
-rw-r--r--test/evalmacro.asm9
6 files changed, 218 insertions, 46 deletions
diff --git a/asm/listing.c b/asm/listing.c
index 1831d877..2e04bb6c 100644
--- a/asm/listing.c
+++ b/asm/listing.c
@@ -108,10 +108,14 @@ static void list_emit(void)
}
if (list_errors) {
+ static const char fillchars[] = " --***XX";
+ char fillchar;
+
strlist_for_each(e, list_errors) {
fprintf(listfp, "%6"PRId32" ", listlineno);
+ fillchar = fillchars[e->pvt.u & ERR_MASK];
for (i = 0; i < LIST_HEXBIT; i++)
- putc('*', listfp);
+ putc(fillchar, listfp);
if (listlevel_e)
fprintf(listfp, " %s<%d>", (listlevel < 10 ? " " : ""),
@@ -363,6 +367,7 @@ static void list_error(errflags severity, const char *fmt, ...)
va_start(ap, fmt);
strlist_vprintf(list_errors, fmt, ap);
va_end(ap);
+ strlist_tail(list_errors)->pvt.u = severity;
if ((severity & ERR_MASK) >= ERR_FATAL)
list_emit();
diff --git a/asm/listing.h b/asm/listing.h
index dac18bfe..00326854 100644
--- a/asm/listing.h
+++ b/asm/listing.h
@@ -1,6 +1,6 @@
/* ----------------------------------------------------------------------- *
*
- * Copyright 1996-2016 The NASM Authors - All Rights Reserved
+ * Copyright 1996-2019 The NASM Authors - All Rights Reserved
* See the file AUTHORS included with the NASM distribution for
* the specific copyright holders.
*
@@ -110,5 +110,14 @@ struct lfmt {
extern const struct lfmt *lfmt;
extern bool user_nolist;
+extern uint64_t active_list_options; /* Simply a bitmask of ASCII-64 */
+
+static inline bool list_option(char x)
+{
+ unsigned int p = x - '@';
+ if (p > 63)
+ return false;
+ return unlikely(active_list_options & (UINT64_C(1) << p));
+}
#endif
diff --git a/asm/nasm.c b/asm/nasm.c
index 676ff872..075cc2c2 100644
--- a/asm/nasm.c
+++ b/asm/nasm.c
@@ -115,6 +115,9 @@ const char *outname;
static const char *listname;
static const char *errname;
+static uint64_t list_options;
+uint64_t active_list_options; /* Set during the final pass only */
+
static int64_t globallineno; /* for forward-reference tracking */
const struct ofmt *ofmt = &OF_DEFAULT;
@@ -881,7 +884,7 @@ static bool process_arg(char *p, char *q, int pass)
return false;
if (p[0] == '-' && !stopoptions) {
- if (strchr("oOfpPdDiIlFXuUZwW", p[1])) {
+ if (strchr("oOfpPdDiIlLFXuUZwW", p[1])) {
/* These parameters take values */
if (!(param = get_param(p, q, &advance)))
return advance;
@@ -981,6 +984,17 @@ static bool process_arg(char *p, char *q, int pass)
copy_filename(&listname, param, "listing");
break;
+ case 'L': /* listing options */
+ if (pass == 2) {
+ while (*param) {
+ unsigned int p = *param - '@';
+ if (p <= 63)
+ list_options |= (UINT64_C(1) << p);
+ param++;
+ }
+ }
+ break;
+
case 'Z': /* error messages file */
if (pass == 1)
copy_filename(&errname, param, "error");
@@ -1533,8 +1547,10 @@ static void assemble_file(const char *fname, struct strlist *depend_list)
globalbits = cmd_sb; /* set 'bits' to command line default */
cpu = cmd_cpu;
- if (pass_final())
+ if (pass_final()) {
+ active_list_options = list_options;
lfmt->init(listname);
+ }
in_absolute = false;
if (!pass_first()) {
@@ -1929,7 +1945,10 @@ static void help(const char xopt)
" -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"
+ " -l listfile write listing to a list file\n"
+ " -Lflags... add optional information to the list file\n"
+ " -Le show the preprocessed output\n\n"
+ " -Lm show all single-line macro definitions\n\n"
" -Ipath add a pathname to the include file path\n");
printf
(" -Oflags... optimize opcodes, immediates and branch offsets\n"
diff --git a/asm/preproc.c b/asm/preproc.c
index 7a5d11fe..b16ed0c9 100644
--- a/asm/preproc.c
+++ b/asm/preproc.c
@@ -184,7 +184,8 @@ struct Context {
Context *next;
char *name;
struct hash_table localmac;
- uint32_t number;
+ uint64_t number;
+ unsigned int depth;
};
/*
@@ -1290,7 +1291,6 @@ static char *detoken(Token * tlist, bool expand_locals)
{
Token *t;
char *line, *p;
- const char *q;
int len = 0;
list_for_each(t, tlist) {
@@ -1333,9 +1333,8 @@ static char *detoken(Token * tlist, bool expand_locals)
char *p;
Context *ctx = get_ctx(t->text, &q);
if (ctx) {
- char buffer[40];
- snprintf(buffer, sizeof(buffer), "..@%"PRIu32".", ctx->number);
- p = nasm_strcat(buffer, q);
+ p = nasm_asprintf("..@%"PRIu64".%s", ctx->number, q);
+ t->len = nasm_last_string_len();
nasm_free(t->text);
t->text = p;
}
@@ -1352,9 +1351,8 @@ static char *detoken(Token * tlist, bool expand_locals)
if (t->type == TOK_WHITESPACE) {
*p++ = ' ';
} else if (t->text) {
- q = t->text;
- while (*q)
- *p++ = *q++;
+ memcpy(p, t->text, t->len);
+ p += t->len;
}
}
*p = '\0';
@@ -2075,10 +2073,105 @@ smacro_expand_default(const SMacro *s, Token **params, unsigned int nparams)
}
/*
+ * Emit a macro defintion or undef to the listing file, if
+ * desired. This is similar to detoken(), but it handles the reverse
+ * expansion list, does not expand %! or local variable tokens, and
+ * does some special handling for macro parameters.
+ */
+static void
+list_smacro_def(enum preproc_token op, const Context *ctx, const SMacro *m)
+{
+ static const Token unused_arg_name = { NULL, "", 0, TOK_OTHER };
+ const Token **param_names;
+ Token *junk_names = NULL;
+ Token *t;
+ size_t namelen, size;
+ unsigned int i;
+ char *def, *p;
+ unsigned int context_depth = 0;
+
+ nasm_newn(param_names, m->nparam);
+
+ namelen = strlen(m->name);
+ size = namelen + 2; /* Include room for space after name + NUL */
+
+ if (ctx) {
+ context_depth = cstk->depth - ctx->depth + 1;
+ size += context_depth + 1; /* % + some number of $ */
+ }
+
+ list_for_each(t, m->expansion) {
+ if (!t->text) {
+ size++; /* Whitespace, presumably */
+ } else {
+ size += t->len;
+ if (is_smac_param(t->type))
+ param_names[smac_nparam(t->type)] = t;
+ }
+ }
+
+ if (m->nparam) {
+ /*
+ * Space for ( and either , or ) around each
+ * parameter, plus an optional =.
+ */
+ size += 1 + 2 * m->nparam;
+ for (i = 0; i < m->nparam; i++) {
+ if (!param_names[i])
+ param_names[i] = &unused_arg_name;
+ size += param_names[i]->len;
+ }
+ }
+
+ def = nasm_malloc(size);
+ p = def+size;
+ *--p = '\0';
+
+ list_for_each(t, m->expansion) {
+ if (!t->text) {
+ *--p = ' ';
+ } else {
+ p -= t->len;
+ memcpy(p, t->text, t->len);
+ }
+ }
+
+ *--p = ' ';
+
+ if (m->nparam) {
+ *--p = ')';
+ for (i = m->nparam; i--;) {
+ p -= param_names[i]->len;
+ memcpy(p, param_names[i]->text, param_names[i]->len);
+ if (m->eval_param && m->eval_param[i])
+ *--p = '=';
+ *--p = ',';
+ }
+ *p = '('; /* First parameter starts with ( not , */
+
+ free_tlist(junk_names);
+ }
+
+ p -= namelen;
+ memcpy(p, m->name, namelen);
+
+ if (context_depth) {
+ for (i = 0; i < context_depth; i++)
+ *--p = '$';
+ *--p = '%';
+ }
+
+ nasm_listmsg("%s %s", pp_directives[op], p);
+
+ nasm_free(def);
+ }
+
+/*
* Common code for defining an smacro
*/
static SMacro *define_smacro(Context *ctx, const char *mname,
- bool casesense, int nparam, Token *expansion)
+ bool casesense, int nparam,
+ bool *eval_param, Token *expansion)
{
SMacro *smac, **smhead;
struct hash_table *smtbl;
@@ -2111,8 +2204,13 @@ static SMacro *define_smacro(Context *ctx, const char *mname,
smac->name = nasm_strdup(mname);
smac->casesense = casesense;
smac->nparam = nparam;
+ smac->eval_param = eval_param;
smac->expansion = expansion;
smac->expand = smacro_expand_default;
+
+ if (list_option('m'))
+ list_smacro_def(casesense ? PP_DEFINE : PP_IDEFINE, ctx, smac);
+
return smac;
}
@@ -2134,6 +2232,8 @@ static void undef_smacro(Context *ctx, const char *mname)
sp = smhead;
while ((s = *sp) != NULL) {
if (!mstrcmp(s->name, mname, s->casesense)) {
+ if (list_option('m'))
+ list_smacro_def(PP_UNDEF, ctx, s);
*sp = s->next;
free_smacro(s);
} else {
@@ -2711,6 +2811,7 @@ static int do_directive(Token *tline, Token **output)
if (i == PP_PUSH) {
nasm_new(ctx);
+ ctx->depth = cstk ? cstk->depth + 1 : 1;
ctx->next = cstk;
ctx->name = p;
ctx->number = unique++;
@@ -3149,8 +3250,8 @@ issue_error:
case PP_DEFINE:
case PP_XDEFINE:
{
- SMacro *s;
bool have_eval_params = false;
+ bool *eval_params = NULL;
tline = tline->next;
skip_white_(tline);
@@ -3184,12 +3285,30 @@ issue_error:
if (tok_is_(tline, "=")) {
have_eval_params = true;
tline = tline->next;
+ skip_white_(tline);
}
+
+ /*
+ * "*" means an unnamed, ignored argument; it can never
+ * match anything because "*" is not TOK_ID, and so
+ * none of the expansion entries will be converted
+ * to parameters.
+ */
if (tline->type != TOK_ID) {
- nasm_nonfatal("`%s': parameter identifier expected",
- tline->text);
- free_tlist(origline);
- return DIRECTIVE_FOUND;
+ if (tok_is_(tline, ",") || tok_is_(tline, ")")) {
+ /*
+ * Empty name; duplicate the termination
+ * token and use the first copy as a placeholder.
+ * It will never match anything, since the
+ * associated text doesn't correspond to a TOK_ID.
+ */
+ tline = dup_Token(tline, tline);
+ } else {
+ nasm_nonfatal("`%s': parameter identifier expected",
+ tline->text);
+ free_tlist(origline);
+ return DIRECTIVE_FOUND;
+ }
}
tline->type = tok_smac_param(nparam++);
tline = tline->next;
@@ -3207,7 +3326,20 @@ issue_error:
}
last = tline;
tline = tline->next;
+
+ if (have_eval_params) {
+ /* Create evaluated parameters table */
+ bool is_eval = false;
+
+ nasm_newn(eval_params, nparam);
+ list_for_each(tt, param_start) {
+ if (is_smac_param(tt->type))
+ eval_params[smac_nparam(tt->type)] = is_eval;
+ is_eval = tok_is_(tt, "=");
+ }
+ }
}
+
if (tok_type_(tline, TOK_WHITESPACE))
last = tline, tline = tline->next;
last->next = NULL;
@@ -3239,20 +3371,7 @@ issue_error:
* carefully re-terminated after chopping off the expansion
* from the end).
*/
- s = define_smacro(ctx, mname, casesense, nparam, macro_start);
-
- if (have_eval_params) {
- /* Create evaluated parameters table */
- bool is_eval = false;
-
- nasm_newn(s->eval_param, nparam);
- list_for_each(tt, param_start) {
- if (is_smac_param(tt->type))
- s->eval_param[smac_nparam(tt->type)] = is_eval;
- is_eval = tok_is_(tt, "=");
- }
- }
-
+ define_smacro(ctx, mname, casesense, nparam, eval_params, macro_start);
free_tlist(origline);
return DIRECTIVE_FOUND;
@@ -3310,7 +3429,7 @@ issue_error:
* zero, and a string token to use as an expansion. Create
* and store an SMacro.
*/
- define_smacro(ctx, mname, casesense, 0, macro_start);
+ define_smacro(ctx, mname, casesense, 0, NULL, macro_start);
free_tlist(origline);
return DIRECTIVE_FOUND;
@@ -3357,7 +3476,7 @@ issue_error:
* zero, and a numeric token to use as an expansion. Create
* and store an SMacro.
*/
- define_smacro(ctx, mname, casesense, 0, macro_start);
+ define_smacro(ctx, mname, casesense, 0, NULL, macro_start);
free_tlist(tline);
free_tlist(origline);
return DIRECTIVE_FOUND;
@@ -3411,7 +3530,7 @@ issue_error:
* zero, and a string token to use as an expansion. Create
* and store an SMacro.
*/
- define_smacro(ctx, mname, casesense, 0, macro_start);
+ define_smacro(ctx, mname, casesense, 0, NULL, macro_start);
free_tlist(tline);
free_tlist(origline);
return DIRECTIVE_FOUND;
@@ -3454,7 +3573,7 @@ issue_error:
* zero, and a numeric token to use as an expansion. Create
* and store an SMacro.
*/
- define_smacro(ctx, mname, casesense, 0, macro_start);
+ define_smacro(ctx, mname, casesense, 0, NULL, macro_start);
free_tlist(tline);
free_tlist(origline);
return DIRECTIVE_FOUND;
@@ -3513,7 +3632,7 @@ issue_error:
*/
macro_start = make_tok_qstr(pp);
nasm_free(pp);
- define_smacro(ctx, mname, casesense, 0, macro_start);
+ define_smacro(ctx, mname, casesense, 0, NULL, macro_start);
free_tlist(tline);
free_tlist(origline);
return DIRECTIVE_FOUND;
@@ -3612,7 +3731,7 @@ issue_error:
* zero, and a numeric token to use as an expansion. Create
* and store an SMacro.
*/
- define_smacro(ctx, mname, casesense, 0, macro_start);
+ define_smacro(ctx, mname, casesense, 0, NULL, macro_start);
free_tlist(tline);
free_tlist(origline);
return DIRECTIVE_FOUND;
@@ -3663,7 +3782,7 @@ issue_error:
* zero, and a numeric token to use as an expansion. Create
* and store an SMacro.
*/
- define_smacro(ctx, mname, casesense, 0, macro_start);
+ define_smacro(ctx, mname, casesense, 0, NULL, macro_start);
free_tlist(origline);
return DIRECTIVE_FOUND;
@@ -4362,10 +4481,8 @@ static bool expand_one_smacro(Token ***tpp)
paren--;
if (!paren) {
skip = true;
- if (nparam > 0 || *phead) {
- /* Count the final argument unless just () */
- nparam++;
- }
+ /* Count the final argument */
+ nparam++;
}
}
break;
@@ -5158,7 +5275,7 @@ static void pp_add_magic_stdmac(void)
SMacro *s;
for (m = magic_macros; m->name; m++) {
- s = define_smacro(NULL, m->name, true, m->nparams, NULL);
+ s = define_smacro(NULL, m->name, true, m->nparams, NULL, NULL);
s->expand = m->func;
}
}
@@ -5226,7 +5343,7 @@ pp_reset(const char *file, enum preproc_mode mode, struct strlist *dep_list)
panic();
}
- define_smacro(NULL, "__PASS__", true, 0, make_tok_num(apass));
+ define_smacro(NULL, "__PASS__", true, 0, NULL, make_tok_num(apass));
}
static void pp_init(void)
@@ -5465,6 +5582,12 @@ static char *pp_getline(void)
}
}
+ if (list_option('e') && line && line[0]) {
+ char *buf = nasm_strcat(" ;;; ", line);
+ lfmt->line(LIST_MACRO, buf);
+ nasm_free(buf);
+ }
+
nasm_set_verror(real_verror);
return line;
}
diff --git a/include/strlist.h b/include/strlist.h
index 610aad4d..2c80d0be 100644
--- a/include/strlist.h
+++ b/include/strlist.h
@@ -46,6 +46,7 @@ struct strlist_entry {
struct strlist_entry *next;
size_t offset;
size_t size;
+ intorptr pvt;
char str[1];
};
@@ -61,6 +62,12 @@ strlist_head(const struct strlist *list)
{
return list ? list->head : NULL;
}
+static inline struct strlist_entry *strlist_tail(struct strlist *list)
+{
+ if (!list || !list->head)
+ return NULL;
+ return container_of(list->tailp, struct strlist_entry, next);
+}
static inline size_t strlist_count(const struct strlist *list)
{
return list ? list->nstr : 0;
diff --git a/test/evalmacro.asm b/test/evalmacro.asm
index 0dd668dd..f93f6939 100644
--- a/test/evalmacro.asm
+++ b/test/evalmacro.asm
@@ -2,3 +2,12 @@
dd tonum(1+3)
dd tonum(5*7)
+
+%define mixed(a,=b,c) (a + b)
+%define mixed2(a,=b,) (a + b)
+%define ALPHA (1 + 2)
+%define BETA (3 + 4)
+%define GAMMA (5 + 6)
+
+ dd mixed(ALPHA, BETA, GAMMA)
+ dd mixed2(ALPHA, BETA, GAMMA)