[binutils-gdb] Fix the handling or arguments and macro pseudo-variables inside nested assembler macros.

Nick Clifton nickc@sourceware.org
Thu Dec 19 10:01:35 GMT 2024


https://sourceware.org/git/gitweb.cgi?p=binutils-gdb.git;h=9f2e3c21f6506f081f1360f02b847606e0e00995

commit 9f2e3c21f6506f081f1360f02b847606e0e00995
Author: Nick Clifton <nickc@redhat.com>
Date:   Thu Dec 19 09:59:11 2024 +0000

    Fix the handling or arguments and macro pseudo-variables inside nested assembler macros.
    
    PR 32391

Diff:
---
 gas/config/tc-iq2000.c              |   6 +-
 gas/doc/as.texi                     |  60 +++++++-
 gas/input-scrub.c                   |   7 +-
 gas/macro.c                         | 270 ++++++++++++++++++++++++++++++------
 gas/macro.h                         |  17 +--
 gas/read.c                          |  15 +-
 gas/testsuite/gas/macros/macros.exp |   1 +
 gas/testsuite/gas/macros/nesting.d  |  28 ++++
 gas/testsuite/gas/macros/nesting.s  | 104 ++++++++++++++
 9 files changed, 444 insertions(+), 64 deletions(-)

diff --git a/gas/config/tc-iq2000.c b/gas/config/tc-iq2000.c
index 2198ffda2b9..1cbc578281f 100644
--- a/gas/config/tc-iq2000.c
+++ b/gas/config/tc-iq2000.c
@@ -105,8 +105,6 @@ 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[] =
@@ -279,9 +277,7 @@ iq2000_add_macro (const char *  name,
 	}
     }
 
-  str_hash_insert (macro_hash, macro->name, macro, 1);
-
-  macro_defined = 1;
+  (void) add_macro (macro, true);
 }
 
 static void
diff --git a/gas/doc/as.texi b/gas/doc/as.texi
index 6be54b57599..1683594a0bb 100644
--- a/gas/doc/as.texi
+++ b/gas/doc/as.texi
@@ -6215,7 +6215,12 @@ 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}.  If your macro
+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
 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
@@ -6380,6 +6385,29 @@ 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.
@@ -6395,6 +6423,33 @@ 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 \+
@@ -6681,6 +6736,9 @@ 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}]]]}
diff --git a/gas/input-scrub.c b/gas/input-scrub.c
index 878edc8fd36..25fac879a56 100644
--- a/gas/input-scrub.c
+++ b/gas/input-scrub.c
@@ -23,6 +23,7 @@
 #include "input-file.h"
 #include "sb.h"
 #include "listing.h"
+#include "macro.h"
 
 /*
  * O/S independent module to supply buffers of sanitised source code
@@ -290,12 +291,13 @@ 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 ();
+    }
 
   next_saved_file = input_scrub_push (position);
 
@@ -350,6 +352,7 @@ input_scrub_next_buffer (char **bufp)
 	         data.  */
 	      md_macro_end ();
 #endif
+	      decrement_macro_nesting_depth ();
 	    }
 	  if (from_sb_expansion != expanding_app)
 	    --macro_nest;
diff --git a/gas/macro.c b/gas/macro.c
index 8b376f7f490..a0f2a5c764c 100644
--- a/gas/macro.c
+++ b/gas/macro.c
@@ -44,11 +44,24 @@
 
 /* The macro hash table.  */
 
-htab_t macro_hash;
+/* 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;
 
-/* Whether any macros have been defined.  */
+/* 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
 
-int macro_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;
 
 /* Whether we should strip '@' characters.  */
 
