gas: tc-tic54x.c hash tables
authorAlan Modra <amodra@gmail.com>
Fri, 8 Jul 2022 08:07:07 +0000 (17:37 +0930)
committerAlan Modra <amodra@gmail.com>
Sat, 9 Jul 2022 12:18:02 +0000 (21:48 +0930)
Cleaning up the subsym_hash memory is a real pain.  Keys and values
entered into the table are quite diverse.  In some cases the key is
allocated and thus needs to be freed, in others the key is a const
string.  Values are similar, and in some cases not even a string.
Tidy this by inserting a new subsym_ent_t that describes key/value
type.  This meant the math_hash table was no longer needed.  The patch
also tidies how math functions are called, those that are supposed to
return int now no longer return their value in a float.

* config/tc-tic54x.c (math_hash): Delete.
(subsym_proc_entry): Move earlier, make proc a union, merge with..
(math_proc_entry): ..this.  Delete type.
(math_procs): Merge into subsym_procs.
(subsym_ent_t): New.  Use this type in subsym_hash..
(stag_add_field_symbols, tic54x_var, tic54x_macro_info): ..here..
(md_begin, subsym_create_or_replace, subsym_lookup): ..and here..
(subsym_substitute): ..and here.  Adjust subsym_proc_entry
function calls.  Free replacement when not returned.
(subsym_get_arg): Adjust subsym_lookup.
(free_subsym_ent, subsym_htab_create ): New functions, use when
creating subsym_hash.
(free_local_label_ent, local_label_htab_create): Similarly.
(tic54x_remove_local_label): Delete.
(tic54x_clear_local_labels): Simplify.
(tic54x_asg): Use notes obstack to dup strings.
(tic54x_eval): Likewise.
(subsym_ismember): Likewise.
(math_cvi, math_int, math_sgn): Return int.
(tic54x_macro_start): Decrement macro_level before calling as_fatal.
(tic54x_md_end): New function.
* config/tc-tic54h.c (tic54x_md_end): Declare.
(md_end): Define.

gas/config/tc-tic54x.c
gas/config/tc-tic54x.h

index ebefcf1c83c2f6324beb70526c3cfb39e3a35f12..9bc4fa57033c01f00bcda9b454b22cca305fb9d6 100644 (file)
@@ -182,12 +182,35 @@ static symbolS *last_label_seen = NULL;
 static int local_label_id;
 
 static htab_t subsym_recurse_hash; /* Prevent infinite recurse.  */
-static htab_t math_hash; /* Built-in math functions.  */
 /* Allow maximum levels of macro nesting; level 0 is the main substitution
    symbol table.  The other assembler only does 32 levels, so there!  */
 #define MAX_SUBSYM_HASH 100
 static htab_t subsym_hash[MAX_SUBSYM_HASH];
 
+typedef struct
+{
+  const char *name;
+  union {
+    int (*s) (char *, char *);
+    float (*f) (float, float);
+    int (*i) (float, float);
+  } proc;
+  int nargs;
+  int type;
+} subsym_proc_entry;
+
+typedef struct {
+  union {
+    char *s;
+    const subsym_proc_entry *p;
+  } u;
+  unsigned int freekey : 1;
+  unsigned int freeval : 1;
+  unsigned int isproc : 1;
+  unsigned int ismath : 1;
+} subsym_ent_t;
+
+
 /* Keep track of local labels so we can substitute them before GAS sees them
    since macros use their own 'namespace' for local labels, use a separate hash
 
@@ -197,7 +220,7 @@ static htab_t subsym_hash[MAX_SUBSYM_HASH];
    We use our own macro nesting counter, since GAS overloads it when expanding
    other things (like conditionals and repeat loops).  */
 static int macro_level = 0;
-static htab_t local_label_hash[100];
+static htab_t local_label_hash[MAX_SUBSYM_HASH];
 /* Keep track of struct/union tags.  */
 static htab_t stag_hash;
 static htab_t op_hash;
@@ -223,7 +246,7 @@ static htab_t misc_symbol_hash;
 
 
 static void subsym_create_or_replace (char *, char *);
-static char *subsym_lookup (char *, int);
+static subsym_ent_t *subsym_lookup (char *, int);
 static char *subsym_substitute (char *, int);
 
 
