diff --git a/gas/config/tc-iq2000.c b/gas/config/tc-iq2000.c
index f5d7c90d0d7..4e169727b84 100644
--- a/gas/config/tc-iq2000.c
+++ b/gas/config/tc-iq2000.c
@@ -229,15 +229,14 @@ iq2000_add_macro (const char *  name,
 		  const char ** arguments)
 {
   macro_entry *macro;
-  sb macro_name;
-  const char *namestr;
 
   macro = XNEW (macro_entry);
+  macro->name = xstrdup (name);
   sb_new (& macro->sub);
-  sb_new (& macro_name);
-
   macro->formal_count = 0;
   macro->formals = 0;
+  macro->formal_hash = str_htab_create ();
+  macro->file = as_where (&macro->line);
 
   sb_add_string (& macro->sub, semantics);
 
@@ -245,9 +244,6 @@ iq2000_add_macro (const char *  name,
     {
       formal_entry ** p = &macro->formals;
 
-      macro->formal_count = 0;
-      macro->formal_hash = str_htab_create ();
-
       while (*arguments != NULL)
 	{
 	  formal_entry *formal;
@@ -261,7 +257,7 @@ iq2000_add_macro (const char *  name,
 	  /* chlm: Added the following to allow defaulted args.  */
 	  if (strchr (*arguments,'='))
 	    {
-	      char * tt_args = strdup (*arguments);
+	      char * tt_args = xstrdup (*arguments);
 	      char * tt_dflt = strchr (tt_args,'=');
 
 	      *tt_dflt = 0;
@@ -283,9 +279,7 @@ iq2000_add_macro (const char *  name,
 	}
     }
 
-  sb_add_string (&macro_name, name);
-  namestr = sb_terminate (&macro_name);
-  str_hash_insert (macro_hash, namestr, macro, 1);
+  str_hash_insert (macro_hash, macro->name, macro, 1);
 
   macro_defined = 1;
 }
diff --git a/gas/macro.c b/gas/macro.c
index ed1e9ef605a..763bafbdc3d 100644
--- a/gas/macro.c
+++ b/gas/macro.c
@@ -70,13 +70,23 @@ static size_t (*macro_expr) (const char *, size_t, sb *, offsetT *);
 
 static int macro_number;
 
+static void free_macro (macro_entry *);
+
+static void
+macro_del_f (void *ent)
+{
+  string_tuple_t *tuple = ent;
+  free_macro ((macro_entry *) tuple->value);
+}
+
 /* Initialize macro processing.  */
 
 void
 macro_init (int alternate, int mri, int strip_at,
 	    size_t (*exp) (const char *, size_t, sb *, offsetT *))
 {
-  macro_hash = str_htab_create ();
+  macro_hash = htab_create_alloc (16, hash_string_tuple, eq_string_tuple,
+				  macro_del_f, notes_calloc, NULL);
   macro_defined = 0;
   macro_alternate = alternate;
   macro_mri = mri;
@@ -664,34 +674,30 @@ free_macro (macro_entry *macro)
     }
   htab_delete (macro->formal_hash);
   sb_kill (&macro->sub);
+  free ((char *) macro->name);
   free (macro);
 }
 
-/* Define a new macro.  Returns NULL on success, otherwise returns an
-   error message.  If NAMEP is not NULL, *NAMEP is set to the name of
-   the macro which was defined.  */
+/* Define a new macro.  */
 
-const char *
-define_macro (size_t idx, sb *in, sb *label,
-	      size_t (*get_line) (sb *),
-	      const char *file, unsigned int line,
-	      const char **namep)
+macro_entry *
+define_macro (sb *in, sb *label, size_t (*get_line) (sb *))
 {
   macro_entry *macro;
   sb name;
+  size_t idx;
   const char *error = NULL;
 
   macro = XNEW (macro_entry);
   sb_new (&macro->sub);
   sb_new (&name);
-  macro->file = file;
-  macro->line = line;
+  macro->file = as_where (&macro->line);
 
   macro->formal_count = 0;
   macro->formals = 0;
   macro->formal_hash = str_htab_create ();
 
-  idx = sb_skip_white (idx, in);
+  idx = sb_skip_white (0, in);
   if (! buffer_and_nest ("MACRO", "ENDM", &macro->sub, get_line))
     error = _("unexpected end of file in macro `%s' definition");
   if (label != NULL && label->len != 0)
@@ -740,15 +746,16 @@ define_macro (size_t idx, sb *in, sb *label,
 	error = _("Macro `%s' was already defined");
     }
 
-  if (namep != NULL)
-    *namep = macro->name;
-
   if (!error)
     macro_defined = 1;
   else
-    free_macro (macro);
+    {
+      as_bad_where (macro->file, macro->line, error, macro->name);
+      free_macro (macro);
+      macro = NULL;
+    }
 
-  return error;
+  return macro;
 }
 
 /* Scan a token, and then skip KIND.  */
@@ -1318,10 +1325,7 @@ delete_macro (const char *name)
 
   macro = str_hash_find (macro_hash, copy);
   if (macro != NULL)
-    {
-      free_macro (macro);
-      str_hash_delete (macro_hash, copy);
-    }
+    str_hash_delete (macro_hash, copy);
   else
     as_warn (_("Attempt to purge non-existing macro `%s'"), copy);
   free (copy);
diff --git a/gas/macro.h b/gas/macro.h
index 5593281c552..2ec0ec451d5 100644
--- a/gas/macro.h
+++ b/gas/macro.h
@@ -88,8 +88,7 @@ extern void macro_init (int, int, int,
 extern void macro_end (void);
 extern void macro_set_alternate (int);
 extern void macro_mri_mode (int);
-extern const char *define_macro (size_t, sb *, sb *, size_t (*) (sb *),
-				 const char *, unsigned int, const char **);
+extern macro_entry *define_macro (sb *, sb *, size_t (*) (sb *));
 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 *));
diff --git a/gas/read.c b/gas/read.c
index 8fb11e8a67c..c5a477f9e08 100644
--- a/gas/read.c
+++ b/gas/read.c
@@ -2647,13 +2647,8 @@ void
 s_macro (int ignore ATTRIBUTE_UNUSED)
 {
   char *eol;
-  const char * file;
-  unsigned int line;
   sb s;
-  const char *err;
-  const char *name;
-
-  file = as_where (&line);
+  macro_entry *macro;
 
   eol = find_end_of_line (input_line_pointer, 0);
   sb_build (&s, eol - input_line_pointer);
@@ -2664,19 +2659,18 @@ s_macro (int ignore ATTRIBUTE_UNUSED)
     {
       sb label;
       size_t len;
+      const char *name;
 
       name = S_GET_NAME (line_label);
       len = strlen (name);
       sb_build (&label, len);
       sb_add_buffer (&label, name, len);
-      err = define_macro (0, &s, &label, get_macro_line_sb, file, line, &name);
+      macro = define_macro (&s, &label, get_macro_line_sb);
       sb_kill (&label);
     }
   else
-    err = define_macro (0, &s, NULL, get_macro_line_sb, file, line, &name);
-  if (err != NULL)
-    as_bad_where (file, line, err, name);
-  else
+    macro = define_macro (&s, NULL, get_macro_line_sb);
+  if (macro != NULL)
     {
       if (line_label != NULL)
 	{
@@ -2686,14 +2680,16 @@ s_macro (int ignore ATTRIBUTE_UNUSED)
 	}
 
       if (((NO_PSEUDO_DOT || flag_m68k_mri)
-	   && str_hash_find (po_hash, name) != NULL)
+	   && str_hash_find (po_hash, macro->name) != NULL)
 	  || (!flag_m68k_mri
-	      && *name == '.'
-	      && str_hash_find (po_hash, name + 1) != NULL))
-	as_warn_where (file,
-		 line,
-		 _("attempt to redefine pseudo-op `%s' ignored"),
-		 name);
+	      && macro->name[0] == '.'
+	      && str_hash_find (po_hash, macro->name + 1) != NULL))
+	{
+	  as_warn_where (macro->file, macro->line,
+			 _("attempt to redefine pseudo-op `%s' ignored"),
+			 macro->name);
+	  str_hash_delete (macro_hash, macro->name);
+	}
     }
 
   sb_kill (&s);