@@ -60,6 +73,18 @@ 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)
 {
@@ -72,15 +97,23 @@ macro_del_f (void *ent)
 void
 macro_init (void)
 {
-  macro_hash = htab_create_alloc (16, hash_string_tuple, eq_string_tuple,
-				  macro_del_f, notes_calloc, NULL);
-  macro_defined = 0;
+  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;
 }
 
 void
 macro_end (void)
 {
-  htab_delete (macro_hash);
+  int i;
+
+  for (i = MAX_MACRO_DEPTH; i--;)
+    htab_delete (macro_hash[i]);
+
+  macros_defined = false;
 }
 
 /* Read input lines till we get to a TO string.
@@ -655,6 +688,13 @@ 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 *
@@ -718,15 +758,19 @@ 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 (str_hash_insert (macro_hash, macro->name, macro, 0) != NULL)
+      if (! add_macro (macro, false))
 	error = _("Macro `%s' was already defined");
     }
 
-  if (!error)
-    macro_defined = 1;
-  else
+  if (error != NULL)
     {
       as_bad_where (macro->file, macro->line, error, macro->name);
       free_macro (macro);
@@ -750,11 +794,25 @@ get_apost_token (size_t idx, sb *in, sb *name, int kind)
   return idx;
 }
 
-/* Substitute the actual value for a formal parameter.  */
+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.  */
 
 static size_t
 sub_actual (size_t start, sb *in, sb *t, struct htab *formal_hash,
-	    int kind, sb *out, int copyifnotthere)
+	    int kind, sb *out, int copyifnotthere, const macro_entry * macro)
 {
   size_t src;
   formal_entry *ptr;
@@ -768,16 +826,12 @@ 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)
     {
-      if (ptr->actual.len)
-	{
-	  sb_add_sb (out, &ptr->actual);
-	}
-      else
-	{
-	  sb_add_sb (out, &ptr->def);
-	}
+      sb * add = ptr->actual.len ? &ptr->actual : &ptr->def;
+
+      sb_add_sb (out, add);
     }
   else if (kind == '&')
     {
@@ -791,6 +845,55 @@ 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 (strchr (add->ptr, '\\'))
+	    {
+	      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);
+	    }
+	  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, '\\');
@@ -799,7 +902,12 @@ sub_actual (size_t start, sb *in, sb *t, struct htab *formal_hash,
   return src;
 }
 
-/* Expand the body of a macro.  */
+/* 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.  */
 
 static const char *
 macro_expand_body (sb *in, sb *out, formal_entry *formals,
@@ -811,18 +919,38 @@ 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);
+		src = sub_actual (src + 2, in, &t, formal_hash,
+				  '\'', out, 1, macro);
 	      else
 		sb_add_char (out, in->ptr[src++]);
 	    }
@@ -830,7 +958,8 @@ 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);
+	      src = sub_actual (src + 1, in, &t, formal_hash,
+				'&', out, 0, macro);
 	    }
 	}
       else if (in->ptr[src] == '\\')
@@ -851,7 +980,12 @@ 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] == '@')
+	  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)
 	    {
 	      /* Sub in the total macro invocation number.  */
 
@@ -860,7 +994,12 @@ 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] == '+')
+	  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)
 	    {
 	      /* Sub in the current macro invocation number.  */
 
@@ -904,7 +1043,18 @@ macro_expand_body (sb *in, sb *out, formal_entry *formals,
 	  else
 	    {
 	      sb_reset (&t);
-	      src = sub_actual (src, in, &t, formal_hash, '\'', out, 0);
+
+	      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);
+		}
 	    }
 	}
       else if ((flag_macro_alternate || flag_mri)
@@ -923,7 +1073,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);
+				out, 1, macro);
 	    }
 	  else
 	    {
@@ -1035,6 +1185,7 @@ 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;
 }
 
@@ -1219,8 +1370,7 @@ macro_expand (size_t idx, sb *in, macro_entry *m, sb *out)
 	    }
 	}
 
-      err = macro_expand_body (&m->sub, out, m->formals, m->formal_hash, m,
-			       m->count);
+      err = macro_expand_body (&m->sub, out, NULL, NULL, m, m->count);
     }
 
   /* Discard any unnamed formal arguments.  */
@@ -1253,9 +1403,9 @@ 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 1 if a macro is found, 0 otherwise.  */
+   *EXPAND.  Return TRUE if a macro is found, FALSE otherwise.  */
 