@@ -334,6 +357,7 @@ tic54x_asg (int x ATTRIBUTE_UNUSED)
     }
   else
     {
+      size_t len;
       str = input_line_pointer;
       while ((c = *input_line_pointer) != ',')
        {
@@ -341,28 +365,30 @@ tic54x_asg (int x ATTRIBUTE_UNUSED)
            break;
          ++input_line_pointer;
        }
-      *input_line_pointer = 0;
+      len = input_line_pointer - str;
+      str = notes_memdup (str, len, len + 1);
     }
   if (c != ',')
     {
       as_bad (_("Comma and symbol expected for '.asg STRING, SYMBOL'"));
+      notes_free (str);
       ignore_rest_of_line ();
       return;
     }
 
   ++input_line_pointer;
   c = get_symbol_name (&name); /* Get terminator.  */
+  name = notes_strdup (name);
+  (void) restore_line_pointer (c);
   if (!ISALPHA (*name))
     {
       as_bad (_("symbols assigned with .asg must begin with a letter"));
+      notes_free (str);
       ignore_rest_of_line ();
       return;
     }
 
-  str = xstrdup (str);
-  name = xstrdup (name);
   subsym_create_or_replace (name, str);
-  (void) restore_line_pointer (c);
   demand_empty_rest_of_line ();
 }
 
@@ -407,15 +433,17 @@ tic54x_eval (int x ATTRIBUTE_UNUSED)
       return;
     }
   c = get_symbol_name (&name); /* Get terminator.  */
-  name = xstrdup (name);
-  (void) restore_line_pointer (c);
 
   if (!ISALPHA (*name))
     {
       as_bad (_("symbols assigned with .eval must begin with a letter"));
+      (void) restore_line_pointer (c);
       ignore_rest_of_line ();
       return;
     }
+  name = notes_strdup (name);
+  (void) restore_line_pointer (c);
+
   symbolP = symbol_new (name, absolute_section, &zero_address_frag, value);
   SF_SET_LOCAL (symbolP);
   symbol_table_insert (symbolP);
@@ -424,7 +452,7 @@ tic54x_eval (int x ATTRIBUTE_UNUSED)
      But since there's not written rule as to when, don't even bother trying
      to match their behavior.  */
   sprintf (valuestr, "%d", value);
-  tmp = xstrdup (valuestr);
+  tmp = notes_strdup (valuestr);
   subsym_create_or_replace (name, tmp);
 
   demand_empty_rest_of_line ();
@@ -564,11 +592,14 @@ stag_add_field_symbols (struct stag *stag,
        }
       else
        {
-         char *replacement;
-
-         replacement = concat (S_GET_NAME (rootsym), "+", root_stag_name,
-                               name + strlen (S_GET_NAME (rootsym)), NULL);
-         str_hash_insert (subsym_hash[0], name, replacement, 0);
+         subsym_ent_t *ent = xmalloc (sizeof (*ent));
+         ent->u.s = concat (S_GET_NAME (rootsym), "+", root_stag_name,
+                            name + strlen (S_GET_NAME (rootsym)), NULL);
+         ent->freekey = 1;
+         ent->freeval = 1;
+         ent->isproc = 0;
+         ent->ismath = 0;
+         str_hash_insert (subsym_hash[0], name, ent, 0);
          freename = NULL;
        }
 
@@ -1115,16 +1146,40 @@ tic54x_global (int type)
   demand_empty_rest_of_line ();
 }
 
-/* Remove the symbol from the local label hash lookup.  */
+static void
+free_subsym_ent (void *ent)
+{
+  string_tuple_t *tuple = (string_tuple_t *) ent;
+  subsym_ent_t *val = (void *) tuple->value;
+  if (val->freekey)
+    free ((void *) tuple->key);
+  if (val->freeval)
+    free (val->u.s);
+  free (val);
+  free (ent);
+}
 
