mirror of
https://github.com/bminor/binutils-gdb.git
synced 2025-11-16 04:24:43 +00:00
gas: Revert PR 32391 related commits to fix 3 regressions
9f2e3c21f6 Fix the handling or arguments and macro pseudo-variables inside nested assembler macros.
introduced 3 regressions of PR gas/32484, PR gas/32486 and PR gas/32487.
Revert all PR 32391 related commits and add tests for PR gas/32484,
PR gas/32486, PR gas/32487.
PR gas/32484
PR gas/32486
PR gas/32487
* testsuite/gas/macros/macros.exp: Run nesting1, nesting2 and
nesting3.
* testsuite/gas/macros/nesting1.d: New file.
* testsuite/gas/macros/nesting1.s: Likewise.
* testsuite/gas/macros/nesting2.d: Likewise.
* testsuite/gas/macros/nesting2.s: Likewise.
* testsuite/gas/macros/nesting3.d: Likewise.
* testsuite/gas/macros/nesting3.s: Likewise.
Signed-off-by: H.J. Lu <hjl.tools@gmail.com>
This commit is contained in:
@@ -105,6 +105,8 @@ struct iq2000_hi_fixup
|
||||
/* The list of unmatched HI relocs. */
|
||||
static struct iq2000_hi_fixup * iq2000_hi_fixup_list;
|
||||
|
||||
/* Macro hash table, which we will add to. */
|
||||
extern struct htab *macro_hash;
|
||||
|
||||
const char md_shortopts[] = "";
|
||||
const struct option md_longopts[] =
|
||||
@@ -277,7 +279,9 @@ iq2000_add_macro (const char * name,
|
||||
}
|
||||
}
|
||||
|
||||
(void) add_macro (macro, true);
|
||||
str_hash_insert (macro_hash, macro->name, macro, 1);
|
||||
|
||||
macro_defined = 1;
|
||||
}
|
||||
|
||||
static void
|
||||
|
||||
@@ -6215,12 +6215,7 @@ With that definition, @samp{SUM 0,5} is equivalent to this assembly input:
|
||||
@item .macro @var{macname}
|
||||
@itemx .macro @var{macname} @var{macargs} @dots{}
|
||||
@cindex @code{macro} directive
|
||||
Begin the definition of a macro called @var{macname}. Macro names are case
|
||||
insensitive. Macro definitions can be nested, although their behaviour is
|
||||
sometimes counter intuitive. Nested macros only have scope within their
|
||||
defining macro.
|
||||
|
||||
If your macro
|
||||
Begin the definition of a macro called @var{macname}. If your macro
|
||||
definition requires arguments, specify their names after the macro name,
|
||||
separated by commas or spaces. You can qualify the macro argument to
|
||||
indicate whether all invocations must specify a non-blank value (through
|
||||
@@ -6385,29 +6380,6 @@ adjacent string literals - even if separated only by a blank - will not be
|
||||
concatenated when determining macro arguments, even if they're only separated
|
||||
by white space. This is unlike certain other pseudo ops, e.g. @code{.ascii}.
|
||||
|
||||
Nested macros can access the arguments of their parents. But also if their
|
||||
argument names clash with those of their parents, their versions are used. So
|
||||
for example:
|
||||
|
||||
@smallexample
|
||||
.macro OUTER arg1, arg2, arg3:vararg
|
||||
.macro INNER arg4 arg2
|
||||
.dc.a \arg2
|
||||
.dc.a \arg3
|
||||
.endm
|
||||
INNER \arg1 bert
|
||||
.dc.a \arg2
|
||||
.endm
|
||||
|
||||
OUTER fred, jim, harry\arg4
|
||||
@end smallexample
|
||||
|
||||
This will generate references to symbols called @samp{jim} - from the
|
||||
definition of the OUTER macro, @samp{bert} - from the definition in INNER
|
||||
where arg2 has been overridden and @samp{harryfred} - from the definition in
|
||||
INNER where the value of arg3 from OUTER is used, but with the value of arg4
|
||||
substituted into the symbol.
|
||||
|
||||
@item .endm
|
||||
@cindex @code{endm} directive
|
||||
Mark the end of a macro definition.
|
||||
@@ -6423,33 +6395,6 @@ Exit early from the current macro definition.
|
||||
executed in this pseudo-variable; you can copy that number to your
|
||||
output with @samp{\@@}, but @emph{only within a macro definition}.
|
||||
|
||||
Note - the @samp{\@@} counter is incremented at the end of the expansion of a
|
||||
macro, but before the contents of any nested macros are evaluated. This can
|
||||
lead to counter-intuitive behaviour when nested macros are used. For example:
|
||||
|
||||
@smallexample
|
||||
.macro o
|
||||
.macro i
|
||||
_i\@@_:
|
||||
.endm
|
||||
i
|
||||
_o\@@_:
|
||||
.endm
|
||||
o
|
||||
@end smallexample
|
||||
|
||||
Produces two symbols @samp{_o0_} and @samp{_i1_}. This happens because the
|
||||
@samp{o} macro executes entirely first, putting the definition and invocation
|
||||
of the @samp{i} macro into the input buffer. It also puts the definition of
|
||||
the @samp{_o\@@_} symbol into the input buffer, evaluating the @samp{\@@}
|
||||
counter in the process and so generating a symbol called @samp{_o0_}.
|
||||
|
||||
That finishes the invocation of @samp{o} so the @samp{\@@} counter is
|
||||
incremented. Then the input buffer is re-evaluated and the definition and
|
||||
invocation of macro @samp{i} is found. This results in @samp{_i\@@_} being put
|
||||
into the input buffer and this time @samp{\@@} evaluates to 1, so the symbol
|
||||
created is @samp{_i1_}.
|
||||
|
||||
@cindex number of times a macro has been executed
|
||||
@cindex macro, execution count
|
||||
@item \+
|
||||
@@ -6736,9 +6681,6 @@ those explicitly specified with @code{.eject}.
|
||||
Undefine the macro @var{name}, so that later uses of the string will not be
|
||||
expanded. @xref{Macro}.
|
||||
|
||||
Note - nested macros are automatically purged at the end of the macro that
|
||||
defines them.
|
||||
|
||||
@ifset ELF
|
||||
@node PushSection
|
||||
@section @code{.pushsection @var{name} [, @var{subsection}] [, "@var{flags}"[, @@@var{type}[,@var{arguments}]]]}
|
||||
|
||||
@@ -23,7 +23,6 @@
|
||||
#include "input-file.h"
|
||||
#include "sb.h"
|
||||
#include "listing.h"
|
||||
#include "macro.h"
|
||||
|
||||
/*
|
||||
* O/S independent module to supply buffers of sanitised source code
|
||||
@@ -291,13 +290,12 @@ input_scrub_include_sb (sb *from, char *position, enum expansion expansion)
|
||||
++macro_nest;
|
||||
}
|
||||
|
||||
#ifdef md_macro_start
|
||||
if (expansion == expanding_macro)
|
||||
{
|
||||
#ifdef md_macro_start
|
||||
md_macro_start ();
|
||||
#endif
|
||||
increment_macro_nesting_depth ();
|
||||
}
|
||||
#endif
|
||||
|
||||
next_saved_file = input_scrub_push (position);
|
||||
|
||||
@@ -352,7 +350,6 @@ input_scrub_next_buffer (char **bufp)
|
||||
data. */
|
||||
md_macro_end ();
|
||||
#endif
|
||||
decrement_macro_nesting_depth ();
|
||||
}
|
||||
if (from_sb_expansion != expanding_app)
|
||||
--macro_nest;
|
||||
|
||||
272
gas/macro.c
272
gas/macro.c
@@ -44,24 +44,11 @@
|
||||
|
||||
/* The macro hash table. */
|
||||
|
||||
/* Macro nesting depth. Similar to macro_nest defined in sb.c, but this
|
||||
counter is specific to macros, whereas macro_nest also counts repeated
|
||||
string blocks. */
|
||||
static unsigned int macro_nesting_depth;
|
||||
htab_t macro_hash;
|
||||
|
||||
/* Maximum nesting depth. Ideally the same as the value of max_macro_nest
|
||||
as defined in as.c (ie 100). But there is one test in the assembler
|
||||
testsuite (bfin/allinsn16.s) that nests macros to a depth of 8192. So
|
||||
we have a ridiculously large number here. */
|
||||
#define MAX_MACRO_DEPTH 8193
|
||||
/* Whether any macros have been defined. */
|
||||
|
||||
static htab_t macro_hash[MAX_MACRO_DEPTH];
|
||||
|
||||
/* Whether any macros have been defined.
|
||||
FIXME: This could be a counter that is incremented
|
||||
with .macro and decremented with .purgem. */
|
||||
|
||||
static bool macros_defined = false;
|
||||
int macro_defined;
|
||||
|
||||
/* Whether we should strip '@' characters. */
|
||||
|
||||
@@ -73,18 +60,6 @@ static unsigned int macro_number;
|
||||
|
||||
static void free_macro (macro_entry *);
|
||||
|
||||
bool
|
||||
add_macro (macro_entry * macro, bool replace)
|
||||
{
|
||||
if (str_hash_insert (macro_hash [macro_nesting_depth],
|
||||
macro->name, macro, replace) == NULL)
|
||||
{
|
||||
macros_defined = true;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
static void
|
||||
macro_del_f (void *ent)
|
||||
{
|
||||
@@ -97,23 +72,15 @@ macro_del_f (void *ent)
|
||||
void
|
||||
macro_init (void)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < MAX_MACRO_DEPTH; i++)
|
||||
macro_hash[i] = htab_create_alloc (16, hash_string_tuple, eq_string_tuple,
|
||||
macro_del_f, notes_calloc, NULL);
|
||||
macros_defined = false;
|
||||
macro_hash = htab_create_alloc (16, hash_string_tuple, eq_string_tuple,
|
||||
macro_del_f, notes_calloc, NULL);
|
||||
macro_defined = 0;
|
||||
}
|
||||
|
||||
void
|
||||
macro_end (void)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = MAX_MACRO_DEPTH; i--;)
|
||||
htab_delete (macro_hash[i]);
|
||||
|
||||
macros_defined = false;
|
||||
htab_delete (macro_hash);
|
||||
}
|
||||
|
||||
/* Read input lines till we get to a TO string.
|
||||
@@ -688,13 +655,6 @@ free_macro (macro_entry *macro)
|
||||
free (macro);
|
||||
}
|
||||
|
||||
static macro_entry * last_recorded_macro = NULL;
|
||||
void
|
||||
macro_record_invocation (macro_entry * macro)
|
||||
{
|
||||
last_recorded_macro = macro;
|
||||
}
|
||||
|
||||
/* Define a new macro. */
|
||||
|
||||
macro_entry *
|
||||
@@ -758,19 +718,15 @@ define_macro (sb *in, sb *label, size_t (*get_line) (sb *))
|
||||
/* And stick it in the macro hash table. */
|
||||
for (idx = 0; idx < name.len; idx++)
|
||||
name.ptr[idx] = TOLOWER (name.ptr[idx]);
|
||||
|
||||
if (macro_nesting_depth > 0)
|
||||
macro->parent = last_recorded_macro;
|
||||
else
|
||||
macro->parent = NULL;
|
||||
|
||||
if (!error)
|
||||
{
|
||||
if (! add_macro (macro, false))
|
||||
if (str_hash_insert (macro_hash, macro->name, macro, 0) != NULL)
|
||||
error = _("Macro `%s' was already defined");
|
||||
}
|
||||
|
||||
if (error != NULL)
|
||||
if (!error)
|
||||
macro_defined = 1;
|
||||
else
|
||||
{
|
||||
as_bad_where (macro->file, macro->line, error, macro->name);
|
||||
free_macro (macro);
|
||||
@@ -794,25 +750,11 @@ get_apost_token (size_t idx, sb *in, sb *name, int kind)
|
||||
return idx;
|
||||
}
|
||||
|
||||
static const char *
|
||||
macro_expand_body (sb *, sb *, formal_entry *, struct htab *,
|
||||
const macro_entry *, unsigned int);
|
||||
|
||||
/* Find the actual value for a formal parameter starting at START inside IN.
|
||||
Appends the value of parameter onto OUT.
|
||||
The hash table of formal parameters is provided by FORMAL_HASH.
|
||||
The character that indicated the presense of a formal parameter is passed
|
||||
in KIND.
|
||||
If COPYIFNOTTHERE is true and the parameter is not found in the hash table
|
||||
then it is appended as plain text onto OUT.
|
||||
The macro containing the formal parameters is passed in MACRO.
|
||||
This can be empty.
|
||||
Returns the offset inside IN after advanceing past the parameter.
|
||||
Also stores the parameter's name into T. */
|
||||
/* Substitute the actual value for a formal parameter. */
|
||||
|
||||
static size_t
|
||||
sub_actual (size_t start, sb *in, sb *t, struct htab *formal_hash,
|
||||
int kind, sb *out, int copyifnotthere, const macro_entry * macro)
|
||||
int kind, sb *out, int copyifnotthere)
|
||||
{
|
||||
size_t src;
|
||||
formal_entry *ptr;
|
||||
@@ -826,12 +768,16 @@ sub_actual (size_t start, sb *in, sb *t, struct htab *formal_hash,
|
||||
ptr = NULL;
|
||||
else
|
||||
ptr = str_hash_find (formal_hash, sb_terminate (t));
|
||||
|
||||
if (ptr)
|
||||
{
|
||||
sb * add = ptr->actual.len ? &ptr->actual : &ptr->def;
|
||||
|
||||
sb_add_sb (out, add);
|
||||
if (ptr->actual.len)
|
||||
{
|
||||
sb_add_sb (out, &ptr->actual);
|
||||
}
|
||||
else
|
||||
{
|
||||
sb_add_sb (out, &ptr->def);
|
||||
}
|
||||
}
|
||||
else if (kind == '&')
|
||||
{
|
||||
@@ -845,56 +791,6 @@ sub_actual (size_t start, sb *in, sb *t, struct htab *formal_hash,
|
||||
{
|
||||
sb_add_sb (out, t);
|
||||
}
|
||||
else if (!macro_strip_at
|
||||
&& macro_nesting_depth > 0
|
||||
&& macro != NULL
|
||||
&& macro->parent != NULL)
|
||||
{
|
||||
const macro_entry * orig_macro = macro;
|
||||
bool success = false;
|
||||
|
||||
/* We have failed to find T, but we are inside nested macros. So check
|
||||
the parent macros so see if they have a FORMAL that matches T. */
|
||||
while (macro->parent != NULL)
|
||||
{
|
||||
macro = macro->parent;
|
||||
|
||||
ptr = str_hash_find (macro->formal_hash, t->ptr);
|
||||
if (ptr == NULL)
|
||||
continue;
|
||||
|
||||
sb * add = ptr->actual.len ? &ptr->actual : &ptr->def;
|
||||
|
||||
/* The parent's FORMALs might contain parameters that need further
|
||||
substitution. See gas/testsuite/gas/arm/macro-vld1.s for an
|
||||
example of this. */
|
||||
if (memchr (add->ptr, '\\', add->len))
|
||||
{
|
||||
sb newadd;
|
||||
|
||||
sb_new (&newadd);
|
||||
/* FIXME: Should we do something if the call to
|
||||
macro_expand_body returns an error message ? */
|
||||
(void) macro_expand_body (add, &newadd, NULL, NULL,
|
||||
orig_macro, orig_macro->count);
|
||||
sb_add_sb (out, &newadd);
|
||||
sb_kill (&newadd);
|
||||
}
|
||||
else
|
||||
{
|
||||
sb_add_sb (out, add);
|
||||
}
|
||||
success = true;
|
||||
break;
|
||||
}
|
||||
if (! success)
|
||||
{
|
||||
/* We reached the outermost macro and failed to find T, so
|
||||
just copy the entire parameter as is. */
|
||||
sb_add_char (out, '\\');
|
||||
sb_add_sb (out, t);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
sb_add_char (out, '\\');
|
||||
@@ -903,12 +799,7 @@ sub_actual (size_t start, sb *in, sb *t, struct htab *formal_hash,
|
||||
return src;
|
||||
}
|
||||
|
||||
/* Expands the body of a macro / block of text IN, copying it into OUT.
|
||||
Parameters for substitution are found in FORMALS and FORMAL_HASH or
|
||||
MACRO.
|
||||
The number of times that this macro / block of text have already been
|
||||
copied into the output is held in INSTANCE.
|
||||
Returns NULL upon success or an error message otherwise. */
|
||||
/* Expand the body of a macro. */
|
||||
|
||||
static const char *
|
||||
macro_expand_body (sb *in, sb *out, formal_entry *formals,
|
||||
@@ -920,38 +811,18 @@ macro_expand_body (sb *in, sb *out, formal_entry *formals,
|
||||
int inquote = 0, macro_line = 0;
|
||||
formal_entry *loclist = NULL;
|
||||
const char *err = NULL;
|
||||
int nesting = 0;
|
||||
|
||||
if (formals == NULL && macro != NULL)
|
||||
formals = macro->formals;
|
||||
|
||||
if (formal_hash == NULL && macro != NULL)
|
||||
formal_hash = macro->formal_hash;
|
||||
|
||||
sb_new (&t);
|
||||
|
||||
while (src < in->len && !err)
|
||||
{
|
||||
if (in->ptr[src] == '.')
|
||||
{
|
||||
/* Check to see if we have encountered ".macro" or ".endm" */
|
||||
if (in->len > src + 5
|
||||
&& strncmp (in->ptr + src, ".macro", 6) == 0)
|
||||
++ nesting;
|
||||
|
||||
else if (in->len > src + 4
|
||||
&& strncmp (in->ptr + src, ".endm", 5) == 0)
|
||||
-- nesting;
|
||||
}
|
||||
|
||||
if (in->ptr[src] == '&')
|
||||
{
|
||||
sb_reset (&t);
|
||||
if (flag_mri)
|
||||
{
|
||||
if (src + 1 < in->len && in->ptr[src + 1] == '&')
|
||||
src = sub_actual (src + 2, in, &t, formal_hash,
|
||||
'\'', out, 1, macro);
|
||||
src = sub_actual (src + 2, in, &t, formal_hash, '\'', out, 1);
|
||||
else
|
||||
sb_add_char (out, in->ptr[src++]);
|
||||
}
|
||||
@@ -959,8 +830,7 @@ macro_expand_body (sb *in, sb *out, formal_entry *formals,
|
||||
{
|
||||
/* Permit macro parameter substitution delineated with
|
||||
an '&' prefix and optional '&' suffix. */
|
||||
src = sub_actual (src + 1, in, &t, formal_hash,
|
||||
'&', out, 0, macro);
|
||||
src = sub_actual (src + 1, in, &t, formal_hash, '&', out, 0);
|
||||
}
|
||||
}
|
||||
else if (in->ptr[src] == '\\')
|
||||
@@ -981,12 +851,7 @@ macro_expand_body (sb *in, sb *out, formal_entry *formals,
|
||||
else
|
||||
as_bad_where (macro->file, macro->line + macro_line, _("missing `)'"));
|
||||
}
|
||||
else if (src < in->len
|
||||
&& in->ptr[src] == '@'
|
||||
/* PR 32391: Do not perform the substition inside nested
|
||||
macros. Instead wait until they are re-evaluated and
|
||||
perform the substition then. */
|
||||
&& ! nesting)
|
||||
else if (src < in->len && in->ptr[src] == '@')
|
||||
{
|
||||
/* Sub in the total macro invocation number. */
|
||||
|
||||
@@ -995,12 +860,7 @@ macro_expand_body (sb *in, sb *out, formal_entry *formals,
|
||||
sprintf (buffer, "%u", macro_number);
|
||||
sb_add_string (out, buffer);
|
||||
}
|
||||
else if (src < in->len
|
||||
&& in->ptr[src] == '+'
|
||||
/* PR 32391: Do not perform the substition inside nested
|
||||
macros. Instead wait until they are re-evaluated and
|
||||
perform the substition then. */
|
||||
&& ! nesting)
|
||||
else if (src < in->len && in->ptr[src] == '+')
|
||||
{
|
||||
/* Sub in the current macro invocation number. */
|
||||
|
||||
@@ -1044,18 +904,7 @@ macro_expand_body (sb *in, sb *out, formal_entry *formals,
|
||||
else
|
||||
{
|
||||
sb_reset (&t);
|
||||
|
||||
if (nesting)
|
||||
{
|
||||
src = get_apost_token (src, in, &t, '\'');
|
||||
sb_add_char (out, '\\');
|
||||
sb_add_sb (out, &t);
|
||||
}
|
||||
else
|
||||
{
|
||||
src = sub_actual (src, in, &t, formal_hash,
|
||||
'\'', out, 0, macro);
|
||||
}
|
||||
src = sub_actual (src, in, &t, formal_hash, '\'', out, 0);
|
||||
}
|
||||
}
|
||||
else if ((flag_macro_alternate || flag_mri)
|
||||
@@ -1074,7 +923,7 @@ macro_expand_body (sb *in, sb *out, formal_entry *formals,
|
||||
sb_reset (&t);
|
||||
src = sub_actual (src, in, &t, formal_hash,
|
||||
(macro_strip_at && inquote) ? '@' : '\'',
|
||||
out, 1, macro);
|
||||
out, 1);
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -1186,7 +1035,6 @@ macro_expand_body (sb *in, sb *out, formal_entry *formals,
|
||||
|
||||
if (!err && (out->len == 0 || out->ptr[out->len - 1] != '\n'))
|
||||
sb_add_char (out, '\n');
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
@@ -1371,7 +1219,8 @@ macro_expand (size_t idx, sb *in, macro_entry *m, sb *out)
|
||||
}
|
||||
}
|
||||
|
||||
err = macro_expand_body (&m->sub, out, NULL, NULL, m, m->count);
|
||||
err = macro_expand_body (&m->sub, out, m->formals, m->formal_hash, m,
|
||||
m->count);
|
||||
}
|
||||
|
||||
/* Discard any unnamed formal arguments. */
|
||||
@@ -1404,22 +1253,20 @@ macro_expand (size_t idx, sb *in, macro_entry *m, sb *out)
|
||||
}
|
||||
|
||||
/* Check for a macro. If one is found, put the expansion into
|
||||
*EXPAND. Return TRUE if a macro is found, FALSE otherwise. */
|
||||
*EXPAND. Return 1 if a macro is found, 0 otherwise. */
|
||||
|
||||
bool
|
||||
int
|
||||
check_macro (const char *line, sb *expand,
|
||||
const char **error, macro_entry **info)
|
||||
{
|
||||
const char *s;
|
||||
char *copy, *cls;
|
||||
macro_entry *macro;
|
||||
sb line_sb;
|
||||
|
||||
if (! macros_defined)
|
||||
return false;
|
||||
|
||||
if (! is_name_beginner (*line)
|
||||
&& (! flag_mri || *line != '.'))
|
||||
return false;
|
||||
return 0;
|
||||
|
||||
s = line + 1;
|
||||
while (is_part_of_name (*s))
|
||||
@@ -1431,17 +1278,11 @@ check_macro (const char *line, sb *expand,
|
||||
for (cls = copy; *cls != '\0'; cls ++)
|
||||
*cls = TOLOWER (*cls);
|
||||
|
||||
macro_entry *macro = NULL;
|
||||
for (int i = macro_nesting_depth; i >= 0; i--)
|
||||
{
|
||||
macro = str_hash_find (macro_hash[i], copy);
|
||||
if (macro != NULL)
|
||||
break;
|
||||
}
|
||||
macro = str_hash_find (macro_hash, copy);
|
||||
free (copy);
|
||||
|
||||
if (macro == NULL)
|
||||
return false;
|
||||
return 0;
|
||||
|
||||
/* Wrap the line up in an sb. */
|
||||
sb_new (&line_sb);
|
||||
@@ -1457,7 +1298,7 @@ check_macro (const char *line, sb *expand,
|
||||
if (info)
|
||||
*info = macro;
|
||||
|
||||
return true;
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* Delete a macro. */
|
||||
@@ -1475,20 +1316,11 @@ delete_macro (const char *name)
|
||||
copy[i] = TOLOWER (name[i]);
|
||||
copy[i] = '\0';
|
||||
|
||||
int j;
|
||||
for (j = macro_nesting_depth; j >= 0; j--)
|
||||
{
|
||||
macro = str_hash_find (macro_hash [j], copy);
|
||||
if (macro != NULL)
|
||||
{
|
||||
str_hash_delete (macro_hash[j], copy);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (j < 0)
|
||||
macro = str_hash_find (macro_hash, copy);
|
||||
if (macro != NULL)
|
||||
str_hash_delete (macro_hash, copy);
|
||||
else
|
||||
as_warn (_("Attempt to purge non-existing macro `%s'"), copy);
|
||||
|
||||
free (copy);
|
||||
}
|
||||
|
||||
@@ -1590,25 +1422,3 @@ expand_irp (int irpc, size_t idx, sb *in, sb *out, size_t (*get_line) (sb *))
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
void
|
||||
increment_macro_nesting_depth (void)
|
||||
{
|
||||
if (macro_nesting_depth >= (MAX_MACRO_DEPTH - 1))
|
||||
as_fatal (_("macros nested too deeply"));
|
||||
else
|
||||
++macro_nesting_depth;
|
||||
}
|
||||
|
||||
void
|
||||
decrement_macro_nesting_depth (void)
|
||||
{
|
||||
if (macro_nesting_depth == 0)
|
||||
as_fatal (_("too much macro un-nesting"));
|
||||
else
|
||||
{
|
||||
/* FIXME: Potential memory leak here. */
|
||||
htab_empty (macro_hash [macro_nesting_depth]);
|
||||
--macro_nesting_depth;
|
||||
}
|
||||
}
|
||||
|
||||
17
gas/macro.h
17
gas/macro.h
@@ -64,28 +64,31 @@ typedef struct macro_struct
|
||||
int formal_count; /* Number of formal args. */
|
||||
formal_entry * formals; /* List of formal_structs. */
|
||||
htab_t formal_hash; /* Hash table of formals. */
|
||||
struct macro_struct * parent; /* Parent of nested macros. */
|
||||
const char * name; /* Macro name. */
|
||||
const char * file; /* File the macro was defined in. */
|
||||
unsigned int line; /* Line number of definition. */
|
||||
unsigned int count; /* Invocation count. */
|
||||
} macro_entry;
|
||||
|
||||
/* The macro/text block nesting level. */
|
||||
/* Whether any macros have been defined. */
|
||||
|
||||
extern int macro_defined;
|
||||
|
||||
/* The macro nesting level. */
|
||||
|
||||
extern int macro_nest;
|
||||
|
||||
/* The macro hash table. */
|
||||
|
||||
extern htab_t macro_hash;
|
||||
|
||||
extern int buffer_and_nest (const char *, const char *, sb *,
|
||||
size_t (*) (sb *));
|
||||
extern void macro_init (void);
|
||||
extern void macro_end (void);
|
||||
extern macro_entry *define_macro (sb *, sb *, size_t (*) (sb *));
|
||||
extern bool check_macro (const char *, sb *, const char **, macro_entry **);
|
||||
extern int check_macro (const char *, sb *, const char **, macro_entry **);
|
||||
extern void delete_macro (const char *);
|
||||
extern const char *expand_irp (int, size_t, sb *, sb *, size_t (*) (sb *));
|
||||
extern void increment_macro_nesting_depth (void);
|
||||
extern void decrement_macro_nesting_depth (void);
|
||||
extern void macro_record_invocation (macro_entry *);
|
||||
extern bool add_macro (macro_entry *, bool);
|
||||
|
||||
#endif
|
||||
|
||||
15
gas/read.c
15
gas/read.c
@@ -656,8 +656,7 @@ poend (void)
|
||||
}
|
||||
|
||||
/* Helper function of read_a_source_file, which tries to expand a macro. */
|
||||
|
||||
static bool
|
||||
static int
|
||||
try_macro (char term, const char *line)
|
||||
{
|
||||
sb out;
|
||||
@@ -674,14 +673,12 @@ try_macro (char term, const char *line)
|
||||
sb_kill (&out);
|
||||
buffer_limit =
|
||||
input_scrub_next_buffer (&input_line_pointer);
|
||||
|
||||
macro_record_invocation (macro);
|
||||
#ifdef md_macro_info
|
||||
md_macro_info (macro);
|
||||
#endif
|
||||
return true;
|
||||
return 1;
|
||||
}
|
||||
return false;
|
||||
return 0;
|
||||
}
|
||||
|
||||
#ifdef HANDLE_BUNDLE
|
||||
@@ -1273,7 +1270,7 @@ read_a_source_file (const char *name)
|
||||
s_ignore (0);
|
||||
nul_char = next_char = *--input_line_pointer;
|
||||
*input_line_pointer = '\0';
|
||||
if (! try_macro (next_char, s))
|
||||
if (! macro_defined || ! try_macro (next_char, s))
|
||||
{
|
||||
*end = '\0';
|
||||
as_bad (_("unknown pseudo-op: `%s'"), s);
|
||||
@@ -1310,7 +1307,7 @@ read_a_source_file (const char *name)
|
||||
|
||||
generate_lineno_debug ();
|
||||
|
||||
if (try_macro (next_char, s))
|
||||
if (macro_defined && try_macro (next_char, s))
|
||||
continue;
|
||||
|
||||
if (mri_pending_align)
|
||||
@@ -2820,7 +2817,7 @@ s_macro (int ignore ATTRIBUTE_UNUSED)
|
||||
as_warn_where (macro->file, macro->line,
|
||||
_("attempt to redefine pseudo-op `%s' ignored"),
|
||||
macro->name);
|
||||
delete_macro (macro->name);
|
||||
str_hash_delete (macro_hash, macro->name);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -112,4 +112,6 @@ run_list_test count
|
||||
run_list_test irp-count
|
||||
run_list_test irpc-quote
|
||||
run_list_test rept-count
|
||||
run_dump_test nesting
|
||||
run_dump_test nesting1
|
||||
run_dump_test nesting2
|
||||
run_dump_test nesting3
|
||||
|
||||
@@ -1,28 +0,0 @@
|
||||
#nm: -j
|
||||
#name: Nested macros (PR 32391)
|
||||
# Sone targets do not support macros used like this.
|
||||
#skip: tic*-*-* mmix-*
|
||||
|
||||
#...
|
||||
_m7_
|
||||
_m8_
|
||||
after_at_0
|
||||
after_at_3
|
||||
after_plus_0
|
||||
after_plus_1
|
||||
before_at_0
|
||||
before_at_3
|
||||
before_plus_0
|
||||
before_plus_1
|
||||
bert
|
||||
harryfred
|
||||
i3_bar
|
||||
inside_at_1
|
||||
inside_at_2
|
||||
inside_at_4
|
||||
inside_at_5
|
||||
inside_plus_0
|
||||
inside_plus_1
|
||||
jim
|
||||
o3_foo
|
||||
other_inner_6
|
||||
@@ -1,104 +0,0 @@
|
||||
.text
|
||||
/* PR 32391: Automatic counters inside macros should increment when nested
|
||||
macros finish execution. */
|
||||
.macro o1
|
||||
.global before_at_\@
|
||||
before_at_\@:
|
||||
.global before_plus_\+
|
||||
before_plus_\+:
|
||||
|
||||
.macro i1
|
||||
.global inside_at_\@
|
||||
inside_at_\@:
|
||||
.global inside_plus_\+
|
||||
inside_plus_\+:
|
||||
.endm
|
||||
|
||||
i1
|
||||
i1
|
||||
|
||||
.global after_at_\@
|
||||
after_at_\@:
|
||||
.global after_plus_\+
|
||||
after_plus_\+:
|
||||
|
||||
.endm
|
||||
|
||||
/* Invoking o1 should produce these symbols in this order:
|
||||
|
||||
before_at_0
|
||||
before_plus_0
|
||||
inside_at_1
|
||||
inside_plus_0
|
||||
inside_at_2
|
||||
inside_plus_1
|
||||
after_at_0
|
||||
after_plus_0 */
|
||||
o1
|
||||
|
||||
/* A second invocation of o1 should not produce any errors about
|
||||
symbols or macros being redefined. */
|
||||
o1
|
||||
|
||||
/* This definition should not collide with the definition inside o1. */
|
||||
.macro i1
|
||||
.global other_inner_\@
|
||||
other_inner_\@:
|
||||
.endm
|
||||
|
||||
/* And invoking it should invoke the second defintion of i1, not the first. */
|
||||
i1
|
||||
|
||||
.macro o2
|
||||
.global _m\@_
|
||||
_m\@_:
|
||||
.macro i2
|
||||
.global _m\@_
|
||||
_m\@_:
|
||||
.endm
|
||||
i2
|
||||
.endm
|
||||
|
||||
/* This should not generate conflicting symbols because the assembler
|
||||
inserts the contents of o2 into the input buffer as pure text (ie
|
||||
without evaluating i2). The first use of \@ is evaluated at this
|
||||
time, creating _m4_. But the second use is not evaluated because
|
||||
it is inside a .macro definition.
|
||||
|
||||
This finishes the evaluation of o2, so the \@ counter is incremented.
|
||||
|
||||
Next the input buffer is re-evaluated and the i2 macro definition
|
||||
and invocation are encounterd. The text from i2 are inserted into
|
||||
the input buffer and at this point the second use of \@ is evaluated
|
||||
resulting in the creation of a symbol called _m5_. */
|
||||
o2
|
||||
|
||||
/* Macro arguments should be independent of nesting. */
|
||||
.macro O3 arg
|
||||
.global o3_\arg
|
||||
o3_\arg:
|
||||
|
||||
.macro I3 arg
|
||||
.global i3_\arg
|
||||
i3_\arg:
|
||||
.endm
|
||||
|
||||
i3 bar /* Macro names are case insensitive. */
|
||||
.endm
|
||||
|
||||
o3 foo /* Should produce two labels: o3_foo and i3_bar. */
|
||||
|
||||
/* Nested macros can access the arguments of their parents.
|
||||
In addition their arguments can be substituted into the arguments
|
||||
that are substited from their parents: */
|
||||
.macro OUTER arg1, arg2, arg3:vararg
|
||||
.macro INNER arg4 arg2
|
||||
.dc.a \arg2
|
||||
.dc.a \arg3
|
||||
.endm
|
||||
INNER \arg1 bert
|
||||
.dc.a \arg2
|
||||
.endm
|
||||
|
||||
/* This produces references to "jim", "bert" and "harryfred". */
|
||||
OUTER fred, jim, harry\arg4
|
||||
7
gas/testsuite/gas/macros/nesting1.d
Normal file
7
gas/testsuite/gas/macros/nesting1.d
Normal file
@@ -0,0 +1,7 @@
|
||||
#nm: -j
|
||||
#name: Nested macros (PR 32484)
|
||||
# Sone targets do not support macros used like this.
|
||||
#skip: mmix-*
|
||||
|
||||
#...
|
||||
foo
|
||||
14
gas/testsuite/gas/macros/nesting1.s
Normal file
14
gas/testsuite/gas/macros/nesting1.s
Normal file
@@ -0,0 +1,14 @@
|
||||
.text
|
||||
.macro entry fname
|
||||
\fname:
|
||||
.endm
|
||||
|
||||
.macro func fname, t
|
||||
entry \fname
|
||||
.macro data
|
||||
.dc.\()\t 0
|
||||
.endm
|
||||
data
|
||||
.endm
|
||||
|
||||
func foo, a
|
||||
7
gas/testsuite/gas/macros/nesting2.d
Normal file
7
gas/testsuite/gas/macros/nesting2.d
Normal file
@@ -0,0 +1,7 @@
|
||||
#nm: -j
|
||||
#name: Nested macros (PR 32486)
|
||||
# Sone targets do not support macros used like this.
|
||||
#skip: mmix-*
|
||||
|
||||
#...
|
||||
foo
|
||||
10
gas/testsuite/gas/macros/nesting2.s
Normal file
10
gas/testsuite/gas/macros/nesting2.s
Normal file
@@ -0,0 +1,10 @@
|
||||
.macro function name
|
||||
.macro endfunc
|
||||
.endm
|
||||
.text
|
||||
\name:
|
||||
.endm
|
||||
|
||||
function foo
|
||||
.dc.a 0
|
||||
endfunc
|
||||
7
gas/testsuite/gas/macros/nesting3.d
Normal file
7
gas/testsuite/gas/macros/nesting3.d
Normal file
@@ -0,0 +1,7 @@
|
||||
#nm: -j
|
||||
#name: Nested macros (PR 32487)
|
||||
# Sone targets do not support macros used like this.
|
||||
#skip: mmix-*
|
||||
|
||||
#...
|
||||
foo
|
||||
13
gas/testsuite/gas/macros/nesting3.s
Normal file
13
gas/testsuite/gas/macros/nesting3.s
Normal file
@@ -0,0 +1,13 @@
|
||||
.text
|
||||
.macro func
|
||||
foo
|
||||
.endm
|
||||
|
||||
.macro do_foo
|
||||
.macro foo
|
||||
foo:
|
||||
.dc.a 0
|
||||
.endm
|
||||
.endm
|
||||
do_foo
|
||||
func
|
||||
Reference in New Issue
Block a user