]> git.ipfire.org Git - thirdparty/binutils-gdb.git/blobdiff - gas/config/tc-tic54x.c
Update year range in copyright notice of binutils files
[thirdparty/binutils-gdb.git] / gas / config / tc-tic54x.c
index 3ed7933b56055e0c4bc4e5e43f805bc4c98fba59..5a6bc8aa7dc67b1b02afe0f400223dc97088d794 100644 (file)
@@ -1,5 +1,5 @@
 /* tc-tic54x.c -- Assembly code for the Texas Instruments TMS320C54X
-   Copyright (C) 1999-2016 Free Software Foundation, Inc.
+   Copyright (C) 1999-2021 Free Software Foundation, Inc.
    Contributed by Timothy Wall (twall@cygnus.com)
 
    This file is part of GAS, the GNU Assembler.
@@ -50,7 +50,6 @@
 #include "sb.h"
 #include "macro.h"
 #include "subsegs.h"
-#include "struc-symbol.h"
 #include "opcode/tic54x.h"
 #include "obj-coff.h"
 #include <math.h>
@@ -161,7 +160,7 @@ size_t md_longopts_size = sizeof (md_longopts);
 static int assembly_begun = 0;
 /* Addressing mode is not entirely implemented; the latest rev of the Other
    assembler doesn't seem to make any distinction whatsoever; all relocations
-   are stored as extended relocatiosn.  Older versions used REL16 vs RELEXT16,
+   are stored as extended relocations.  Older versions used REL16 vs RELEXT16,
    but now it seems all relocations are RELEXT16.  We use all RELEXT16.
 
    The cpu version is kind of a waste of time as well.  There is one
@@ -182,11 +181,12 @@ static symbolS *last_label_seen = NULL;
 /* This ensures that all new labels are unique.  */
 static int local_label_id;
 
-static struct hash_control *subsym_recurse_hash; /* Prevent infinite recurse.  */
-static struct hash_control *math_hash; /* Built-in math functions.  */
+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!  */
-static struct hash_control *subsym_hash[100];
+#define MAX_SUBSYM_HASH 100
+static htab_t subsym_hash[MAX_SUBSYM_HASH];
 
 /* 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,18 +197,18 @@ static struct hash_control *subsym_hash[100];
    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 struct hash_control *local_label_hash[100];
+static htab_t local_label_hash[100];
 /* Keep track of struct/union tags.  */
-static struct hash_control *stag_hash;
-static struct hash_control *op_hash;
-static struct hash_control *parop_hash;
-static struct hash_control *reg_hash;
-static struct hash_control *mmreg_hash;
-static struct hash_control *cc_hash;
-static struct hash_control *cc2_hash;
-static struct hash_control *cc3_hash;
-static struct hash_control *sbit_hash;
-static struct hash_control *misc_symbol_hash;
+static htab_t stag_hash;
+static htab_t op_hash;
+static htab_t parop_hash;
+static htab_t reg_hash;
+static htab_t mmreg_hash;
+static htab_t cc_hash;
+static htab_t cc2_hash;
+static htab_t cc3_hash;
+static htab_t sbit_hash;
+static htab_t misc_symbol_hash;
 
 /* Only word (et al.), align, or conditionals are allowed within
    .struct/.union.  */
@@ -230,14 +230,14 @@ static char *subsym_substitute (char *, int);
 void
 md_show_usage (FILE *stream)
 {
-  fprintf (stream, _("C54x-specific command line  options:\n"));
+  fprintf (stream, _("C54x-specific command line options:\n"));
   fprintf (stream, _("-mfar-mode | -mf          Use extended addressing\n"));
   fprintf (stream, _("-mcpu=<CPU version>       Specify the CPU version\n"));
   fprintf (stream, _("-merrors-to-file <filename>\n"));
   fprintf (stream, _("-me <filename>            Redirect errors to a file\n"));
 }
 
-/* Output a single character (upper octect is zero).  */
+/* Output a single character (upper octet is zero).  */
 
 static void
 tic54x_emit_char (char c)
@@ -322,7 +322,6 @@ tic54x_asg (int x ATTRIBUTE_UNUSED)
   int c;
   char *name;
   char *str;
-  char *tmp;
   int quoted = *input_line_pointer == '"';
 
   ILLEGAL_WITHIN_STRUCT ();
@@ -338,7 +337,7 @@ tic54x_asg (int x ATTRIBUTE_UNUSED)
       str = input_line_pointer;
       while ((c = *input_line_pointer) != ',')
        {
-         if (is_end_of_line[(int) *input_line_pointer])
+         if (is_end_of_line[(unsigned char) c])
            break;
          ++input_line_pointer;
        }
@@ -360,12 +359,8 @@ tic54x_asg (int x ATTRIBUTE_UNUSED)
       return;
     }
 
-  tmp = xmalloc (strlen (str) + 1);
-  strcpy (tmp, str);
-  str = tmp;
-  tmp = xmalloc (strlen (name) + 1);
-  strcpy (tmp, name);
-  name = tmp;
+  str = xstrdup (str);
+  name = xstrdup (name);
   subsym_create_or_replace (name, str);
   (void) restore_line_pointer (c);
   demand_empty_rest_of_line ();
@@ -412,8 +407,7 @@ tic54x_eval (int x ATTRIBUTE_UNUSED)
       return;
     }
   c = get_symbol_name (&name); /* Get terminator.  */
-  tmp = xmalloc (strlen (name) + 1);
-  name = strcpy (tmp, name);
+  name = xstrdup (name);
   (void) restore_line_pointer (c);
 
   if (!ISALPHA (*name))
@@ -422,8 +416,7 @@ tic54x_eval (int x ATTRIBUTE_UNUSED)
       ignore_rest_of_line ();
       return;
     }
-  symbolP = symbol_new (name, absolute_section,
-                       (valueT) value, &zero_address_frag);
+  symbolP = symbol_new (name, absolute_section, &zero_address_frag, value);
   SF_SET_LOCAL (symbolP);
   symbol_table_insert (symbolP);
 
@@ -431,8 +424,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 = xmalloc (strlen (valuestr) + 1);
-  strcpy (tmp, valuestr);
+  tmp = xstrdup (valuestr);
   subsym_create_or_replace (name, tmp);
 
   demand_empty_rest_of_line ();
@@ -513,7 +505,7 @@ tic54x_bss (int x ATTRIBUTE_UNUSED)
   symbolP = symbol_find_or_make (name);
 
   if (S_GET_SEGMENT (symbolP) == bss_section)