-static int
-tic54x_remove_local_label (void **slot, void *arg ATTRIBUTE_UNUSED)
+static htab_t
+subsym_htab_create (void)
 {
-  string_tuple_t *tuple = *((string_tuple_t **) slot);
-  void *elem = str_hash_find (local_label_hash[macro_level], tuple->key);
-  str_hash_delete (local_label_hash[macro_level], tuple->key);
-  free (elem);
-  return 0;
+  return htab_create_alloc (16, hash_string_tuple, eq_string_tuple,
+                           free_subsym_ent, xcalloc, free);
+}
+
+static void
+free_local_label_ent (void *ent)
+{
+  string_tuple_t *tuple = (string_tuple_t *) ent;
+  free ((void *) tuple->key);
+  free ((void *) tuple->value);
+  free (ent);
+}
+
+static htab_t
+local_label_htab_create (void)
+{
+  return htab_create_alloc (16, hash_string_tuple, eq_string_tuple,
+                           free_local_label_ent, xcalloc, free);
 }
 
 /* Reset all local labels.  */
@@ -1132,7 +1187,7 @@ tic54x_remove_local_label (void **slot, void *arg ATTRIBUTE_UNUSED)
 static void
 tic54x_clear_local_labels (int ignored ATTRIBUTE_UNUSED)
 {
-  htab_traverse (local_label_hash[macro_level], tic54x_remove_local_label, NULL);
+  htab_empty (local_label_hash[macro_level]);
 }
 
 /* .text
@@ -2215,7 +2270,6 @@ tic54x_sslist (int show)
 static void
 tic54x_var (int ignore ATTRIBUTE_UNUSED)
 {
-  static char empty[] = "";
   char *name;
   int c;
 
@@ -2236,10 +2290,17 @@ tic54x_var (int ignore ATTRIBUTE_UNUSED)
          return;
        }
       c = get_symbol_name (&name);
-      /* .var symbols start out with a null string.  */
       name = xstrdup (name);
-      str_hash_insert (subsym_hash[macro_level], name, empty, 0);
       c = restore_line_pointer (c);
+
+      /* .var symbols start out with a null string.  */
+      subsym_ent_t *ent = xmalloc (sizeof (*ent));
+      ent->u.s = (char *) "";
+      ent->freekey = 1;
+      ent->freeval = 0;
+      ent->isproc = 0;
+      ent->ismath = 0;
+      str_hash_insert (subsym_hash[macro_level], name, ent, 0);
       if (c == ',')
        {
          ++input_line_pointer;
@@ -2503,11 +2564,12 @@ tic54x_macro_start (void)
 {
   if (++macro_level >= MAX_SUBSYM_HASH)
     {
+      --macro_level;
       as_fatal (_("Macro nesting is too deep"));
       return;
     }
-  subsym_hash[macro_level] = str_htab_create ();
-  local_label_hash[macro_level] = str_htab_create ();
+  subsym_hash[macro_level] = subsym_htab_create ();
+  local_label_hash[macro_level] = local_label_htab_create ();
 }
 
 void
@@ -2519,11 +2581,14 @@ tic54x_macro_info (const macro_entry *macro)
   for (entry = macro->formals; entry; entry = entry->next)
     {
       char *name = xstrndup (entry->name.ptr, entry->name.len);
-      char *value = xstrndup (entry->actual.ptr, entry->actual.len);
+      subsym_ent_t *ent = xmalloc (sizeof (*ent));
 
-      name[entry->name.len] = '\0';
-      value[entry->actual.len] = '\0';
-      str_hash_insert (subsym_hash[macro_level], name, value, 0);
+      ent->u.s = xstrndup (entry->actual.ptr, entry->actual.len);
+      ent->freekey = 1;
+      ent->freeval = 1;
+      ent->isproc = 0;
+      ent->ismath = 0;
+      str_hash_insert (subsym_hash[macro_level], name, ent, 0);
     }
 }
 
@@ -2594,20 +2659,21 @@ subsym_isdefed (char *a, char *ignore ATTRIBUTE_UNUSED)
 static int
 subsym_ismember (char *sym, char *list)
 {
-  char *elem, *ptr, *listv;
+  char *elem, *ptr;
+  subsym_ent_t *listv;
 
   if (!list)
     return 0;
 
   listv = subsym_lookup (list, macro_level);
-  if (!listv)
+  if (!listv || listv->isproc)
     {
       as_bad (_("Undefined substitution symbol '%s'"), list);
       ignore_rest_of_line ();
       return 0;
     }
 
-  ptr = elem = xstrdup (listv);
+  ptr = elem = notes_strdup (listv->u.s);
   while (*ptr && *ptr != ',')
     ++ptr;
   *ptr++ = 0;
@@ -2728,7 +2794,7 @@ math_ceil (float arg1, float ignore ATTRIBUTE_UNUSED)
   return (float) ceil (arg1);
 }
 