-int
+bool
 check_macro (const char *line, sb *expand,
 	     const char **error, macro_entry **info)
 {
@@ -1264,9 +1414,12 @@ check_macro (const char *line, sb *expand,
   macro_entry *macro;
   sb line_sb;
 
+  if (! macros_defined)
+    return false;
+
   if (! is_name_beginner (*line)
       && (! flag_mri || *line != '.'))
-    return 0;
+    return false;
 
   s = line + 1;
   while (is_part_of_name (*s))
@@ -1278,11 +1431,17 @@ check_macro (const char *line, sb *expand,
   for (cls = copy; *cls != '\0'; cls ++)
     *cls = TOLOWER (*cls);
 
-  macro = str_hash_find (macro_hash, copy);
+  int i;
+  for (i = macro_nesting_depth; i >= 0; i--)
+    {
+      macro = str_hash_find (macro_hash[i], copy);
+      if (macro != NULL)
+	break;
+    }
   free (copy);
 
   if (macro == NULL)
-    return 0;
+    return false;
 
   /* Wrap the line up in an sb.  */
   sb_new (&line_sb);
@@ -1298,7 +1457,7 @@ check_macro (const char *line, sb *expand,
   if (info)
     *info = macro;
 
-  return 1;
+  return true;
 }
 
 /* Delete a macro.  */
@@ -1316,11 +1475,20 @@ delete_macro (const char *name)
     copy[i] = TOLOWER (name[i]);
   copy[i] = '\0';
 
-  macro = str_hash_find (macro_hash, copy);
-  if (macro != NULL)
-    str_hash_delete (macro_hash, copy);
-  else
+  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 (macro == NULL)
     as_warn (_("Attempt to purge non-existing macro `%s'"), copy);
+
   free (copy);
 }
 
@@ -1422,3 +1590,25 @@ 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;
+    }
+}
diff --git a/gas/macro.h b/gas/macro.h
index e87f64e70ca..97f2a5a4066 100644
--- a/gas/macro.h
+++ b/gas/macro.h
@@ -64,31 +64,28 @@ 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;
 
-/* Whether any macros have been defined.  */
-
-extern int macro_defined;
-
-/* The macro nesting level.  */
+/* The macro/text block 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 int check_macro (const char *, sb *, const char **, macro_entry **);
+extern bool 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
diff --git a/gas/read.c b/gas/read.c
index 589c7b080c2..e5185f4ba26 100644
--- a/gas/read.c
+++ b/gas/read.c
@@ -655,7 +655,8 @@ poend (void)
     }
 
 /* Helper function of read_a_source_file, which tries to expand a macro.  */
-static int
+
+static bool
 try_macro (char term, const char *line)
 {
   sb out;
@@ -672,12 +673,14 @@ 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 1;
+      return true;
     }
-  return 0;
+  return false;
 }
 
 #ifdef HANDLE_BUNDLE
@@ -1269,7 +1272,7 @@ read_a_source_file (const char *name)
 			  s_ignore (0);
 			  nul_char = next_char = *--input_line_pointer;
 			  *input_line_pointer = '\0';
-			  if (! macro_defined || ! try_macro (next_char, s))
+			  if (! try_macro (next_char, s))
 			    {
 			      *end = '\0';
 			      as_bad (_("unknown pseudo-op: `%s'"), s);
@@ -1306,7 +1309,7 @@ read_a_source_file (const char *name)
 
 		      generate_lineno_debug ();
 
-		      if (macro_defined && try_macro (next_char, s))
+		      if (try_macro (next_char, s))
 			continue;
 
 		      if (mri_pending_align)
@@ -2816,7 +2819,7 @@ s_macro (int ignore ATTRIBUTE_UNUSED)
 	  as_warn_where (macro->file, macro->line,
 			 _("attempt to redefine pseudo-op `%s' ignored"),
 			 macro->name);
-	  str_hash_delete (macro_hash, macro->name);
+	  delete_macro (macro->name);
 	}
     }
 
diff --git a/gas/testsuite/gas/macros/macros.exp b/gas/testsuite/gas/macros/macros.exp
index 3ac199feaa5..94ac37cdb8b 100644
--- a/gas/testsuite/gas/macros/macros.exp
+++ b/gas/testsuite/gas/macros/macros.exp
@@ -112,3 +112,4 @@ run_list_test count
 run_list_test irp-count
 run_list_test irpc-quote
 run_list_test rept-count
+run_dump_test nesting
diff --git a/gas/testsuite/gas/macros/nesting.d b/gas/testsuite/gas/macros/nesting.d
new file mode 100644
index 00000000000..2f44aedb2dc
--- /dev/null
+++ b/gas/testsuite/gas/macros/nesting.d
@@ -0,0 +1,28 @@
+#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
diff --git a/gas/testsuite/gas/macros/nesting.s b/gas/testsuite/gas/macros/nesting.s
new file mode 100644
index 00000000000..438d5af8d00
--- /dev/null
+++ b/gas/testsuite/gas/macros/nesting.s
@@ -0,0 +1,104 @@
+
+	.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
+
+OUTER fred, jim, harry\arg4 /* This produces references to "jim", "bert" and "harryfred".  */


More information about the Binutils-cvs mailing list