-    symbolP->sy_frag->fr_symbol = (symbolS *) NULL;
+    symbol_get_frag (symbolP)->fr_symbol = (symbolS *) NULL;
 
   symbol_set_frag (symbolP, frag_now);
   p = frag_var (rs_org, 1, 1, (relax_substateT) 0, symbolP,
@@ -549,41 +541,35 @@ stag_add_field_symbols (struct stag *stag,
                        symbolS *rootsym,
                        const char *root_stag_name)
 {
-  char prefix[strlen (path) + 2];
+  char * prefix;
   struct stag_field *field = stag->field;
 
   /* Construct a symbol for every field contained within this structure
      including fields within structure fields.  */
-  strcpy (prefix, path);
-  if (*path)
-    strcat (prefix, ".");
+  prefix = concat (path, *path ? "." : "", NULL);
 
   while (field != NULL)
     {
-      int len = strlen (prefix) + strlen (field->name) + 2;
-      char *name = xmalloc (len);
-      strcpy (name, prefix);
-      strcat (name, field->name);
+      char *name = concat (prefix, field->name, NULL);
+      char *freename = name;
 
       if (rootsym == NULL)
        {
          symbolS *sym;
-         sym = symbol_new (name, absolute_section,
-                           (field->stag ? field->offset :
-                            (valueT) (base_offset + field->offset)),
-                           &zero_address_frag);
+         sym = symbol_new (name, absolute_section, &zero_address_frag,
+                           (field->stag ? field->offset
+                            : base_offset + field->offset));
          SF_SET_LOCAL (sym);
          symbol_table_insert (sym);
        }
       else
        {
-         char *replacement = xmalloc (strlen (name)
-                                      + strlen (stag->name) + 2);
-         strcpy (replacement, S_GET_NAME (rootsym));
-         strcat (replacement, "+");
-         strcat (replacement, root_stag_name);
-         strcat (replacement, name + strlen (S_GET_NAME (rootsym)));
-         hash_insert (subsym_hash[0], name, replacement);
+         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);
+         freename = NULL;
        }
 
       /* Recurse if the field is a structure.
@@ -593,7 +579,9 @@ stag_add_field_symbols (struct stag *stag,
                                field->offset,
                                rootsym, root_stag_name);
       field = field->next;
+      free (freename);
     }
+  free (prefix);
 }
 
 /* Keep track of stag fields so that when structures are nested we can add the
@@ -605,10 +593,9 @@ stag_add_field (struct stag *parent,
                bfd_vma offset,
                struct stag *stag)
 {
-  struct stag_field *sfield = xmalloc (sizeof (struct stag_field));
+  struct stag_field *sfield = XCNEW (struct stag_field);
 
-  memset (sfield, 0, sizeof (*sfield));
-  sfield->name = strcpy (xmalloc (strlen (name) + 1), name);
+  sfield->name = xstrdup (name);
   sfield->offset = offset;
   sfield->bitfield_offset = parent->current_bitfield_offset;
   sfield->stag = stag;
@@ -624,8 +611,8 @@ stag_add_field (struct stag *parent,
   /* Only create a symbol for this field if the parent has no name.  */
   if (!strncmp (".fake", parent->name, 5))
     {
-      symbolS *sym = symbol_new (name, absolute_section,
-                                (valueT) offset, &zero_address_frag);
+      symbolS *sym = symbol_new (name, absolute_section, &zero_address_frag,
+                                offset);
       SF_SET_LOCAL (sym);
       symbol_table_insert (sym);
     }
@@ -659,7 +646,7 @@ tic54x_struct (int arg)
     {
       /* Offset is ignored in inner structs.  */
       SKIP_WHITESPACE ();
-      if (!is_end_of_line[(int) *input_line_pointer])
+      if (!is_end_of_line[(unsigned char) *input_line_pointer])
        start_offset = get_absolute_expression ();
       else
        start_offset = 0;
@@ -668,8 +655,7 @@ tic54x_struct (int arg)
   if (current_stag)
     {
       /* Nesting, link to outer one.  */
-      current_stag->inner = (struct stag *) xmalloc (sizeof (struct stag));
-      memset (current_stag->inner, 0, sizeof (struct stag));
+      current_stag->inner = XCNEW (struct stag);
       current_stag->inner->outer = current_stag;
       current_stag = current_stag->inner;
       if (start_offset)
@@ -678,8 +664,7 @@ tic54x_struct (int arg)
     }
   else
     {
-      current_stag = (struct stag *) xmalloc (sizeof (struct stag));
-      memset (current_stag, 0, sizeof (struct stag));
+      current_stag = XCNEW (struct stag);
       abs_section_offset = start_offset;
     }
   current_stag->is_union = is_union;
@@ -690,16 +675,17 @@ tic54x_struct (int arg)
       char fake[] = ".fake_stagNNNNNNN";
       sprintf (fake, ".fake_stag%d", struct_count++);
       current_stag->sym = symbol_new (fake, absolute_section,
-                                     (valueT) abs_section_offset,
-                                     &zero_address_frag);
+                                     &zero_address_frag,
+                                     abs_section_offset);
     }
   else
     {
-      char label[strlen (S_GET_NAME (line_label)) + 1];
-      strcpy (label, S_GET_NAME (line_label));
-      current_stag->sym = symbol_new (label, absolute_section,
-                                     (valueT) abs_section_offset,
-                                     &zero_address_frag);
+      char * label = xstrdup (S_GET_NAME (line_label));
+      current_stag->sym = symbol_new (label,
+                                     absolute_section,
+                                     &zero_address_frag,
+                                     abs_section_offset);
+      free (label);
     }
   current_stag->name = S_GET_NAME (current_stag->sym);
   SF_SET_LOCAL (current_stag->sym);
@@ -754,7 +740,7 @@ tic54x_endstruct (int is_union)
   /* Nested .structs don't get put in the stag table.  */
   if (current_stag->outer == NULL)
     {
-      hash_insert (stag_hash, current_stag->name, current_stag);
+      str_hash_insert (stag_hash, current_stag->name, current_stag, 0);
       stag_add_field_symbols (current_stag, path,
                              S_GET_VALUE (current_stag->sym),
                              NULL, NULL);
@@ -784,7 +770,7 @@ tic54x_tag (int ignore ATTRIBUTE_UNUSED)
 {
   char *name;
   int c = get_symbol_name (&name);
-  struct stag *stag = (struct stag *) hash_find (stag_hash, name);
+  struct stag *stag = (struct stag *) str_hash_find (stag_hash, name);
 
   if (!stag)
     {
@@ -803,9 +789,9 @@ tic54x_tag (int ignore ATTRIBUTE_UNUSED)
     }
   else
     {
-      char label[strlen (S_GET_NAME (line_label)) + 1];
+      char * label;
 
-      strcpy (label, S_GET_NAME (line_label));
+      label = xstrdup (S_GET_NAME (line_label));
       if (current_stag != NULL)
        stag_add_field (current_stag, label,
                        abs_section_offset - S_GET_VALUE (current_stag->sym),
@@ -818,11 +804,13 @@ tic54x_tag (int ignore ATTRIBUTE_UNUSED)
            {
              as_bad (_(".tag target '%s' undefined"), label);
              ignore_rest_of_line ();
+             free (label);
              return;
            }
          stag_add_field_symbols (stag, S_GET_NAME (sym),
                                  S_GET_VALUE (stag->sym), sym, stag->name);
        }
+      free (label);
     }
 
   /* Bump by the struct size, but only if we're within a .struct section.  */
@@ -848,7 +836,7 @@ tic54x_struct_field (int type)
   int longword_align = 0;
 
   SKIP_WHITESPACE ();
-  if (!is_end_of_line[(int) *input_line_pointer])
+  if (!is_end_of_line[(unsigned char) *input_line_pointer])
     count = get_absolute_expression ();
 
   switch (type)
@@ -933,12 +921,13 @@ tic54x_struct_field (int type)
     }
   else
     {
-      char label[strlen (S_GET_NAME (line_label) + 1)];
+      char * label;
 
-      strcpy (label, S_GET_NAME (line_label));
+      label = xstrdup (S_GET_NAME (line_label));
       stag_add_field (current_stag, label,
                      abs_section_offset - S_GET_VALUE (current_stag->sym),
                      NULL);
+      free (label);
     }
 
   if (current_stag->is_union)
@@ -1117,7 +1106,7 @@ tic54x_global (int type)
       if (c == ',')
        {
          input_line_pointer++;
-         if (is_end_of_line[(int) *input_line_pointer])
+         if (is_end_of_line[(unsigned char) *input_line_pointer])
            c = *input_line_pointer;
        }
     }
@@ -1128,11 +1117,14 @@ tic54x_global (int type)
 
 /* Remove the symbol from the local label hash lookup.  */
 
-static void
-tic54x_remove_local_label (const char *key, void *value ATTRIBUTE_UNUSED)
+static int
+tic54x_remove_local_label (void **slot, void *arg ATTRIBUTE_UNUSED)
 {
-  void *elem = hash_delete (local_label_hash[macro_level], key, FALSE);
+  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;
 }
 
 /* Reset all local labels.  */
@@ -1140,7 +1132,7 @@ tic54x_remove_local_label (const char *key, void *value ATTRIBUTE_UNUSED)
 static void
 tic54x_clear_local_labels (int ignored ATTRIBUTE_UNUSED)
 {
-  hash_traverse (local_label_hash[macro_level], tic54x_remove_local_label);
+  htab_traverse (local_label_hash[macro_level], tic54x_remove_local_label, NULL);
 }
 
 /* .text
@@ -1172,28 +1164,27 @@ tic54x_sect (int arg)
     {
       char *name = NULL;
       int len;
+      /* Make sure all named initialized sections flagged properly.  If we
+         encounter instructions, we'll flag it with SEC_CODE as well.  */
+      const char *flags = ",\"w\"\n";
 
       /* If there are quotes, remove them.  */
       if (*input_line_pointer == '"')
        {
          name = demand_copy_C_string (&len);
          demand_empty_rest_of_line ();
-         name = strcpy (xmalloc (len + 10), name);
+         name = concat (name, flags, (char *) NULL);
        }
       else
        {
          int c;
 
          c = get_symbol_name (&name);
-          len = strlen(name);
-         name = strcpy (xmalloc (len + 10), name);
+         name = concat (name, flags, (char *) NULL);
          (void) restore_line_pointer (c);
          demand_empty_rest_of_line ();
        }
 
-      /* Make sure all named initialized sections flagged properly.  If we
-         encounter instructions, we'll flag it with SEC_CODE as well.  */
-      strcat (name, ",\"w\"\n");
       input_scrub_insert_line (name);
       obj_coff_section (0);
 
@@ -1244,7 +1235,7 @@ tic54x_space (int arg)
      partial allocation has not been completed yet.  */
   if (expn.X_op != O_constant || frag_bit_offset (frag_now, now_seg) == -1)
     {
-      struct bit_info *bi = xmalloc (sizeof (struct bit_info));
+      struct bit_info *bi = XNEW (struct bit_info);
 
       bi->seg = now_seg;
       bi->type = bes;
@@ -1367,8 +1358,7 @@ tic54x_usect (int x ATTRIBUTE_UNUSED)
   current_subseg = now_subseg; /* Save current subseg.  */
 
   c = get_symbol_name (&section_name); /* Get terminator.  */
-  name = xmalloc (input_line_pointer - section_name + 1);
-  strcpy (name, section_name);
+  name = xstrdup (section_name);
   c = restore_line_pointer (c);
   
   if (c == ',')
@@ -1404,7 +1394,7 @@ tic54x_usect (int x ATTRIBUTE_UNUSED)
     blocking_flag = alignment_flag = 0;
 
   seg = subseg_new (name, 0);
-  flags = bfd_get_section_flags (stdoutput, seg) | SEC_ALLOC;
+  flags = bfd_section_flags (seg) | SEC_ALLOC;
 
   if (alignment_flag)
     {
@@ -1433,7 +1423,7 @@ tic54x_usect (int x ATTRIBUTE_UNUSED)
   if (blocking_flag)
     flags |= SEC_TIC54X_BLOCK;
 
-  if (!bfd_set_section_flags (stdoutput, seg, flags))
+  if (!bfd_set_section_flags (seg, flags))
     as_warn (_("Error setting flags for \"%s\": %s"), name,
             bfd_errmsg (bfd_get_error ()));
 
@@ -1469,7 +1459,7 @@ set_cpu (enum cpu_version version)
   if (version == V545LP || version == V546LP)
     {
       symbolS *symbolP = symbol_new ("__allow_lp", absolute_section,
-                                    (valueT) 1, &zero_address_frag);
+                                    &zero_address_frag, 1);
       SF_SET_LOCAL (symbolP);
       symbol_table_insert (symbolP);
     }
@@ -1501,7 +1491,7 @@ tic54x_version (int x ATTRIBUTE_UNUSED)
 
   SKIP_WHITESPACE ();
   ver = input_line_pointer;
-  while (!is_end_of_line[(int) *input_line_pointer])
+  while (!is_end_of_line[(unsigned char) *input_line_pointer])
     ++input_line_pointer;
   c = *input_line_pointer;
   *input_line_pointer = 0;
@@ -1659,7 +1649,7 @@ tic54x_align_words (int arg)
   /* Only ".align" with no argument is allowed within .struct/.union.  */
   int count = arg;
 
-  if (!is_end_of_line[(int) *input_line_pointer])
+  if (!is_end_of_line[(unsigned char) *input_line_pointer])
     {
       if (arg == 2)
        as_warn (_("Argument to .even ignored"));
@@ -1683,7 +1673,7 @@ tic54x_align_words (int arg)
   s_align_bytes (count << 1);
 }
 
-/* Initialize multiple-bit fields withing a single word of memory.  */
+/* Initialize multiple-bit fields within a single word of memory.  */
 
 static void
 tic54x_field (int ignore ATTRIBUTE_UNUSED)
@@ -1753,7 +1743,7 @@ tic54x_field (int ignore ATTRIBUTE_UNUSED)
          fragS *alloc_frag = bit_offset_frag (frag_now, now_seg);
          if (bit_offset == -1)
            {
-             struct bit_info *bi = xmalloc (sizeof (struct bit_info));
+             struct bit_info *bi = XNEW (struct bit_info);
              /* We don't know the previous offset at this time, so store the
                 info we need and figure it out later.  */
              expressionS size_exp;
@@ -1837,8 +1827,7 @@ tic54x_clink (int ignored ATTRIBUTE_UNUSED)
        ;
       know (input_line_pointer[-1] == '\"');
       input_line_pointer[-1] = 0;
-      name = xmalloc (input_line_pointer - section_name + 1);
-      strcpy (name, section_name);
+      name = xstrdup (section_name);
 
       seg = bfd_get_section_by_name (stdoutput, name);
       if (seg == NULL)
@@ -1852,7 +1841,7 @@ tic54x_clink (int ignored ATTRIBUTE_UNUSED)
     {
       if (!tic54x_initialized_section (seg))
        {
-         as_bad (_("Current section is unitialized, "
+         as_bad (_("Current section is uninitialized, "
                    "section name required for .clink"));
          ignore_rest_of_line ();
          return;
@@ -1869,20 +1858,15 @@ tic54x_clink (int ignored ATTRIBUTE_UNUSED)
    set to "." instead.  */
 
 static void
-tic54x_set_default_include (int dot)
+tic54x_set_default_include (void)
 {
-  char *dir = ".";
-  char *tmp = NULL;
+  char *dir, *tmp = NULL;
+  const char *curfile;
+  unsigned lineno;
 
-  if (!dot)
-    {
-      const char *curfile;
-      unsigned lineno;
-
-      curfile = as_where (&lineno);
-      dir = strcpy (xmalloc (strlen (curfile) + 1), curfile);
-      tmp = strrchr (dir, '/');
-    }
+  curfile = as_where (&lineno);
+  dir = xstrdup (curfile);
+  tmp = strrchr (dir, '/');
   if (tmp != NULL)
     {
       int len;
@@ -1891,7 +1875,7 @@ tic54x_set_default_include (int dot)
       len = strlen (dir);
       if (include_dir_count == 0)
        {
-         include_dirs = (char **) xmalloc (sizeof (*include_dirs));
+         include_dirs = XNEWVEC (const char *, 1);
          include_dir_count = 1;
        }
       include_dirs[0] = dir;
@@ -1933,11 +1917,11 @@ tic54x_include (int ignored ATTRIBUTE_UNUSED)
   else
     {
       filename = input_line_pointer;
-      while (!is_end_of_line[(int) *input_line_pointer])
+      while (!is_end_of_line[(unsigned char) *input_line_pointer])
        ++input_line_pointer;
       c = *input_line_pointer;
       *input_line_pointer = '\0';
-      filename = strcpy (xmalloc (strlen (filename) + 1), filename);
+      filename = xstrdup (filename);
       *input_line_pointer = c;
       demand_empty_rest_of_line ();
     }
@@ -1945,13 +1929,12 @@ tic54x_include (int ignored ATTRIBUTE_UNUSED)
      and a .newblock.
      The included file will be inserted before the newblock, so that the
      newblock is executed after the included file is processed.  */
-  input = xmalloc (sizeof (newblock) + strlen (filename) + 4);
-  sprintf (input, "\"%s\"\n%s", filename, newblock);
+  input = concat ("\"", filename, "\"\n", newblock, (char *) NULL);
   input_scrub_insert_line (input);
 
   tic54x_clear_local_labels (0);
 
-  tic54x_set_default_include (0);
+  tic54x_set_default_include ();
 
   s_include (0);
 }
@@ -1970,11 +1953,11 @@ tic54x_message (int type)
   else
     {
       msg = input_line_pointer;
-      while (!is_end_of_line[(int) *input_line_pointer])
+      while (!is_end_of_line[(unsigned char) *input_line_pointer])
        ++input_line_pointer;
       c = *input_line_pointer;
       *input_line_pointer = 0;
-      msg = strcpy (xmalloc (strlen (msg) + 1), msg);
+      msg = xstrdup (msg);
       *input_line_pointer = c;
     }
 
@@ -2026,14 +2009,14 @@ tic54x_label (int ignored ATTRIBUTE_UNUSED)
 static void
 tic54x_mmregs (int ignored ATTRIBUTE_UNUSED)
 {
-  symbol *sym;
+  tic54x_symbol *sym;
 
   ILLEGAL_WITHIN_STRUCT ();
 
-  for (sym = (symbol *) mmregs; sym->name; sym++)
+  for (sym = (tic54x_symbol *) mmregs; sym->name; sym++)
     {
       symbolS *symbolP = symbol_new (sym->name, absolute_section,
-                                    (valueT) sym->value, &zero_address_frag);
+                                    &zero_address_frag, sym->value);
       SF_SET_LOCAL (symbolP);
       symbol_table_insert (symbolP);
     }
@@ -2048,10 +2031,10 @@ tic54x_loop (int count)
   ILLEGAL_WITHIN_STRUCT ();
 
   SKIP_WHITESPACE ();
-  if (!is_end_of_line[(int) *input_line_pointer])
+  if (!is_end_of_line[(unsigned char) *input_line_pointer])
     count = get_absolute_expression ();
 
-  do_repeat (count, "LOOP", "ENDLOOP");
+  do_repeat ((size_t) count, "LOOP", "ENDLOOP");
 }
 
 /* Normally, endloop gets eaten by the preceding loop.  */
@@ -2073,7 +2056,7 @@ tic54x_break (int ignore ATTRIBUTE_UNUSED)
   ILLEGAL_WITHIN_STRUCT ();
 
   SKIP_WHITESPACE ();
-  if (!is_end_of_line[(int) *input_line_pointer])
+  if (!is_end_of_line[(unsigned char) *input_line_pointer])
     cond = get_absolute_expression ();
 
   if (cond)
@@ -2087,7 +2070,7 @@ set_address_mode (int mode)
   if (mode == far_mode)
     {
       symbolS *symbolP = symbol_new ("__allow_far", absolute_section,
-                                    (valueT) 1, &zero_address_frag);
+                                    &zero_address_frag, 1);
       SF_SET_LOCAL (symbolP);
       symbol_table_insert (symbolP);
     }
@@ -2141,8 +2124,7 @@ tic54x_sblock (int ignore ATTRIBUTE_UNUSED)
          char *section_name;
 
          c = get_symbol_name (&section_name);
-         name = xmalloc (strlen (section_name) + 1);
-         strcpy (name, section_name);
+         name = xstrdup (section_name);
          (void) restore_line_pointer (c);
        }
 
@@ -2162,7 +2144,7 @@ tic54x_sblock (int ignore ATTRIBUTE_UNUSED)
       seg->flags |= SEC_TIC54X_BLOCK;
 
       c = *input_line_pointer;
-      if (!is_end_of_line[(int) c])
+      if (!is_end_of_line[(unsigned char) c])
        ++input_line_pointer;
     }
 
@@ -2194,7 +2176,7 @@ tic54x_set (int ignore ATTRIBUTE_UNUSED)
   if ((symbolP = symbol_find (name)) == NULL
       && (symbolP = md_undefined_symbol (name)) == NULL)
     {
-      symbolP = symbol_new (name, absolute_section, 0, &zero_address_frag);
+      symbolP = symbol_new (name, absolute_section, &zero_address_frag, 0);
       S_SET_STORAGE_CLASS (symbolP, C_STAT);
     }
   free (name);
@@ -2255,13 +2237,13 @@ tic54x_var (int ignore ATTRIBUTE_UNUSED)
        }
       c = get_symbol_name (&name);
       /* .var symbols start out with a null string.  */
-      name = strcpy (xmalloc (strlen (name) + 1), name);
-      hash_insert (subsym_hash[macro_level], name, empty);
+      name = xstrdup (name);
+      str_hash_insert (subsym_hash[macro_level], name, empty, 0);
       c = restore_line_pointer (c);
       if (c == ',')
        {
          ++input_line_pointer;
-         if (is_end_of_line[(int) *input_line_pointer])
+         if (is_end_of_line[(unsigned char) *input_line_pointer])
            c = *input_line_pointer;
        }
     }
@@ -2297,7 +2279,7 @@ tic54x_mlib (int ignore ATTRIBUTE_UNUSED)
     {
       SKIP_WHITESPACE ();
       len = 0;
-      while (!is_end_of_line[(int) *input_line_pointer]
+      while (!is_end_of_line[(unsigned char) *input_line_pointer]
             && !ISSPACE (*input_line_pointer))
        {
          obstack_1grow (&notes, *input_line_pointer);
@@ -2309,8 +2291,8 @@ tic54x_mlib (int ignore ATTRIBUTE_UNUSED)
     }
   demand_empty_rest_of_line ();
 
-  tic54x_set_default_include (0);
-  path = xmalloc ((unsigned long) len + include_dir_maxlen + 5);
+  tic54x_set_default_include ();
+  path = XNEWVEC (char, (unsigned long) len + include_dir_maxlen + 5);
 
   for (i = 0; i < include_dir_count; i++)
     {
@@ -2359,7 +2341,7 @@ tic54x_mlib (int ignore ATTRIBUTE_UNUSED)
     {
       /* Get a size at least as big as the archive member.  */
       bfd_size_type size = bfd_get_size (mbfd);
-      char *buf = xmalloc (size);
+      char *buf = XNEWVEC (char, size);
       char *fname = tmpnam (NULL);
       FILE *ftmp;
 
@@ -2467,7 +2449,7 @@ const pseudo_typeS md_pseudo_table[] =
 };
 
 int
-md_parse_option (int c, char *arg)
+md_parse_option (int c, const char *arg)
 {
   switch (c)
     {
@@ -2496,7 +2478,7 @@ md_parse_option (int c, char *arg)
       break;
     case OPTION_STDERR_TO_FILE:
       {
-       char *filename = arg;
+       const char *filename = arg;
        FILE *fp = fopen (filename, "w+");
 
        if (fp == NULL)
@@ -2519,9 +2501,13 @@ md_parse_option (int c, char *arg)
 void
 tic54x_macro_start (void)
 {
-  ++macro_level;
-  subsym_hash[macro_level] = hash_new ();
-  local_label_hash[macro_level] = hash_new ();
+  if (++macro_level >= MAX_SUBSYM_HASH)
+    {
+      as_fatal (_("Macro nesting is too deep"));
+      return;
+    }
+  subsym_hash[macro_level] = str_htab_create ();
+  local_label_hash[macro_level] = str_htab_create ();
 }
 
 void
@@ -2532,14 +2518,12 @@ tic54x_macro_info (const macro_entry *macro)
   /* Put the formal args into the substitution symbol table.  */
   for (entry = macro->formals; entry; entry = entry->next)
     {
-      char *name = strncpy (xmalloc (entry->name.len + 1),
-                           entry->name.ptr, entry->name.len);
-      char *value = strncpy (xmalloc (entry->actual.len + 1),
-                            entry->actual.ptr, entry->actual.len);
+      char *name = xstrndup (entry->name.ptr, entry->name.len);
+      char *value = xstrndup (entry->actual.ptr, entry->actual.len);
 
       name[entry->name.len] = '\0';
       value[entry->actual.len] = '\0';
-      hash_insert (subsym_hash[macro_level], name, value);
+      str_hash_insert (subsym_hash[macro_level], name, value, 0);
     }
 }
 
@@ -2548,9 +2532,9 @@ tic54x_macro_info (const macro_entry *macro)
 void
 tic54x_macro_end (void)
 {
-  hash_die (subsym_hash[macro_level]);
+  htab_delete (subsym_hash[macro_level]);
   subsym_hash[macro_level] = NULL;
-  hash_die (local_label_hash[macro_level]);
+  htab_delete (local_label_hash[macro_level]);
   local_label_hash[macro_level] = NULL;
   --macro_level;
 }
@@ -2623,8 +2607,7 @@ subsym_ismember (char *sym, char *list)
       return 0;
     }
 
-  ptr = elem = xmalloc (strlen (listv) + 1);
-  strcpy (elem, listv);
+  ptr = elem = xstrdup (listv);
   while (*ptr && *ptr != ',')
     ++ptr;
   *ptr++ = 0;
@@ -2705,9 +2688,9 @@ subsym_isname (char *a, char *ignore ATTRIBUTE_UNUSED)
 static int
 subsym_isreg (char *a, char *ignore ATTRIBUTE_UNUSED)
 {
-  if (hash_find (reg_hash, a))
+  if (str_hash_find (reg_hash, a))
     return 1;
-  if (hash_find (mmreg_hash, a))
+  if (str_hash_find (mmreg_hash, a))
     return 1;
   return 0;
 }
@@ -2717,7 +2700,7 @@ subsym_isreg (char *a, char *ignore ATTRIBUTE_UNUSED)
 static int
 subsym_structsz (char *name, char *ignore ATTRIBUTE_UNUSED)
 {
-  struct stag *stag = (struct stag *) hash_find (stag_hash, name);
+  struct stag *stag = (struct stag *) str_hash_find (stag_hash, name);
 
   if (stag)
     return stag->size;
@@ -2912,7 +2895,7 @@ math_tanh (float arg1, float ignore ATTRIBUTE_UNUSED)
 /* Built-in substitution symbol functions and math functions.  */
 typedef struct
 {
-  char *name;
+  const char *name;
   int (*proc) (char *, char *);
   int nargs;
 } subsym_proc_entry;
@@ -2936,7 +2919,7 @@ static const subsym_proc_entry subsym_procs[] =
 
 typedef struct
 {
-  char *name;
+  const char *name;
   float (*proc) (float, float);
   int nargs;
   int int_return;
@@ -2982,10 +2965,9 @@ void
 md_begin (void)
 {
   insn_template *tm;
-  symbol *sym;
+  tic54x_symbol *sym;
   const subsym_proc_entry *subsym_proc;
   const math_proc_entry *math_proc;
-  const char *hash_err;
   char **symname;
   char *TIC54X_DIR = getenv ("TIC54X_DIR");
   char *A_DIR = TIC54X_DIR ? TIC54X_DIR : getenv ("A_DIR");
@@ -3009,82 +2991,67 @@ md_begin (void)
       while (tmp != NULL);
     }
 
-  op_hash = hash_new ();
+  op_hash = str_htab_create ();
   for (tm = (insn_template *) tic54x_optab; tm->name; tm++)
-    {
-      if (hash_find (op_hash, tm->name))
-       continue;
-      hash_err = hash_insert (op_hash, tm->name, (char *) tm);
-      if (hash_err)
-       as_fatal ("Internal Error: Can't hash %s: %s",
-                 tm->name, hash_err);
-    }
-  parop_hash = hash_new ();
+    str_hash_insert (op_hash, tm->name, tm, 0);
+
+  parop_hash = str_htab_create ();
   for (tm = (insn_template *) tic54x_paroptab; tm->name; tm++)
-    {
-      if (hash_find (parop_hash, tm->name))
-       continue;
-      hash_err = hash_insert (parop_hash, tm->name, (char *) tm);
-      if (hash_err)
-       as_fatal ("Internal Error: Can't hash %s: %s",
-                 tm->name, hash_err);
-    }
-  reg_hash = hash_new ();
-  for (sym = (symbol *) regs; sym->name; sym++)
+    str_hash_insert (parop_hash, tm->name, tm, 0);
+
+  reg_hash = str_htab_create ();
+  for (sym = (tic54x_symbol *) regs; sym->name; sym++)
     {
       /* Add basic registers to the symbol table.  */
       symbolS *symbolP = symbol_new (sym->name, absolute_section,
-                                    (valueT) sym->value, &zero_address_frag);
+                                    &zero_address_frag, sym->value);
       SF_SET_LOCAL (symbolP);
       symbol_table_insert (symbolP);
-      hash_err = hash_insert (reg_hash, sym->name, (char *) sym);
+      str_hash_insert (reg_hash, sym->name, sym, 0);
     }
-  for (sym = (symbol *) mmregs; sym->name; sym++)
-    hash_err = hash_insert (reg_hash, sym->name, (char *) sym);
-  mmreg_hash = hash_new ();
-  for (sym = (symbol *) mmregs; sym->name; sym++)
-    hash_err = hash_insert (mmreg_hash, sym->name, (char *) sym);
+  for (sym = (tic54x_symbol *) mmregs; sym->name; sym++)
+    str_hash_insert (reg_hash, sym->name, sym, 0);
+  mmreg_hash = str_htab_create ();
+  for (sym = (tic54x_symbol *) mmregs; sym->name; sym++)
+    str_hash_insert (mmreg_hash, sym->name, sym, 0);
 
-  cc_hash = hash_new ();
-  for (sym = (symbol *) condition_codes; sym->name; sym++)
-    hash_err = hash_insert (cc_hash, sym->name, (char *) sym);
+  cc_hash = str_htab_create ();
+  for (sym = (tic54x_symbol *) condition_codes; sym->name; sym++)
+    str_hash_insert (cc_hash, sym->name, sym, 0);
 
-  cc2_hash = hash_new ();
-  for (sym = (symbol *) cc2_codes; sym->name; sym++)
-    hash_err = hash_insert (cc2_hash, sym->name, (char *) sym);
+  cc2_hash = str_htab_create ();
+  for (sym = (tic54x_symbol *) cc2_codes; sym->name; sym++)
+    str_hash_insert (cc2_hash, sym->name, sym, 0);
 
-  cc3_hash = hash_new ();
-  for (sym = (symbol *) cc3_codes; sym->name; sym++)
-    hash_err = hash_insert (cc3_hash, sym->name, (char *) sym);
+  cc3_hash = str_htab_create ();
+  for (sym = (tic54x_symbol *) cc3_codes; sym->name; sym++)
+    str_hash_insert (cc3_hash, sym->name, sym, 0);
 
-  sbit_hash = hash_new ();
-  for (sym = (symbol *) status_bits; sym->name; sym++)
-    hash_err = hash_insert (sbit_hash, sym->name, (char *) sym);
+  sbit_hash = str_htab_create ();
+  for (sym = (tic54x_symbol *) status_bits; sym->name; sym++)
+    str_hash_insert (sbit_hash, sym->name, sym, 0);
 
-  misc_symbol_hash = hash_new ();
+  misc_symbol_hash = str_htab_create ();
   for (symname = (char **) misc_symbols; *symname; symname++)
-    hash_err = hash_insert (misc_symbol_hash, *symname, *symname);
+    str_hash_insert (misc_symbol_hash, *symname, *symname, 0);
 
   /* 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] = hash_new ();
-  subsym_hash[0] = hash_new ();
+  local_label_hash[0] = str_htab_create ();
+  subsym_hash[0] = str_htab_create ();
   for (subsym_proc = subsym_procs; subsym_proc->name; subsym_proc++)
-    hash_err = hash_insert (subsym_hash[0], subsym_proc->name,
-                           (char *) subsym_proc);
+    str_hash_insert (subsym_hash[0], subsym_proc->name, subsym_proc, 0);
 
-  math_hash = hash_new ();
+  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.  */
-      hash_err = hash_insert (subsym_hash[0], math_proc->name,
-                             (char *) math_proc);
-      hash_err = hash_insert (math_hash, math_proc->name,
-                             (char *) math_proc);
+      str_hash_insert (subsym_hash[0], math_proc->name, math_proc, 0);
+      str_hash_insert (math_hash, math_proc->name, math_proc, 0);
     }
-  subsym_recurse_hash = hash_new ();
-  stag_hash = hash_new ();
+  subsym_recurse_hash = str_htab_create ();
+  stag_hash = str_htab_create ();
 }
 
 static int
@@ -3106,7 +3073,7 @@ get_operands (struct opstruct operands[], char *line)
   int expecting_operand = 0;
   int i;
 
-  while (numexp < MAX_OPERANDS && !is_end_of_line[(int) *lptr])
+  while (numexp < MAX_OPERANDS && !is_end_of_line[(unsigned char) *lptr])
     {
       int paren_not_balanced = 0;
       char *op_start, *op_end;
@@ -3168,7 +3135,7 @@ get_operands (struct opstruct operands[], char *line)
 
   while (*lptr && ISSPACE (*lptr++))
     ;
-  if (!is_end_of_line[(int) *lptr])
+  if (!is_end_of_line[(unsigned char) *lptr])
     {
       as_bad (_("Extra junk on line"));
       return -1;
@@ -3277,7 +3244,7 @@ is_mmreg (struct opstruct *operand)
 {
   return (is_absolute (operand)
          || is_immediate (operand)
-         || hash_find (mmreg_hash, operand->buf) != 0);
+         || str_hash_find (mmreg_hash, operand->buf) != 0);
 }
 
 static int
@@ -3321,13 +3288,13 @@ is_type (struct opstruct *operand, enum optype type)
       return strncasecmp ("ar", operand->buf, 2) == 0
        && ISDIGIT (operand->buf[2]);
     case OP_SBIT:
-      return hash_find (sbit_hash, operand->buf) != 0 || is_absolute (operand);
+      return str_hash_find (sbit_hash, operand->buf) != 0 || is_absolute (operand);
     case OP_CC:
-      return hash_find (cc_hash, operand->buf) != 0;
+      return str_hash_find (cc_hash, operand->buf) != 0;
     case OP_CC2:
-      return hash_find (cc2_hash, operand->buf) != 0;
+      return str_hash_find (cc2_hash, operand->buf) != 0;
     case OP_CC3:
-      return hash_find (cc3_hash, operand->buf) != 0
+      return str_hash_find (cc3_hash, operand->buf) != 0
        || is_immediate (operand) || is_absolute (operand);
     case OP_16:
       return (is_immediate (operand) || is_absolute (operand))
@@ -3669,7 +3636,7 @@ encode_integer (tic54x_insn *insn,
 static int
 encode_condition (tic54x_insn *insn, struct opstruct *operand)
 {
-  symbol *cc = (symbol *) hash_find (cc_hash, operand->buf);
+  tic54x_symbol *cc = (tic54x_symbol *) str_hash_find (cc_hash, operand->buf);
   if (!cc)
     {
       as_bad (_("Unrecognized condition code \"%s\""), operand->buf);
@@ -3729,7 +3696,7 @@ encode_condition (tic54x_insn *insn, struct opstruct *operand)
 static int
 encode_cc3 (tic54x_insn *insn, struct opstruct *operand)
 {
-  symbol *cc3 = (symbol *) hash_find (cc3_hash, operand->buf);
+  tic54x_symbol *cc3 = (tic54x_symbol *) str_hash_find (cc3_hash, operand->buf);
   int value = cc3 ? cc3->value : operand->exp.X_add_number << 8;
 
   if ((value & 0x0300) != value)
@@ -3758,7 +3725,7 @@ encode_arx (tic54x_insn *insn, struct opstruct *operand)
 static int
 encode_cc2 (tic54x_insn *insn, struct opstruct *operand)
 {
-  symbol *cc2 = (symbol *) hash_find (cc2_hash, operand->buf);
+  tic54x_symbol *cc2 = (tic54x_symbol *) str_hash_find (cc2_hash, operand->buf);
 
   if (!cc2)
     {
@@ -3917,7 +3884,8 @@ encode_operand (tic54x_insn *insn, enum optype type, struct opstruct *operand)
                             0, 65535, 0xFFFF);
     case OP_SBIT:
       {
-       symbol *sbit = (symbol *) hash_find (sbit_hash, operand->buf);
+       tic54x_symbol *sbit = (tic54x_symbol *)
+         str_hash_find (sbit_hash, operand->buf);
        int value = is_absolute (operand) ?
          operand->exp.X_add_number : (sbit ? sbit->value : -1);
        int reg = 0;
@@ -3931,7 +3899,7 @@ encode_operand (tic54x_insn *insn, enum optype type, struct opstruct *operand)
              }
            /* Guess the register based on the status bit; "ovb" is the last
               status bit defined for st0.  */
-           if (sbit > (symbol *) hash_find (sbit_hash, "ovb"))
+           if (sbit > (tic54x_symbol *) str_hash_find (sbit_hash, "ovb"))
              reg = 1;
          }
        if (value == -1)
@@ -3996,12 +3964,12 @@ static void
 emit_insn (tic54x_insn *insn)
 {
   int i;
-  flagword oldflags = bfd_get_section_flags (stdoutput, now_seg);
+  flagword oldflags = bfd_section_flags (now_seg);
   flagword flags = oldflags | SEC_CODE;
 
-  if (! bfd_set_section_flags (stdoutput, now_seg, flags))
+  if (!bfd_set_section_flags (now_seg, flags))
         as_warn (_("error setting flags for \"%s\": %s"),
-                 bfd_section_name (stdoutput, now_seg),
+                 bfd_section_name (now_seg),
                  bfd_errmsg (bfd_get_error ()));
 
   for (i = 0; i < insn->words; i++)
@@ -4171,7 +4139,7 @@ optimize_insn (tic54x_insn *insn)
 static int
 tic54x_parse_insn (tic54x_insn *insn, char *line)
 {
-  insn->tm = (insn_template *) hash_find (op_hash, insn->mnemonic);
+  insn->tm = (insn_template *) str_hash_find (op_hash, insn->mnemonic);
   if (!insn->tm)
     {
       as_bad (_("Unrecognized instruction \"%s\""), insn->mnemonic);
@@ -4194,8 +4162,8 @@ tic54x_parse_insn (tic54x_insn *insn, char *line)
          /* SUCCESS! now try some optimizations.  */
          if (optimize_insn (insn))
            {
-             insn->tm = (insn_template *) hash_find (op_hash,
-                                                      insn->mnemonic);
+             insn->tm = (insn_template *) str_hash_find (op_hash,
+                                                         insn->mnemonic);
              continue;
            }
 
@@ -4219,7 +4187,7 @@ static int
 next_line_shows_parallel (char *next_line)
 {
   /* Look for the second half.  */
-  while (ISSPACE (*next_line))
+  while (*next_line != 0 && ISSPACE (*next_line))
     ++next_line;
 
   return (next_line[0] == PARALLEL_SEPARATOR
@@ -4229,7 +4197,7 @@ next_line_shows_parallel (char *next_line)
 static int
 tic54x_parse_parallel_insn_firstline (tic54x_insn *insn, char *line)
 {
-  insn->tm = (insn_template *) hash_find (parop_hash, insn->mnemonic);
+  insn->tm = (insn_template *) str_hash_find (parop_hash, insn->mnemonic);
   if (!insn->tm)
     {
       as_bad (_("Unrecognized parallel instruction \"%s\""),
@@ -4296,7 +4264,7 @@ tic54x_parse_parallel_insn_lastline (tic54x_insn *insn, char *line)
    replacement on the value.  */
 
 static char *
-subsym_get_arg (char *line, char *terminators, char **str, int nosub)
+subsym_get_arg (char *line, const char *terminators, char **str, int nosub)
 {
   char *ptr = line;
   char *endp;
@@ -4308,9 +4276,7 @@ subsym_get_arg (char *line, char *terminators, char **str, int nosub)
       while (ISDIGIT (*ptr))
        ++ptr;
       endp = ptr;
-      *str = xmalloc (ptr - line + 1);
-      strncpy (*str, line, ptr - line);
-      (*str)[ptr - line] = 0;
+      *str = xmemdup0 (line, ptr - line);
     }
   else if (is_string)
     {
@@ -4328,7 +4294,7 @@ subsym_get_arg (char *line, char *terminators, char **str, int nosub)
     }
   else
     {
-      char *term = terminators;
+      const char *term = terminators;
       char *value = NULL;
 
       while (*ptr && *ptr != *term)
@@ -4342,9 +4308,7 @@ subsym_get_arg (char *line, char *terminators, char **str, int nosub)
            ++term;
        }
       endp = ptr;
-      *str = xmalloc (ptr - line + 1);
-      strncpy (*str, line, ptr - line);
-      (*str)[ptr - line] = 0;
+      *str = xmemdup0 (line, ptr - line);
       /* Do simple substitution, if available.  */
       if (!nosub && (value = subsym_lookup (*str, macro_level)) != NULL)
        *str = value;
@@ -4364,17 +4328,12 @@ subsym_create_or_replace (char *name, char *value)
   int i;
 
   for (i = macro_level; i > 0; i--)
-    {
-      if (hash_find (subsym_hash[i], name))
-       {
-         hash_replace (subsym_hash[i], name, value);
-         return;
-       }
-    }
-  if (hash_find (subsym_hash[0], name))
-    hash_replace (subsym_hash[0], name, value);
-  else
-    hash_insert (subsym_hash[0], name, value);
+    if (str_hash_find (subsym_hash[i], name))
+      {
+       str_hash_insert (subsym_hash[i], name, value, 1);
+       return;
+      }
+  str_hash_insert (subsym_hash[0], name, value, 1);
 }
 
 /* Look up the substitution string replacement for the given symbol.
@@ -4384,7 +4343,7 @@ subsym_create_or_replace (char *name, char *value)
 static char *
 subsym_lookup (char *name, int nest_level)
 {
-  char *value = hash_find (subsym_hash[nest_level], name);
+  char *value = str_hash_find (subsym_hash[nest_level], name);
 
   if (value || nest_level == 0)
     return value;
@@ -4417,8 +4376,7 @@ subsym_substitute (char *line, int forced)
   char *tmp;
 
   /* Work with a copy of the input line.  */
-  replacement = xmalloc (strlen (line) + 1);
-  strcpy (replacement, line);
+  replacement = xstrdup (line);
 
   ptr = head = replacement;
 
@@ -4440,10 +4398,9 @@ subsym_substitute (char *line, int forced)
   if (strstr (line, ".macro"))
     return line;
 
-  while (!is_end_of_line[(int) *ptr])
+  unsigned char current_char;
+  while (!is_end_of_line[(current_char = * (unsigned char *) ptr)])
     {
-      int current_char = *ptr;
-
       /* Need to update this since LINE may have been modified.  */
       if (eval_line)
        eval_end = strrchr (ptr, ',');
@@ -4468,8 +4425,7 @@ subsym_substitute (char *line, int forced)
              continue;
            }
          *ptr++ = '\0';
-         tmp = xmalloc (strlen (head) + 2 + strlen (ptr) + 1);
-         sprintf (tmp, "%s==%s", head, ptr);
+         tmp = concat (head, "==", ptr, (char *) NULL);
          /* Continue examining after the '=='.  */
          ptr = tmp + strlen (head) + 2;
          free (replacement);
@@ -4508,7 +4464,7 @@ subsym_substitute (char *line, int forced)
            }
          /* Avoid infinite recursion; if a symbol shows up a second time for
             substitution, leave it as is.  */
-         if (hash_find (subsym_recurse_hash, name) == NULL)
+         if (str_hash_find (subsym_recurse_hash, name) == NULL)
            value = subsym_lookup (name, macro_level);
          else
            as_warn (_("%s symbol recursion stopped at "
@@ -4524,11 +4480,11 @@ subsym_substitute (char *line, int forced)
            {
              /* Use an existing identifier for that label if, available, or
                 create a new, unique identifier.  */
-             value = hash_find (local_label_hash[macro_level], name);
+             value = str_hash_find (local_label_hash[macro_level], name);
              if (value == NULL)
                {
                  char digit[11];
-                 char *namecopy = strcpy (xmalloc (strlen (name) + 1), name);
+                 char *namecopy = xstrdup (name);
 
                  value = strcpy (xmalloc (strlen (name) + sizeof (digit) + 1),
                                  name);
@@ -4536,7 +4492,8 @@ subsym_substitute (char *line, int forced)
                    value[strlen (value) - 1] = '\0';
                  sprintf (digit, ".%d", local_label_id++);
                  strcat (value, digit);
-                 hash_insert (local_label_hash[macro_level], namecopy, value);
+                 str_hash_insert (local_label_hash[macro_level],
+                                  namecopy, value, 0);
                }
              /* Indicate where to continue looking for substitutions.  */
              ptr = tail;
@@ -4545,7 +4502,7 @@ subsym_substitute (char *line, int forced)
          else if (value != NULL && *name == '$')
            {
              subsym_proc_entry *entry = (subsym_proc_entry *) value;
-             math_proc_entry *math_entry = hash_find (math_hash, name);
+             math_proc_entry *math_entry = str_hash_find (math_hash, name);
              char *arg1, *arg2 = NULL;
 
              *ptr = c;
@@ -4576,7 +4533,7 @@ subsym_substitute (char *line, int forced)
                      farg2 = (float) strtod (ptr, &ptr);
                    }
                  fresult = (*math_entry->proc) (farg1, farg2);
-                 value = xmalloc (128);
+                 value = XNEWVEC (char, 128);
                  if (math_entry->int_return)
                    sprintf (value, "%d", (int) fresult);
                  else
@@ -4637,7 +4594,7 @@ subsym_substitute (char *line, int forced)
                      break;
                    }
                  val = (*entry->proc) (arg1, arg2);
-                 value = xmalloc (64);
+                 value = XNEWVEC (char, 64);
                  sprintf (value, "%d", val);
                }
              /* Fix things up to replace the entire expression, not just the
@@ -4653,13 +4610,13 @@ subsym_substitute (char *line, int forced)
                 substitutions are performed, or a substitution that has been
                 previously made is encountered again.
 
-                put the symbol into the recursion hash table so we only
+                Put the symbol into the recursion hash table so we only
                 try to replace a symbol once.  */
              if (recurse)
                {
-                 hash_insert (subsym_recurse_hash, name, name);
+                 str_hash_insert (subsym_recurse_hash, name, name, 0);
                  value = subsym_substitute (value, macro_level > 0);
-                 hash_delete (subsym_recurse_hash, name, FALSE);
+                 str_hash_delete (subsym_recurse_hash, name);
                }
 
              /* Temporarily zero-terminate where the symbol started.  */
@@ -4673,8 +4630,7 @@ subsym_substitute (char *line, int forced)
                         kinda indicates that forced substitution is not
                         supposed to be recursive, but I'm not sure.  */
                      unsigned beg, len = 1; /* default to a single char */
-                     char *newval = strcpy (xmalloc (strlen (value) + 1),
-                                            value);
+                     char *newval = xstrdup (value);
 
                      savedp = input_line_pointer;
                      input_line_pointer = tail + 1;
@@ -4691,7 +4647,7 @@ subsym_substitute (char *line, int forced)
                          len = get_absolute_expression ();
                          if (beg + len > strlen (value))
                            {
-                             as_bad (_("Invalid length (use 0 to %d"),
+                             as_bad (_("Invalid length (use 0 to %d)"),
                                      (int) strlen (value) - beg);
                              break;
                            }
@@ -4765,12 +4721,11 @@ tic54x_start_line_hook (void)
   char *replacement = NULL;
 
   /* Work with a copy of the input line, including EOL char.  */
-  endp = input_line_pointer;
-  while (!is_end_of_line[(int) *endp++])
-    ;
-  line = xmalloc (endp - input_line_pointer + 1);
-  strncpy (line, input_line_pointer, endp - input_line_pointer + 1);
-  line[endp - input_line_pointer] = 0;
+  for (endp = input_line_pointer; *endp != 0; )
+    if (is_end_of_line[(unsigned char) *endp++])
+      break;
+
+  line = xmemdup0 (input_line_pointer, endp - input_line_pointer);
 
   /* Scan ahead for parallel insns.  */
   parallel_on_next_line_hint = next_line_shows_parallel (endp);
@@ -4875,8 +4830,11 @@ md_assemble (char *line)
            {
              if (words > delay_slots)
                {
-                 as_bad (_("Instruction does not fit in available delay "
-                           "slots (%d-word insn, %d slots left)"),
+                 as_bad (ngettext ("Instruction does not fit in available "
+                                   "delay slots (%d-word insn, %d slot left)",
+                                   "Instruction does not fit in available "
+                                   "delay slots (%d-word insn, %d slots left)",
+                                   delay_slots),
                          words, delay_slots);
                  delay_slots = 0;
                  return;
@@ -4947,9 +4905,13 @@ md_assemble (char *line)
        {
          if (words > delay_slots)
            {
-             as_warn (_("Instruction does not fit in available delay "
-                        "slots (%d-word insn, %d slots left). "
-                        "Resulting behavior is undefined."),
+             as_warn (ngettext ("Instruction does not fit in available "
+                                "delay slots (%d-word insn, %d slot left). "
+                                "Resulting behavior is undefined.",
+                                "Instruction does not fit in available "
+                                "delay slots (%d-word insn, %d slots left). "
+                                "Resulting behavior is undefined.",
+                                delay_slots),
                       words, delay_slots);
              delay_slots = 0;
              return;
@@ -5040,27 +5002,21 @@ tic54x_define_label (symbolS *sym)
 symbolS *
 tic54x_undefined_symbol (char *name)
 {
-  symbol *sym;
+  tic54x_symbol *sym;
 
   /* Not sure how to handle predefined symbols.  */
-  if ((sym = (symbol *) hash_find (cc_hash, name)) != NULL ||
-      (sym = (symbol *) hash_find (cc2_hash, name)) != NULL ||
-      (sym = (symbol *) hash_find (cc3_hash, name)) != NULL ||
-      (sym = (symbol *) hash_find (misc_symbol_hash, name)) != NULL ||
-      (sym = (symbol *) hash_find (sbit_hash, name)) != NULL)
+  if ((sym = (tic54x_symbol *) str_hash_find (cc_hash, name)) != NULL
+      || (sym = (tic54x_symbol *) str_hash_find (cc2_hash, name)) != NULL
+      || (sym = (tic54x_symbol *) str_hash_find (cc3_hash, name)) != NULL
+      || str_hash_find (misc_symbol_hash, name) != NULL
+      || (sym = (tic54x_symbol *) str_hash_find (sbit_hash, name)) != NULL
+      || (sym = (tic54x_symbol *) str_hash_find (reg_hash, name)) != NULL
+      || (sym = (tic54x_symbol *) str_hash_find (mmreg_hash, name)) != NULL
+      || !strcasecmp (name, "a")
+      || !strcasecmp (name, "b"))
     {
-      return symbol_new (name, reg_section,
-                        (valueT) sym->value,
-                        &zero_address_frag);
-    }
-
-  if ((sym = (symbol *) hash_find (reg_hash, name)) != NULL ||
-      (sym = (symbol *) hash_find (mmreg_hash, name)) != NULL ||
-      !strcasecmp (name, "a") || !strcasecmp (name, "b"))
-    {
-      return symbol_new (name, reg_section,
-                        (valueT) sym ? sym->value : 0,
-                        &zero_address_frag);
+      return symbol_new (name, reg_section, &zero_address_frag,
+                        sym ? sym->value : 0);
     }
 
   return NULL;
@@ -5076,7 +5032,7 @@ tic54x_parse_name (char *name ATTRIBUTE_UNUSED,
   return 0;
 }
 
-char *
+const char *
 md_atof (int type, char *literalP, int *sizeP)
 {
   /* Target data is little-endian, but floats are stored
@@ -5091,8 +5047,8 @@ tc_gen_reloc (asection *section, fixS *fixP)
   bfd_reloc_code_real_type code = fixP->fx_r_type;
   asymbol *sym = symbol_get_bfdsym (fixP->fx_addsy);
 
-  rel = (arelent *) xmalloc (sizeof (arelent));
-  rel->sym_ptr_ptr = (asymbol **) xmalloc (sizeof (asymbol *));
+  rel = XNEW (arelent);
+  rel->sym_ptr_ptr = XNEW (asymbol *);
   *rel->sym_ptr_ptr = sym;
   /* We assume that all rel->address are host byte offsets.  */
   rel->address = fixP->fx_frag->fr_address + fixP->fx_where;
@@ -5359,7 +5315,7 @@ tic54x_convert_frag (bfd *abfd ATTRIBUTE_UNUSED,
    Don't allow labels to start with '.'  */
 
 int
-tic54x_start_label (int nul_char, int next_char)
+tic54x_start_label (char * label_start, int nul_char, int next_char)
 {
   char *rest;
 
@@ -5370,18 +5326,14 @@ tic54x_start_label (int nul_char, int next_char)
   /* Disallow labels starting with "."  */
   if (next_char != ':')
     {
-      char *label = input_line_pointer;
-
-      while (!is_end_of_line[(int) label[-1]])
-       --label;
-      if (*label == '.')
+      if (*label_start == '.')
        {
-         as_bad (_("Invalid label '%s'"), label);
+         as_bad (_("Invalid label '%s'"), label_start);
          return 0;
        }
     }
 
-  if (is_end_of_line[(int) next_char])
+  if (is_end_of_line[(unsigned char) next_char])
     return 1;
 
   rest = input_line_pointer;