-static float
+static int
 math_cvi (float arg1, float ignore ATTRIBUTE_UNUSED)
 {
   return (int) arg1;
@@ -2746,10 +2812,10 @@ math_fmod (float arg1, float arg2)
   return (int) arg1 % (int) arg2;
 }
 
-static float
+static int
 math_int (float arg1, float ignore ATTRIBUTE_UNUSED)
 {
-  return ((float) ((int) arg1)) == arg1;
+  return arg1 == (float) (int) arg1;
 }
 
 static float
@@ -2758,10 +2824,10 @@ math_round (float arg1, float ignore ATTRIBUTE_UNUSED)
   return arg1 > 0 ? (int) (arg1 + 0.5) : (int) (arg1 - 0.5);
 }
 
-static float
+static int
 math_sgn (float arg1, float ignore ATTRIBUTE_UNUSED)
 {
-  return (arg1 < 0) ? -1 : (arg1 ? 1 : 0);
+  return arg1 < 0.0f ? -1 : arg1 != 0.0f ? 1 : 0;
 }
 
 static float
@@ -2893,72 +2959,53 @@ math_tanh (float arg1, float ignore ATTRIBUTE_UNUSED)
 }
 
 /* Built-in substitution symbol functions and math functions.  */
-typedef struct
-{
-  const char *name;
-  int (*proc) (char *, char *);
-  int nargs;
-} subsym_proc_entry;
-
 static const subsym_proc_entry subsym_procs[] =
 {
   /* Assembler built-in string substitution functions.  */
-  { "$symlen", subsym_symlen, 1,  },
-  { "$symcmp", subsym_symcmp, 2,  },
-  { "$firstch", subsym_firstch, 2,  },
-  { "$lastch", subsym_lastch, 2,  },
-  { "$isdefed", subsym_isdefed, 1,  },
-  { "$ismember", subsym_ismember, 2,  },
-  { "$iscons", subsym_iscons, 1,  },
-  { "$isname", subsym_isname, 1,  },
-  { "$isreg", subsym_isreg, 1,  },
-  { "$structsz", subsym_structsz, 1,  },
-  { "$structacc", subsym_structacc, 1,  },
-  { NULL, NULL, 0 },
-};
-
-typedef struct
-{
-  const char *name;
-  float (*proc) (float, float);
-  int nargs;
-  int int_return;
-} math_proc_entry;
+  { "$symlen",    { .s = subsym_symlen },    1, 0 },
+  { "$symcmp",    { .s = subsym_symcmp },    2, 0 },
+  { "$firstch",   { .s = subsym_firstch },   2, 0 },
+  { "$lastch",    { .s = subsym_lastch },    2, 0 },
+  { "$isdefed",   { .s = subsym_isdefed },   1, 0 },
+  { "$ismember",  { .s = subsym_ismember },  2, 0 },
+  { "$iscons",    { .s = subsym_iscons },    1, 0 },
+  { "$isname",    { .s = subsym_isname },    1, 0 },
+  { "$isreg",     { .s = subsym_isreg },     1, 0 },
+  { "$structsz",  { .s = subsym_structsz },  1, 0 },
+  { "$structacc", { .s = subsym_structacc }, 1, 0 },
 
