aboutsummaryrefslogtreecommitdiffstats
path: root/asm
diff options
context:
space:
mode:
authorH. Peter Anvin (Intel) <hpa@zytor.com>2020-08-25 16:16:09 -0700
committerH. Peter Anvin (Intel) <hpa@zytor.com>2020-08-25 16:16:09 -0700
commitcc843efa38bd6a4622ce046e51a192a05580fa4a (patch)
tree8c5b05bafda40161c8957e1bc3d6181a86418799 /asm
parent1227a5d7fbf2d5ad691a5940c4c32ced83477089 (diff)
parent717348304378b9148e3e87d41bf54f67d36dee72 (diff)
downloadnasm-cc843efa38bd6a4622ce046e51a192a05580fa4a.tar.gz
nasm-cc843efa38bd6a4622ce046e51a192a05580fa4a.tar.xz
nasm-cc843efa38bd6a4622ce046e51a192a05580fa4a.zip
Merge tag 'nasm-2.15.04'
NASM 2.15.04 Conflicts: asm/listing.h asm/pptok.pl asm/preproc.c version This doesn't pass travis test 3392711, which is using an extremely odd construct of %?? in the middle of an argument sequence for an smacro while not being in a macro itself, and expecting it to expand to the macro name. This seems to *really* confuse the master branch. Resolve this later...
Diffstat (limited to 'asm')
-rw-r--r--asm/assemble.c19
-rw-r--r--asm/eval.c2
-rw-r--r--asm/listing.c2
-rw-r--r--asm/listing.h17
-rw-r--r--asm/nasm.c4
-rw-r--r--asm/parser.c16
-rw-r--r--asm/preproc.c175
-rwxr-xr-xasm/warnings.pl23
8 files changed, 187 insertions, 71 deletions
diff --git a/asm/assemble.c b/asm/assemble.c
index cd9222c4..ecf5c093 100644
--- a/asm/assemble.c
+++ b/asm/assemble.c
@@ -1246,7 +1246,7 @@ static int64_t calcsize(int32_t segment, int64_t offset, int bits,
enum ea_type eat;
uint8_t hleok = 0;
bool lockcheck = true;
- enum reg_enum mib_index = R_none; /* For a separate index MIB reg form */
+ enum reg_enum mib_index = R_none; /* For a separate index reg form */
const char *errmsg;
ins->rex = 0; /* Ensure REX is reset */
@@ -1282,7 +1282,7 @@ static int64_t calcsize(int32_t segment, int64_t offset, int bits,
break;
case4(014):
- /* this is an index reg of MIB operand */
+ /* this is an index reg of a split SIB operand */
mib_index = opx->basereg;
break;
@@ -1612,6 +1612,10 @@ static int64_t calcsize(int32_t segment, int64_t offset, int bits,
}
}
+ /* SIB encoding required */
+ if (itemp_has(temp, IF_SIB))
+ opy->eaflags |= EAF_SIB;
+
if (process_ea(opy, &ea_data, bits,
rfield, rflags, ins, &errmsg) != eat) {
nasm_nonfatal("%s", errmsg);
@@ -2833,9 +2837,8 @@ static enum ea_type process_ea(operand *input, ea *output, int bits,
}
}
- if (bits == 64 &&
- !(IP_REL & ~input->type) && (eaflags & EAF_MIB)) {
- *errmsg = "RIP-relative addressing is prohibited for MIB";
+ if (bits == 64 && !(IP_REL & ~input->type) && (eaflags & EAF_SIB)) {
+ *errmsg = "instruction requires SIB encoding, cannot be RIP-relative";
goto err;
}
@@ -2844,7 +2847,7 @@ static enum ea_type process_ea(operand *input, ea *output, int bits,
input->disp_size != (addrbits != 16 ? 32 : 16)))
nasm_warn(WARN_OTHER, "displacement size ignored on absolute address");
- if ((eaflags & EAF_MIB) || (bits == 64 && (~input->type & IP_REL))) {
+ if ((eaflags & EAF_SIB) || (bits == 64 && (~input->type & IP_REL))) {
output->sib_present = true;
output->sib = GEN_SIB(0, 4, 5);
output->bytes = 4;
@@ -3022,7 +3025,7 @@ static enum ea_type process_ea(operand *input, ea *output, int bits,
bt = it, bx = ix, it = -1, ix = 0;
}
if (eaflags & EAF_MIB) {
- /* only for mib operands */
+ /* MIB/split-SIB encoding */
if (it == -1 && (hb == b && ht == EAH_NOTBASE)) {
/*
* make a single reg index [reg*1].
@@ -3063,7 +3066,7 @@ static enum ea_type process_ea(operand *input, ea *output, int bits,
output->rex |= rexflags(it, ix, REX_X);
output->rex |= rexflags(bt, bx, REX_B);
- if (it == -1 && (bt & 7) != REG_NUM_ESP && !(eaflags & EAF_MIB)) {
+ if (it == -1 && (bt & 7) != REG_NUM_ESP && !(eaflags & EAF_SIB)) {
/* no SIB needed */
int mod, rm;
diff --git a/asm/eval.c b/asm/eval.c
index 5d6ee1e7..80fb4a28 100644
--- a/asm/eval.c
+++ b/asm/eval.c
@@ -727,7 +727,7 @@ static expr *eval_floatize(enum floatize type)
len = fmt->bytes - fmt->offset;
if (len > 8)
len = 8; /* Max 64 bits */
- p = result + len;
+ p = result + len + fmt->offset;
val = 0;
for (i = len; i; i--) {
p--;
diff --git a/asm/listing.c b/asm/listing.c
index 49b76401..186b8b4e 100644
--- a/asm/listing.c
+++ b/asm/listing.c
@@ -340,7 +340,7 @@ static void list_downlevel(int type)
}
}
-static void list_error(errflags severity, const char *fmt, ...)
+static void printf_func(2, 3) list_error(errflags severity, const char *fmt, ...)
{
va_list ap;
diff --git a/asm/listing.h b/asm/listing.h
index cb64119b..639a56ee 100644
--- a/asm/listing.h
+++ b/asm/listing.h
@@ -1,6 +1,6 @@
/* ----------------------------------------------------------------------- *
*
- * Copyright 1996-2019 The NASM Authors - All Rights Reserved
+ * Copyright 1996-2020 The NASM Authors - All Rights Reserved
* See the file AUTHORS included with the NASM distribution for
* the specific copyright holders.
*
@@ -140,9 +140,10 @@ extern uint64_t list_options, active_list_options;
* computation is needed is when parsing the -L option or %pragma list
* options, neither of which is in any way performance critical.
*
- * The character + represents ALL listing options.
+ * The character + represents ALL listing options except -Lw (flush
+ * after every line.)
*/
-static inline const_func uint64_t list_option_mask(unsigned char x)
+static inline const_func uint64_t list_option_mask_val(unsigned char x)
{
if (x >= 'a') {
if (x > 'z')
@@ -156,8 +157,6 @@ static inline const_func uint64_t list_option_mask(unsigned char x)
if (x > '9')
return 0;
x = x - '0' + 2 + 26*2;
- } else if (x == '+') {
- return ~UINT64_C(1);
} else {
return 0;
}
@@ -165,6 +164,14 @@ static inline const_func uint64_t list_option_mask(unsigned char x)
return UINT64_C(1) << x;
}
+static inline const_func uint64_t list_option_mask(unsigned char x)
+{
+ if (x == '+')
+ return ~(list_option_mask_val('w') | 3);
+ else
+ return list_option_mask_val(x);
+}
+
/* Return true if the listing engine is active and a certain option is set. */
static inline pure_func bool list_option(unsigned char x)
{
diff --git a/asm/nasm.c b/asm/nasm.c
index a7ad4510..5c5c55d7 100644
--- a/asm/nasm.c
+++ b/asm/nasm.c
@@ -2263,8 +2263,8 @@ static void help(FILE *out)
" -Lm show multi-line macro calls with expanded parmeters\n"
" -Lp output a list file every pass, in case of errors\n"
" -Ls show all single-line macro definitions\n"
- " -Lw flush the output after every line\n"
- " -L+ enable all listing options (very verbose!)\n"
+ " -Lw flush the output after every line (very slow!)\n"
+ " -L+ enable all listing options except -Lw (very verbose!)\n"
"\n"
" -Oflags... optimize opcodes, immediates and branch offsets\n"
" -O0 no optimization\n"
diff --git a/asm/parser.c b/asm/parser.c
index dbd2240c..584e40c9 100644
--- a/asm/parser.c
+++ b/asm/parser.c
@@ -458,11 +458,17 @@ static int parse_eops(extop **result, bool critical, int elem)
/* Subexpression is empty */
eop->type = EOT_NOTHING;
} else if (!subexpr->next) {
- /* Subexpression is a single element, flatten */
- eop->val = subexpr->val;
- eop->type = subexpr->type;
- eop->dup *= subexpr->dup;
- nasm_free(subexpr);
+ /*
+ * Subexpression is a single element, flatten.
+ * Note that if subexpr has an allocated buffer associated
+ * with it, freeing it would free the buffer, too, so
+ * we need to move subexpr up, not eop down.
+ */
+ if (!subexpr->elem)
+ subexpr->elem = eop->elem;
+ subexpr->dup *= eop->dup;
+ nasm_free(eop);
+ eop = subexpr;
} else {
eop->type = EOT_EXTOP;
}
diff --git a/asm/preproc.c b/asm/preproc.c
index b64c8fab..28c27060 100644
--- a/asm/preproc.c
+++ b/asm/preproc.c
@@ -1347,6 +1347,11 @@ static Token *tokenize(const char *line)
p++;
if (*p == '?')
p++;
+ } else if (*p == '*' && p[1] == '?') {
+ /* %*? and %*?? */
+ p += 2;
+ if (*p == '?')
+ p++;
} else if (*p == '!') {
/* Environment variable reference */
p++;
@@ -1407,6 +1412,16 @@ static Token *tokenize(const char *line)
type = TOKEN_PREPROC_ID;
break;
+ case '*':
+ type = TOKEN_OTHER;
+ if (line[2] == '?') {
+ if (toklen == 3)
+ type = TOKEN_PREPROC_SQ;
+ else if (toklen == 4 && line[3] == '?')
+ type = TOKEN_PREPROC_SQQ;
+ }
+ break;
+
case '!':
type = (toklen == 2) ? TOKEN_OTHER : TOKEN_ENVIRON;
break;
@@ -2335,9 +2350,8 @@ restart:
continue;
}
}
- if (defn) {
- *defn = (nparam == m->nparam || nparam == -1) ? m : NULL;
- }
+ if (defn)
+ *defn = m;
return true;
}
m = m->next;
@@ -2986,7 +3000,8 @@ static SMacro *define_smacro(const char *mname, bool casesense,
struct hash_table *smtbl;
Context *ctx;
bool defining_alias = false;
- unsigned int nparam = 0;
+ int nparam = 0;
+ bool defined;
if (tmpl) {
defining_alias = tmpl->alias;
@@ -2995,48 +3010,101 @@ static SMacro *define_smacro(const char *mname, bool casesense,
mark_smac_params(expansion, tmpl, 0);
}
- while (1) {
- ctx = get_ctx(mname, &mname);
-
- if (!smacro_defined(ctx, mname, nparam, &smac, casesense, true)) {
- /* Create a new macro */
- smtbl = ctx ? &ctx->localmac : &smacros;
- smhead = (SMacro **) hash_findi_add(smtbl, mname);
- nasm_new(smac);
- smac->next = *smhead;
- *smhead = smac;
- break;
- } else if (!smac) {
- nasm_warn(WARN_OTHER, "single-line macro `%s' defined both with and"
- " without parameters", mname);
+ ctx = get_ctx(mname, &mname);
+
+ defined = smacro_defined(ctx, mname, nparam, &smac, casesense, true);
+
+ if (defined) {
+ if (smac->alias) {
+ if (smac->in_progress) {
+ nasm_nonfatal("macro alias loop");
+ goto fail;
+ }
+
+ if (!defining_alias && !ppconf.noaliases) {
+ /* It is an alias macro; follow the alias link */
+ SMacro *s;
+
+ smac->in_progress = true;
+ s = define_smacro(tok_text(smac->expansion), casesense,
+ expansion, tmpl);
+ smac->in_progress = false;
+ return s;
+ }
+ }
+
+ if (casesense ^ smac->casesense) {
/*
- * Some instances of the old code considered this a failure,
- * some others didn't. What is the right thing to do here?
+ *!macro-def-case-single [on] single-line macro defined both case sensitive and insensitive
+ *! warns when a single-line macro is defined both case
+ *! sensitive and case insensitive.
+ *! The new macro
+ *! definition will override (shadow) the original one,
+ *! although the original macro is not deleted, and will
+ *! be re-exposed if the new macro is deleted with
+ *! \c{%undef}, or, if the original macro is the case
+ *! insensitive one, the macro call is done with a
+ *! different case.
*/
- goto fail;
- } else if (!smac->alias || ppconf.noaliases || defining_alias) {
+ nasm_warn(WARN_MACRO_DEF_CASE_SINGLE, "case %ssensitive definition of macro `%s' will shadow %ssensitive macro `%s'",
+ casesense ? "" : "in",
+ mname,
+ smac->casesense ? "" : "in",
+ smac->name);
+ defined = false;
+ } else if ((!!nparam) ^ (!!smac->nparam)) {
/*
- * We're redefining, so we have to take over an
- * existing SMacro structure. This means freeing
- * what was already in it, but not the structure itself.
+ * Most recent versions of NASM considered this an error,
+ * so promote this warning to error by default.
+ *
+ *!macro-def-param-single [err] single-line macro defined with and without parameters
+ *! warns if the same single-line macro is defined with and
+ *! without parameters.
+ *! The new macro
+ *! definition will override (shadow) the original one,
+ *! although the original macro is not deleted, and will
+ *! be re-exposed if the new macro is deleted with
+ *! \c{%undef}.
*/
- clear_smacro(smac);
- break;
- } else if (smac->in_progress) {
- nasm_nonfatal("macro alias loop");
- goto fail;
- } else {
- /* It is an alias macro; follow the alias link */
- SMacro *s;
-
- smac->in_progress = true;
- s = define_smacro(tok_text(smac->expansion), casesense,
- expansion, tmpl);
- smac->in_progress = false;
- return s;
+ nasm_warn(WARN_MACRO_DEF_PARAM_SINGLE,
+ "macro `%s' defined both with and without parameters",
+ mname);
+ defined = false;
+ } else if (smac->nparam < nparam) {
+ /*
+ *!macro-def-greedy-single [on] single-line macro
+ *! definition shadows greedy macro warns when a
+ *! single-line macro is defined which would match a
+ *! previously existing greedy definition. The new macro
+ *! definition will override (shadow) the original one,
+ *! although the original macro is not deleted, and will
+ *! be re-exposed if the new macro is deleted with
+ *! \c{%undef}, and will be invoked if called with a
+ *! parameter count that does not match the new definition.
+ */
+ nasm_warn(WARN_MACRO_DEF_GREEDY_SINGLE,
+ "defining macro `%s' shadows previous greedy definition",
+ mname);
+ defined = false;
}
}
+ if (defined) {
+ /*
+ * We're redefinining, so we have to take over an
+ * existing SMacro structure. This means freeing
+ * what was already in it, but not the structure itself.
+ */
+ clear_smacro(smac);
+ } else {
+ /* Create a new macro */
+ smtbl = ctx ? &ctx->localmac : &smacros;
+ smhead = (SMacro **) hash_findi_add(smtbl, mname);
+ nasm_new(smac);
+ smac->next = *smhead;
+ *smhead = smac;
+ }
+
smac->name = nasm_strdup(mname);
smac->casesense = casesense;
smac->expansion = reverse_tokens(expansion);
@@ -3660,6 +3728,9 @@ static int do_directive(Token *tline, Token **output)
break;
case PP_STACKSIZE:
+ {
+ const char *arg;
+
/* Directive to tell NASM what the default stack size is. The
* default is for a 16-bit stack, and this can be overriden with
* %stacksize large.
@@ -3667,20 +3738,24 @@ static int do_directive(Token *tline, Token **output)
tline = skip_white(tline->next);
if (!tline || tline->type != TOKEN_ID) {
nasm_nonfatal("`%s' missing size parameter", dname);
+ break;
}
- if (nasm_stricmp(tok_text(tline), "flat") == 0) {
+
+ arg = tok_text(tline);
+
+ if (nasm_stricmp(arg, "flat") == 0) {
/* All subsequent ARG directives are for a 32-bit stack */
StackSize = 4;
StackPointer = "ebp";
ArgOffset = 8;
LocalOffset = 0;
- } else if (nasm_stricmp(tok_text(tline), "flat64") == 0) {
+ } else if (nasm_stricmp(arg, "flat64") == 0) {
/* All subsequent ARG directives are for a 64-bit stack */
StackSize = 8;
StackPointer = "rbp";
ArgOffset = 16;
LocalOffset = 0;
- } else if (nasm_stricmp(tok_text(tline), "large") == 0) {
+ } else if (nasm_stricmp(arg, "large") == 0) {
/* All subsequent ARG directives are for a 16-bit stack,
* far function call.
*/
@@ -3688,7 +3763,7 @@ static int do_directive(Token *tline, Token **output)
StackPointer = "bp";
ArgOffset = 4;
LocalOffset = 0;
- } else if (nasm_stricmp(tok_text(tline), "small") == 0) {
+ } else if (nasm_stricmp(arg, "small") == 0) {
/* All subsequent ARG directives are for a 16-bit stack,
* far function call. We don't support near functions.
*/
@@ -3700,6 +3775,7 @@ static int do_directive(Token *tline, Token **output)
nasm_nonfatal("`%s' invalid size type", dname);
}
break;
+ }
case PP_ARG:
/* TASM like ARG directive to define arguments to functions, in
@@ -5609,15 +5685,17 @@ static SMacro *expand_one_smacro(Token ***tpp)
switch (type) {
case TOKEN_PREPROC_Q:
+ case TOKEN_PREPROC_SQ:
delete_Token(t);
t = dup_Token(tline, mstart);
break;
case TOKEN_PREPROC_QQ:
+ case TOKEN_PREPROC_SQQ:
{
size_t mlen = strlen(m->name);
size_t len;
- char *p;
+ char *p, *from;
t->type = mstart->type;
if (t->type == TOKEN_LOCAL_MACRO) {
@@ -5630,15 +5708,15 @@ static SMacro *expand_one_smacro(Token ***tpp)
plen = pep - psp;
len = mlen + plen;
- p = nasm_malloc(len + 1);
+ from = p = nasm_malloc(len + 1);
p = mempcpy(p, psp, plen);
} else {
len = mlen;
- p = nasm_malloc(len + 1);
+ from = p = nasm_malloc(len + 1);
}
p = mempcpy(p, m->name, mlen);
*p = '\0';
- set_text_free(t, p, len);
+ set_text_free(t, from, len);
t->next = tline;
break;
@@ -6974,6 +7052,9 @@ static Token *pp_tokline(void)
free_tlist(m->iline);
nasm_free(m->paramlen);
fm->in_progress = 0;
+ m->params = NULL;
+ m->iline = NULL;
+ m->paramlen = NULL;
}
}
diff --git a/asm/warnings.pl b/asm/warnings.pl
index 8a79568a..6660d17a 100755
--- a/asm/warnings.pl
+++ b/asm/warnings.pl
@@ -1,6 +1,7 @@
#!/usr/bin/perl
use strict;
+use Fcntl qw(:seek);
use File::Find;
use File::Basename;
@@ -134,8 +135,9 @@ sub sort_warnings {
my @warn_noall = @warnings;
pop @warn_noall if ($warn_noall[$#warn_noall]->{name} eq 'all');
-open(my $out, '>', $outfile)
- or die "$0: cannot open output file $outfile: $!\n";
+my $outdata;
+open(my $out, '>', \$outdata)
+ or die "$0: cannot create memory file: $!\n";
if ($what eq 'c') {
print $out "#include \"error.h\"\n\n";
@@ -273,4 +275,21 @@ if ($what eq 'c') {
print $out "\\b \\i\\c{", $pfx, "} ", @doc, "\n";
}
}
+
+close($out);
+
+# Write data to file if and only if it has changed
+# Windows requires append mode here
+open($out, '+>>', $outfile)
+ or die "$0: cannot open output file $outfile: $!\n";
+my $datalen = length($outdata);
+my $oldlen = read($out, my $oldoutdata, $datalen+1);
+if (!defined($oldlen) || $oldlen != $datalen ||
+ !($oldoutdata eq $outdata)) {
+ # Data changed, must rewrite
+ truncate($out, 0);
+ seek($out, 0, SEEK_SET)
+ or die "$0: cannot rewind output file $outfile: $!\n";
+ print $out $outdata;
+}
close($out);