-static const math_proc_entry math_procs[] =
-{
   /* Integer-returning built-in math functions.  */
-  { "$cvi", math_cvi, 1, 1 },
-  { "$int", math_int, 1, 1 },
-  { "$sgn", math_sgn, 1, 1 },
+  { "$cvi",       { .i = math_cvi },         1, 2 },
+  { "$int",       { .i = math_int },         1, 2 },
+  { "$sgn",       { .i = math_sgn },         1, 2 },
 
   /* Float-returning built-in math functions.  */
-  { "$acos", math_acos, 1, 0 },
-  { "$asin", math_asin, 1, 0 },
-  { "$atan", math_atan, 1, 0 },
-  { "$atan2", math_atan2, 2, 0 },
-  { "$ceil", math_ceil, 1, 0 },
-  { "$cosh", math_cosh, 1, 0 },
-  { "$cos", math_cos, 1, 0 },
-  { "$cvf", math_cvf, 1, 0 },
-  { "$exp", math_exp, 1, 0 },
-  { "$fabs", math_fabs, 1, 0 },
-  { "$floor", math_floor, 1, 0 },
-  { "$fmod", math_fmod, 2, 0 },
-  { "$ldexp", math_ldexp, 2, 0 },
-  { "$log10", math_log10, 1, 0 },
-  { "$log", math_log, 1, 0 },
-  { "$max", math_max, 2, 0 },
-  { "$min", math_min, 2, 0 },
-  { "$pow", math_pow, 2, 0 },
-  { "$round", math_round, 1, 0 },
-  { "$sin", math_sin, 1, 0 },
-  { "$sinh", math_sinh, 1, 0 },
-  { "$sqrt", math_sqrt, 1, 0 },
-  { "$tan", math_tan, 1, 0 },
-  { "$tanh", math_tanh, 1, 0 },
-  { "$trunc", math_trunc, 1, 0 },
-  { NULL, NULL, 0, 0 },
+  { "$acos",      { .f = math_acos },        1, 1 },
+  { "$asin",      { .f = math_asin },        1, 1 },
+  { "$atan",      { .f = math_atan },        1, 1 },
+  { "$atan2",     { .f = math_atan2 },       2, 1 },
+  { "$ceil",      { .f = math_ceil },        1, 1 },
+  { "$cosh",      { .f = math_cosh },        1, 1 },
+  { "$cos",       { .f = math_cos },         1, 1 },
+  { "$cvf",       { .f = math_cvf },         1, 1 },
+  { "$exp",       { .f = math_exp },         1, 1 },
+  { "$fabs",      { .f = math_fabs },        1, 1 },
+  { "$floor",     { .f = math_floor },       1, 1 },
+  { "$fmod",      { .f = math_fmod },        2, 1 },
+  { "$ldexp",     { .f = math_ldexp },       2, 1 },
+  { "$log10",     { .f = math_log10 },       1, 1 },
+  { "$log",       { .f = math_log },         1, 1 },
+  { "$max",       { .f = math_max },         2, 1 },
+  { "$min",       { .f = math_min },         2, 1 },
+  { "$pow",       { .f = math_pow },         2, 1 },
+  { "$round",     { .f = math_round },       1, 1 },
+  { "$sin",       { .f = math_sin },         1, 1 },
+  { "$sinh",      { .f = math_sinh },        1, 1 },
+  { "$sqrt",      { .f = math_sqrt },        1, 1 },
+  { "$tan",       { .f = math_tan },         1, 1 },
+  { "$tanh",      { .f = math_tanh },        1, 1 },
+  { "$trunc",     { .f = math_trunc },       1, 1 },
+  { NULL, { NULL }, 0, 0 },
 };
 
 void
@@ -2967,7 +3014,6 @@ md_begin (void)
   insn_template *tm;
   const tic54x_symbol *sym;
   const subsym_proc_entry *subsym_proc;
-  const math_proc_entry *math_proc;
   const char **symname;
   char *TIC54X_DIR = getenv ("TIC54X_DIR");
   char *A_DIR = TIC54X_DIR ? TIC54X_DIR : getenv ("A_DIR");
@@ -3037,23 +3083,41 @@ md_begin (void)
 
   /* Only the base substitution table and local label table are initialized;
      the others (for local macro substitution) get instantiated as needed.  */
-  local_label_hash[0] = str_htab_create ();
-  subsym_hash[0] = str_htab_create ();
+  local_label_hash[0] = local_label_htab_create ();
+  subsym_hash[0] = subsym_htab_create ();
   for (subsym_proc = subsym_procs; subsym_proc->name; subsym_proc++)
-    str_hash_insert (subsym_hash[0], subsym_proc->name, subsym_proc, 0);
-
-  math_hash = str_htab_create ();
-  for (math_proc = math_procs; math_proc->name; math_proc++)
     {
-      /* Insert into the main subsym hash for recognition; insert into
-        the math hash to actually store information.  */
-      str_hash_insert (subsym_hash[0], math_proc->name, math_proc, 0);
-      str_hash_insert (math_hash, math_proc->name, math_proc, 0);
+      subsym_ent_t *ent = xmalloc (sizeof (*ent));
+      ent->u.p = subsym_proc;
+      ent->freekey = 0;
+      ent->freeval = 0;
+      ent->isproc = 1;
+      ent->ismath = subsym_proc->type != 0;
+      str_hash_insert (subsym_hash[0], subsym_proc->name, ent, 0);
     }
   subsym_recurse_hash = str_htab_create ();
   stag_hash = str_htab_create ();
 }
 
+void
+tic54x_md_end (void)
+{
+  htab_delete (stag_hash);
+  htab_delete (subsym_recurse_hash);
+  while (macro_level != -1)
+    tic54x_macro_end ();
+  macro_level = 0;
+  htab_delete (misc_symbol_hash);
+  htab_delete (sbit_hash);
+  htab_delete (cc3_hash);
+  htab_delete (cc2_hash);
+  htab_delete (cc_hash);
+  htab_delete (mmreg_hash);
+  htab_delete (reg_hash);
+  htab_delete (parop_hash);
+  htab_delete (op_hash);
+}
+
 static int
 is_accumulator (struct opstruct *operand)
 {
@@ -4295,7 +4359,6 @@ subsym_get_arg (char *line, const char *terminators, char **str, int nosub)
   else
     {
       const char *term = terminators;
-      char *value = NULL;
 
       while (*ptr && *ptr != *term)
        {
@@ -4310,8 +4373,12 @@ subsym_get_arg (char *line, const char *terminators, char **str, int nosub)
       endp = ptr;
       *str = xmemdup0 (line, ptr - line);
       /* Do simple substitution, if available.  */
-      if (!nosub && (value = subsym_lookup (*str, macro_level)) != NULL)
-       *str = value;
+      if (!nosub)
+       {
+         subsym_ent_t *ent = subsym_lookup (*str, macro_level);
+         if (ent && !ent->isproc)
+           *str = ent->u.s;
+       }
     }
 
   return endp;
@@ -4326,24 +4393,30 @@ static void
 subsym_create_or_replace (char *name, char *value)
 {
   int i;
+  subsym_ent_t *ent = xmalloc (sizeof (*ent));
+  ent->u.s = value;
+  ent->freekey = 0;
+  ent->freeval = 0;
+  ent->isproc = 0;
+  ent->ismath = 0;
 
   for (i = macro_level; i > 0; i--)
     if (str_hash_find (subsym_hash[i], name))
       {
-       str_hash_insert (subsym_hash[i], name, value, 1);
+       str_hash_insert (subsym_hash[i], name, ent, 1);
        return;
       }
-  str_hash_insert (subsym_hash[0], name, value, 1);
+  str_hash_insert (subsym_hash[0], name, ent, 1);
 }
 
 /* Look up the substitution string replacement for the given symbol.
    Start with the innermost macro substitution table given and work
    outwards.  */
 
-static char *
+static subsym_ent_t *
 subsym_lookup (char *name, int nest_level)
 {
-  char *value = str_hash_find (subsym_hash[nest_level], name);
+  void *value = str_hash_find (subsym_hash[nest_level], name);
 
   if (value || nest_level == 0)
     return value;
@@ -4374,11 +4447,7 @@ subsym_substitute (char *line, int forced)
   int recurse = 1;
   int line_conditional = 0;
   char *tmp;
-
-  /* Work with a copy of the input line.  */
-  replacement = xstrdup (line);
-
-  ptr = head = replacement;
+  unsigned char current_char;
 
   /* Flag lines where we might need to replace a single '=' with two;
      GAS uses single '=' to assign macro args values, and possibly other
@@ -4398,7 +4467,10 @@ subsym_substitute (char *line, int forced)
   if (strstr (line, ".macro"))
     return line;
 
-  unsigned char current_char;
+  /* Work with a copy of the input line.  */
+  replacement = xstrdup (line);
+  ptr = head = replacement;
+
   while (!is_end_of_line[(current_char = * (unsigned char *) ptr)])
     {
       /* Need to update this since LINE may have been modified.  */
@@ -4445,6 +4517,7 @@ subsym_substitute (char *line, int forced)
          char *name; /* Symbol to be replaced.  */
          char *savedp = input_line_pointer;
          int c;
+         subsym_ent_t *ent = NULL;
          char *value = NULL;
          char *tail; /* Rest of line after symbol.  */
 
@@ -4465,7 +4538,11 @@ subsym_substitute (char *line, int forced)
          /* Avoid infinite recursion; if a symbol shows up a second time for
             substitution, leave it as is.  */
          if (str_hash_find (subsym_recurse_hash, name) == NULL)
-           value = subsym_lookup (name, macro_level);
+           {
+             ent = subsym_lookup (name, macro_level);
+             if (ent && !ent->isproc)
+               value = ent->u.s;
+           }
          else
            as_warn (_("%s symbol recursion stopped at "
                       "second appearance of '%s'"),
@@ -4499,14 +4576,13 @@ subsym_substitute (char *line, int forced)
              ptr = tail;
            }
          /* Check for built-in subsym and math functions.  */
-         else if (value != NULL && *name == '$')
+         else if (ent != NULL && *name == '$')
            {
-             subsym_proc_entry *entry = (subsym_proc_entry *) value;
-             math_proc_entry *math_entry = str_hash_find (math_hash, name);
+             const subsym_proc_entry *entry = ent->u.p;
              char *arg1, *arg2 = NULL;
 
              *ptr = c;
-             if (entry == NULL)
+             if (!ent->isproc)
                {
                  as_bad (_("Unrecognized substitution symbol function"));
                  break;
@@ -4517,13 +4593,12 @@ subsym_substitute (char *line, int forced)
                  break;
                }
              ++ptr;
-             if (math_entry != NULL)
+             if (ent->ismath)
                {
                  float farg1, farg2 = 0;
-                 volatile float fresult;
 
                  farg1 = (float) strtod (ptr, &ptr);
-                 if (math_entry->nargs == 2)
+                 if (entry->nargs == 2)
                    {
                      if (*ptr++ != ',')
                        {
@@ -4532,12 +4607,17 @@ subsym_substitute (char *line, int forced)
                        }
                      farg2 = (float) strtod (ptr, &ptr);
                    }
-                 fresult = (*math_entry->proc) (farg1, farg2);
                  value = XNEWVEC (char, 128);
-                 if (math_entry->int_return)
-                   sprintf (value, "%d", (int) fresult);
+                 if (entry->type == 2)
+                   {
+                     int result = (*entry->proc.i) (farg1, farg2);
+                     sprintf (value, "%d", result);
+                   }
                  else
-                   sprintf (value, "%f", fresult);
+                   {
+                     float result = (*entry->proc.f) (farg1, farg2);
+                     sprintf (value, "%f", result);
+                   }
                  if (*ptr++ != ')')
                    {
                      as_bad (_("Extra junk in function call, expecting ')'"));
@@ -4593,7 +4673,7 @@ subsym_substitute (char *line, int forced)
                      as_bad (_("Extra junk in function call, expecting ')'"));
                      break;
                    }
-                 val = (*entry->proc) (arg1, arg2);
+                 val = (*entry->proc.s) (arg1, arg2);
                  value = XNEWVEC (char, 64);
                  sprintf (value, "%d", val);
                }
@@ -4703,8 +4783,9 @@ subsym_substitute (char *line, int forced)
 
   if (changed)
     return replacement;
-  else
-    return line;
+
+  free (replacement);
+  return line;
 }
 
 /* We use this to handle substitution symbols
index d32e0bc095b500d8faec87c5069e6adb97bce1d2..431895d1e4e1db75ce39461bb75b21e7b028881f 100644 (file)
@@ -131,4 +131,7 @@ extern void tic54x_convert_frag(bfd *, segT, fragS *);
 
 extern void tic54x_global (int);
 
+extern void tic54x_md_end (void);
+#define md_end tic54x_md_end
+
 #endif