* config/tc-sh.h (md_cons_align): Define.
authorIan Lance Taylor <ian@airs.com>
Fri, 6 Jun 1997 21:17:46 +0000 (21:17 +0000)
committerIan Lance Taylor <ian@airs.com>
Fri, 6 Jun 1997 21:17:46 +0000 (21:17 +0000)
(sh_cons_align): Declare.
* config/tc-sh.c (md_pseudo_table): Add .uaword and .ualong.
(sh_no_align_cons): New static variable.
(s_uacons): New static function.
(sh_cons_align): New function.
(sh_handle_align): Warn about misaligned data.
* doc/c-sh.texi: Document .uaword and .ualong.
PR 12528.

gas/ChangeLog
gas/config/tc-sh.c

index fd436d3b2bacd57420aefbb8296aa8eea0e3b4cf..53253b4801fc2b7a478cdf4490db72ffcb9456a4 100644 (file)
@@ -1,3 +1,19 @@
+Fri Jun  6 17:15:55 1997  Ian Lance Taylor  <ian@cygnus.com>
+
+       * config/tc-sh.h (md_cons_align): Define.
+       (sh_cons_align): Declare.
+       * config/tc-sh.c (md_pseudo_table): Add .uaword and .ualong.
+       (sh_no_align_cons): New static variable.
+       (s_uacons): New static function.
+       (sh_cons_align): New function.
+       (sh_handle_align): Warn about misaligned data.
+       * doc/c-sh.texi: Document .uaword and .ualong.
+
+Thu Jun  5 15:38:17 1997  Ian Lance Taylor  <ian@cygnus.com>
+
+       * macro.c (macro_expand): In MRI mode, treat single quote as a
+       separator character when checking for a positional argument.
+
 Tue Jun  3 16:15:13 1997  Nick Clifton  <nickc@cygnus.com>
 
        * config/tc-arm.c (md_parse_option): Merge in changes from
index 9a406a6e8cfea907f686ea481123bc867dd311a1..b35dcfe28eecb801b7ace8a3243ead305a6dfecc 100644 (file)
@@ -1,6 +1,5 @@
 /* tc-sh.c -- Assemble code for the Hitachi Super-H
-
-   Copyright (C) 1993, 94, 95, 1996 Free Software Foundation.
+   Copyright (C) 1993, 94, 95, 96, 1997 Free Software Foundation.
 
    This file is part of GAS, the GNU Assembler.
 
@@ -37,6 +36,9 @@ const char line_comment_chars[] = "!#";
 
 static void s_uses PARAMS ((int));
 
+static void sh_count_relocs PARAMS ((bfd *, segT, PTR));
+static void sh_frob_section PARAMS ((bfd *, segT, PTR));
+
 /* This table describes all the machine specific pseudo-ops the assembler
    has to support.  The fields are:
    pseudo-op name without dot
@@ -46,6 +48,7 @@ static void s_uses PARAMS ((int));
 
 void cons ();
 void s_align_bytes ();
+static void s_uacons PARAMS ((int));
 
 int shl = 0;
 
@@ -68,6 +71,8 @@ const pseudo_typeS md_pseudo_table[] =
   {"page", listing_eject, 0},
   {"program", s_ignore, 0},
   {"uses", s_uses, 0},
+  {"uaword", s_uacons, 2},
+  {"ualong", s_uacons, 4},
   {0, 0, 0}
 };
 
@@ -815,31 +820,31 @@ build_Mytes (opcode, operand)
              nbuf[index] = reg_b | 0x08;
              break;
            case DISP_4:
-             insert (output + low_byte, R_SH_IMM4, 0);
+             insert (output + low_byte, BFD_RELOC_SH_IMM4, 0);
              break;
            case IMM_4BY4:
-             insert (output + low_byte, R_SH_IMM4BY4, 0);
+             insert (output + low_byte, BFD_RELOC_SH_IMM4BY4, 0);
              break;
            case IMM_4BY2:
-             insert (output + low_byte, R_SH_IMM4BY2, 0);
+             insert (output + low_byte, BFD_RELOC_SH_IMM4BY2, 0);
              break;
            case IMM_4:
-             insert (output + low_byte, R_SH_IMM4, 0);
+             insert (output + low_byte, BFD_RELOC_SH_IMM4, 0);
              break;
            case IMM_8BY4:
-             insert (output + low_byte, R_SH_IMM8BY4, 0);
+             insert (output + low_byte, BFD_RELOC_SH_IMM8BY4, 0);
              break;
            case IMM_8BY2:
-             insert (output + low_byte, R_SH_IMM8BY2, 0);
+             insert (output + low_byte, BFD_RELOC_SH_IMM8BY2, 0);
              break;
            case IMM_8:
-             insert (output + low_byte, R_SH_IMM8, 0);
+             insert (output + low_byte, BFD_RELOC_SH_IMM8, 0);
              break;
            case PCRELIMM_8BY4:
-             insert (output, R_SH_PCRELIMM8BY4, 1);
+             insert (output, BFD_RELOC_SH_PCRELIMM8BY4, 1);
              break;
            case PCRELIMM_8BY2:
-             insert (output, R_SH_PCRELIMM8BY2, 1);
+             insert (output, BFD_RELOC_SH_PCRELIMM8BY2, 1);
              break;
            default:
              printf ("failed for %d\n", i);
@@ -905,7 +910,8 @@ md_assemble (str)
     {
       /* Output a CODE reloc to tell the linker that the following
          bytes are instructions, not data.  */
-      fix_new (frag_now, frag_now_fix (), 2, &abs_symbol, 0, 0, R_SH_CODE);
+      fix_new (frag_now, frag_now_fix (), 2, &abs_symbol, 0, 0,
+              BFD_RELOC_SH_CODE);
       seg_info (now_seg)->tc_segment_info_data.in_code = 1;
     }
 
@@ -940,18 +946,32 @@ md_assemble (str)
 }
 
 /* This routine is called each time a label definition is seen.  It
-   emits a R_SH_LABEL reloc if necessary.  */
+   emits a BFD_RELOC_SH_LABEL reloc if necessary.  */
 
 void
 sh_frob_label ()
 {
+  static fragS *last_label_frag;
+  static int last_label_offset;
+
   if (sh_relax
       && seg_info (now_seg)->tc_segment_info_data.in_code)
-    fix_new (frag_now, frag_now_fix (), 2, &abs_symbol, 0, 0, R_SH_LABEL);
+    {
+      int offset;
+
+      offset = frag_now_fix ();
+      if (frag_now != last_label_frag
+         || offset != last_label_offset)
+       {       
+         fix_new (frag_now, offset, 2, &abs_symbol, 0, 0, BFD_RELOC_SH_LABEL);
+         last_label_frag = frag_now;
+         last_label_offset = offset;
+       }
+    }
 }
 
 /* This routine is called when the assembler is about to output some
-   data.  It emits a R_SH_DATA reloc if necessary.  */
+   data.  It emits a BFD_RELOC_SH_DATA reloc if necessary.  */
 
 void
 sh_flush_pending_output ()
@@ -959,18 +979,12 @@ sh_flush_pending_output ()
   if (sh_relax
       && seg_info (now_seg)->tc_segment_info_data.in_code)
     {
-      fix_new (frag_now, frag_now_fix (), 2, &abs_symbol, 0, 0, R_SH_DATA);
+      fix_new (frag_now, frag_now_fix (), 2, &abs_symbol, 0, 0,
+              BFD_RELOC_SH_DATA);
       seg_info (now_seg)->tc_segment_info_data.in_code = 0;
     }
 }
 
-void
-DEFUN (tc_crawl_symbol_chain, (headers),
-       object_headers * headers)
-{
-  printf ("call to tc_crawl_symbol_chain \n");
-}
-
 symbolS *
 DEFUN (md_undefined_symbol, (name),
        char *name)
@@ -978,6 +992,15 @@ DEFUN (md_undefined_symbol, (name),
   return 0;
 }
 
+#ifdef OBJ_COFF
+
+void
+DEFUN (tc_crawl_symbol_chain, (headers),
+       object_headers * headers)
+{
+  printf ("call to tc_crawl_symbol_chain \n");
+}
+
 void
 DEFUN (tc_headers_hook, (headers),
        object_headers * headers)
@@ -985,6 +1008,8 @@ DEFUN (tc_headers_hook, (headers),
   printf ("call to tc_headers_hook \n");
 }
 
+#endif
+
 /* Various routines to kill one day */
 /* Equal to MAX_PRECISION in atof-ieee.c */
 #define MAX_LITTLENUMS 6
@@ -1068,7 +1093,7 @@ s_uses (ignore)
       return;
     }
 
-  fix_new_exp (frag_now, frag_now_fix (), 2, &ex, 1, R_SH_USES);
+  fix_new_exp (frag_now, frag_now_fix (), 2, &ex, 1, BFD_RELOC_SH_USES);
 
   demand_empty_rest_of_line ();
 }
@@ -1147,128 +1172,199 @@ md_create_long_jump (ptr, from_Nddr, to_Nddr, frag, to_symbol)
   as_fatal ("failed sanity check.");
 }
 
-/* This is function is called after the symbol table has been
-   completed, but before md_convert_frag has been called.  If we have
-   seen any .uses pseudo-ops, they point to an instruction which loads
-   a register with the address of a function.  We look through the
-   fixups to find where the function address is being loaded from.  We
-   then generate a COUNT reloc giving the number of times that
-   function address is referred to.  The linker uses this information
-   when doing relaxing, to decide when it can eliminate the stored
-   function address entirely.  */
+/* This struct is used to pass arguments to sh_count_relocs through
+   bfd_map_over_sections.  */
 
-void
-sh_coff_frob_file ()
+struct sh_count_relocs
 {
-  int iseg;
+  /* Symbol we are looking for.  */
+  symbolS *sym;
+  /* Count of relocs found.  */
+  int count;
+};
 
-  if (! sh_relax)
+/* Count the number of fixups in a section which refer to a particular
+   symbol.  When using BFD_ASSEMBLER, this is called via
+   bfd_map_over_sections.  */
+
+/*ARGSUSED*/
+static void
+sh_count_relocs (abfd, sec, data)
+     bfd *abfd;
+     segT sec;
+     PTR data;
+{
+  struct sh_count_relocs *info = (struct sh_count_relocs *) data;
+  segment_info_type *seginfo;
+  symbolS *sym;
+  fixS *fix;
+
+  seginfo = seg_info (sec);
+  if (seginfo == NULL)
     return;
 
-  for (iseg = SEG_E0; iseg < SEG_UNKNOWN; iseg++)
+  sym = info->sym;
+  for (fix = seginfo->fix_root; fix != NULL; fix = fix->fx_next)
     {
-      fixS *fix;
-
-      for (fix = segment_info[iseg].fix_root; fix != NULL; fix = fix->fx_next)
+      if (fix->fx_addsy == sym)
        {
-         symbolS *sym;
-         bfd_vma val;
-         fixS *fscan;
-         int iscan;
-         int count;
-
-         if (fix->fx_r_type != R_SH_USES)
-           continue;
-
-         /* The R_SH_USES reloc should refer to a defined local
-             symbol in the same section.  */
-         sym = fix->fx_addsy;
-         if (sym == NULL
-             || fix->fx_subsy != NULL
-             || fix->fx_addnumber != 0
-             || S_GET_SEGMENT (sym) != iseg
-             || S_GET_STORAGE_CLASS (sym) == C_EXT)
-           {
-             as_warn_where (fix->fx_file, fix->fx_line,
-                            ".uses does not refer to a local symbol in the same section");
-             continue;
-           }
+         ++info->count;
+         fix->fx_tcbit = 1;
+       }
+    }
+}
 
-         /* Look through the fixups again, this time looking for one
-             at the same location as sym.  */
-         val = S_GET_VALUE (sym);
-         for (fscan = segment_info[iseg].fix_root;
-              fscan != NULL;
-              fscan = fscan->fx_next)
-           if (val == fscan->fx_frag->fr_address + fscan->fx_where
-               && fscan->fx_r_type != R_SH_ALIGN
-               && fscan->fx_r_type != R_SH_CODE
-               && fscan->fx_r_type != R_SH_DATA
-               && fscan->fx_r_type != R_SH_LABEL)
-             break;
-         if (fscan == NULL)
-           {
-             as_warn_where (fix->fx_file, fix->fx_line,
-                            "can't find fixup pointed to by .uses");
-             continue;
-           }
+/* Handle the count relocs for a particular section.  When using
+   BFD_ASSEMBLER, this is called via bfd_map_over_sections.  */
 
-         if (fscan->fx_tcbit)
-           {
-             /* We've already done this one.  */
-             continue;
-           }
+/*ARGSUSED*/
+static void
+sh_frob_section (abfd, sec, ignore)
+     bfd *abfd;
+     segT sec;
+     PTR ignore;
+{
+  segment_info_type *seginfo;
+  fixS *fix;
 
-         /* fscan should also be a fixup to a local symbol in the same
-             section.  */
-         sym = fscan->fx_addsy;
-         if (sym == NULL
-             || fscan->fx_subsy != NULL
-             || fscan->fx_addnumber != 0
-             || S_GET_SEGMENT (sym) != iseg
-             || S_GET_STORAGE_CLASS (sym) == C_EXT)
-           {
-             as_warn_where (fix->fx_file, fix->fx_line,
-                            ".uses target does not refer to a local symbol in the same section");
-             continue;
-           }
+  seginfo = seg_info (sec);
+  if (seginfo == NULL)
+    return;
 
-         /* Now we look through all the fixups of all the sections,
-            counting the number of times we find a reference to sym.  */
-         count = 0;
-         for (iscan = SEG_E0; iscan < SEG_UNKNOWN; iscan++)
-           {
-             for (fscan = segment_info[iscan].fix_root;
-                  fscan != NULL;
-                  fscan = fscan->fx_next)
-               {
-                 if (fscan->fx_addsy == sym)
-                   {
-                     ++count;
-                     fscan->fx_tcbit = 1;
-                   }
-               }
-           }
+  for (fix = seginfo->fix_root; fix != NULL; fix = fix->fx_next)
+    {
+      symbolS *sym;
+      bfd_vma val;
+      fixS *fscan;
+      struct sh_count_relocs info;
+
+      if (fix->fx_r_type != BFD_RELOC_SH_USES)
+       continue;
+
+      /* The BFD_RELOC_SH_USES reloc should refer to a defined local
+        symbol in the same section.  */
+      sym = fix->fx_addsy;
+      if (sym == NULL
+         || fix->fx_subsy != NULL
+         || fix->fx_addnumber != 0
+         || S_GET_SEGMENT (sym) != sec
+#if ! defined (BFD_ASSEMBLER) && defined (OBJ_COFF)
+         || S_GET_STORAGE_CLASS (sym) == C_EXT
+#endif
+         || S_IS_EXTERNAL (sym))
+       {
+         as_warn_where (fix->fx_file, fix->fx_line,
+                        ".uses does not refer to a local symbol in the same section");
+         continue;
+       }
+
+      /* Look through the fixups again, this time looking for one
+        at the same location as sym.  */
+      val = S_GET_VALUE (sym);
+      for (fscan = seginfo->fix_root;
+          fscan != NULL;
+          fscan = fscan->fx_next)
+       if (val == fscan->fx_frag->fr_address + fscan->fx_where
+           && fscan->fx_r_type != BFD_RELOC_SH_ALIGN
+           && fscan->fx_r_type != BFD_RELOC_SH_CODE
+           && fscan->fx_r_type != BFD_RELOC_SH_DATA
+           && fscan->fx_r_type != BFD_RELOC_SH_LABEL)
+         break;
+      if (fscan == NULL)
+       {
+         as_warn_where (fix->fx_file, fix->fx_line,
+                        "can't find fixup pointed to by .uses");
+         continue;
+       }
 
-         if (count < 1)
-           abort ();
+      if (fscan->fx_tcbit)
+       {
+         /* We've already done this one.  */
+         continue;
+       }
 
-         /* Generate a R_SH_COUNT fixup at the location of sym.  We
-             have already adjusted the value of sym to include the
-             fragment address, so we undo that adjustment here.  */
-         subseg_change (iseg, 0);
-         fix_new (sym->sy_frag, S_GET_VALUE (sym) - sym->sy_frag->fr_address,
-                  4, &abs_symbol, count, 0, R_SH_COUNT);
+      /* fscan should also be a fixup to a local symbol in the same
+        section.  */
+      sym = fscan->fx_addsy;
+      if (sym == NULL
+         || fscan->fx_subsy != NULL
+         || fscan->fx_addnumber != 0
+         || S_GET_SEGMENT (sym) != sec
+#if ! defined (BFD_ASSEMBLER) && defined (OBJ_COFF)
+         || S_GET_STORAGE_CLASS (sym) == C_EXT
+#endif
+         || S_IS_EXTERNAL (sym))
+       {
+         as_warn_where (fix->fx_file, fix->fx_line,
+                        ".uses target does not refer to a local symbol in the same section");
+         continue;
        }
+
+      /* Now we look through all the fixups of all the sections,
+        counting the number of times we find a reference to sym.  */
+      info.sym = sym;
+      info.count = 0;
+#ifdef BFD_ASSEMBLER
+      bfd_map_over_sections (stdoutput, sh_count_relocs, (PTR) &info);
+#else
+      {
+       int iscan;
+
+       for (iscan = SEG_E0; iscan < SEG_UNKNOWN; iscan++)
+         sh_count_relocs ((bfd *) NULL, iscan, (PTR) &info);
+      }
+#endif
+
+      if (info.count < 1)
+       abort ();
+
+      /* Generate a BFD_RELOC_SH_COUNT fixup at the location of sym.
+        We have already adjusted the value of sym to include the
+        fragment address, so we undo that adjustment here.  */
+      subseg_change (sec, 0);
+      fix_new (sym->sy_frag, S_GET_VALUE (sym) - sym->sy_frag->fr_address,
+              4, &abs_symbol, info.count, 0, BFD_RELOC_SH_COUNT);
     }
 }
 
+/* This function is called after the symbol table has been completed,
+   but before the relocs or section contents have been written out.
+   If we have seen any .uses pseudo-ops, they point to an instruction
+   which loads a register with the address of a function.  We look
+   through the fixups to find where the function address is being
+   loaded from.  We then generate a COUNT reloc giving the number of
+   times that function address is referred to.  The linker uses this
+   information when doing relaxing, to decide when it can eliminate
+   the stored function address entirely.  */
+
+void
+sh_frob_file ()
+{
+  if (! sh_relax)
+    return;
+
+#ifdef BFD_ASSEMBLER
+  bfd_map_over_sections (stdoutput, sh_frob_section, (PTR) NULL);
+#else
+  {
+    int iseg;
+
+    for (iseg = SEG_E0; iseg < SEG_UNKNOWN; iseg++)
+      sh_frob_section ((bfd *) NULL, iseg, (PTR) NULL);
+  }
+#endif
+}
+
 /* Called after relaxing.  Set the correct sizes of the fragments, and
    create relocs so that md_apply_fix will fill in the correct values.  */
 
 void
 md_convert_frag (headers, seg, fragP)
+#ifdef BFD_ASSEMBLER
+     bfd *headers;
+#else
      object_headers *headers;
+#endif
      segT seg;
      fragS *fragP;
 {
@@ -1279,7 +1375,7 @@ md_convert_frag (headers, seg, fragP)
     case C (COND_JUMP, COND8):
       subseg_change (seg, 0);
       fix_new (fragP, fragP->fr_fix, 2, fragP->fr_symbol, fragP->fr_offset,
-              1, R_SH_PCDISP8BY2);
+              1, BFD_RELOC_SH_PCDISP8BY2);
       fragP->fr_fix += 2;
       fragP->fr_var = 0;
       break;
@@ -1287,7 +1383,7 @@ md_convert_frag (headers, seg, fragP)
     case C (UNCOND_JUMP, UNCOND12):
       subseg_change (seg, 0);
       fix_new (fragP, fragP->fr_fix, 2, fragP->fr_symbol, fragP->fr_offset,
-              1, R_SH_PCDISP);
+              1, BFD_RELOC_SH_PCDISP12BY2);
       fragP->fr_fix += 2;
       fragP->fr_var = 0;
       break;
@@ -1337,7 +1433,7 @@ md_convert_frag (headers, seg, fragP)
               fragP->fr_symbol,
               fragP->fr_offset,
               0,
-              R_SH_IMM32);
+              BFD_RELOC_32);
       fragP->fr_fix += UNCOND32_LENGTH;
       fragP->fr_var = 0;
       donerelax = 1;
@@ -1359,15 +1455,19 @@ md_convert_frag (headers, seg, fragP)
        /* Build a relocation to six bytes farther on.  */
        subseg_change (seg, 0);
        fix_new (fragP, fragP->fr_fix, 2,
-                segment_info[seg].dot,
+#ifdef BFD_ASSEMBLER
+                section_symbol (seg),
+#else
+                seg_info (seg)->dot,
+#endif
                 fragP->fr_address + fragP->fr_fix + 6,
-                1, R_SH_PCDISP8BY2);
+                1, BFD_RELOC_SH_PCDISP8BY2);
 
        /* Set up a jump instruction.  */
        buffer[highbyte + 2] = 0xa0;
        buffer[lowbyte + 2] = 0;
        fix_new (fragP, fragP->fr_fix + 2, 2, fragP->fr_symbol,
-                fragP->fr_offset, 1, R_SH_PCDISP);
+                fragP->fr_offset, 1, BFD_RELOC_SH_PCDISP12BY2);
 
        /* Fill in a NOP instruction.  */
        buffer[highbyte + 4] = 0x0;
@@ -1425,7 +1525,7 @@ md_convert_frag (headers, seg, fragP)
               fragP->fr_symbol,
               fragP->fr_offset,
               0,
-              R_SH_IMM32);
+              BFD_RELOC_32);
       fragP->fr_fix += COND32_LENGTH;
       fragP->fr_var = 0;
       donerelax = 1;
@@ -1438,10 +1538,11 @@ md_convert_frag (headers, seg, fragP)
     }
 
   if (donerelax && !sh_relax)
-    as_warn ("Offset doesn't fit at 0x%lx, trying to get to %s+0x%lx",
-            (unsigned long) fragP->fr_address,
-            fragP->fr_symbol ? S_GET_NAME(fragP->fr_symbol): "",
-            (unsigned long) fragP->fr_offset);
+    as_warn_where (fragP->fr_file, fragP->fr_line,
+                  "overflow in branch to %s; converted into longer instruction sequence",
+                  (fragP->fr_symbol != NULL
+                   ? S_GET_NAME (fragP->fr_symbol)
+                   : ""));
 }
 
 valueT
@@ -1449,13 +1550,83 @@ DEFUN (md_section_align, (seg, size),
        segT seg AND
        valueT size)
 {
+#ifdef BFD_ASSEMBLER
+#ifdef OBJ_ELF
+  return size;
+#else /* ! OBJ_ELF */
+  return ((size + (1 << bfd_get_section_alignment (stdoutput, seg)) - 1)
+         & (-1 << bfd_get_section_alignment (stdoutput, seg)));
+#endif /* ! OBJ_ELF */
+#else /* ! BFD_ASSEMBLER */
   return ((size + (1 << section_alignment[(int) seg]) - 1)
          & (-1 << section_alignment[(int) seg]));
+#endif /* ! BFD_ASSEMBLER */
+}
+
+/* This static variable is set by s_uacons to tell sh_cons_align that
+   the expession does not need to be aligned.  */
+
+static int sh_no_align_cons = 0;
+
+/* This handles the unaligned space allocation pseudo-ops, such as
+   .uaword.  .uaword is just like .word, but the value does not need
+   to be aligned.  */
 
+static void
+s_uacons (bytes)
+     int bytes;
+{
+  /* Tell sh_cons_align not to align this value.  */
+  sh_no_align_cons = 1;
+  cons (bytes);
+}
+
+/* If a .word, et. al., pseud-op is seen, warn if the value is not
+   aligned correctly.  Note that this can cause warnings to be issued
+   when assembling initialized structured which were declared with the
+   packed attribute.  FIXME: Perhaps we should require an option to
+   enable this warning?  */
+
+void
+sh_cons_align (nbytes)
+     int nbytes;
+{
+  int nalign;
+  char *p;
+
+  if (sh_no_align_cons)
+    {
+      /* This is an unaligned pseudo-op.  */
+      sh_no_align_cons = 0;
+      return;
+    }
+
+  nalign = 0;
+  while ((nbytes & 1) == 0)
+    {
+      ++nalign;
+      nbytes >>= 1;
+    }
+
+  if (nalign == 0)
+    return;
+
+  if (now_seg == absolute_section)
+    {
+      if ((abs_section_offset & ((1 << nalign) - 1)) != 0)
+       as_warn ("misaligned data");
+      return;
+    }
+
+  p = frag_var (rs_align_code, 1, 1, (relax_substateT) 0,
+               (symbolS *) NULL, (offsetT) nalign, (char *) NULL);
+
+  record_alignment (now_seg, nalign);
 }
 
 /* When relaxing, we need to output a reloc for any .align directive
-   that requests alignment to a four byte boundary or larger.  */
+   that requests alignment to a four byte boundary or larger.  This is
+   also where we check for misaligned data.  */
 
 void
 sh_handle_align (frag)
@@ -1467,7 +1638,11 @@ sh_handle_align (frag)
       && frag->fr_offset > 1
       && now_seg != bss_section)
     fix_new (frag, frag->fr_fix, 2, &abs_symbol, frag->fr_offset, 0,
-            R_SH_ALIGN);
+            BFD_RELOC_SH_ALIGN);
+
+  if (frag->fr_type == rs_align_code
+      && frag->fr_next->fr_address - frag->fr_address - frag->fr_fix != 0)
+    as_warn_where (frag->fr_file, frag->fr_line, "misaligned data");
 }
 
 /* This macro decides whether a particular reloc is an entry in a
@@ -1475,16 +1650,23 @@ sh_handle_align (frag)
    to know about all such entries so that it can adjust them if
    necessary.  */
 
+#ifdef BFD_ASSEMBLER
+#define SWITCH_TABLE_CONS(fix) (0)
+#else
+#define SWITCH_TABLE_CONS(fix)                         \
+  ((fix)->fx_r_type == 0                               \
+   && ((fix)->fx_size == 2                             \
+       || (fix)->fx_size == 4))
+#endif
+
 #define SWITCH_TABLE(fix)                              \
   ((fix)->fx_addsy != NULL                             \
    && (fix)->fx_subsy != NULL                          \
    && S_GET_SEGMENT ((fix)->fx_addsy) == text_section  \
    && S_GET_SEGMENT ((fix)->fx_subsy) == text_section  \
-   && ((fix)->fx_r_type == R_SH_IMM32                  \
-       || (fix)->fx_r_type == R_SH_IMM16               \
-       || ((fix)->fx_r_type == 0                       \
-          && ((fix)->fx_size == 2                      \
-              || (fix)->fx_size == 4))))
+   && ((fix)->fx_r_type == BFD_RELOC_32                        \
+       || (fix)->fx_r_type == BFD_RELOC_16             \
+       || SWITCH_TABLE_CONS (fix)))
 
 /* See whether we need to force a relocation into the output file.
    This is used to force out switch and PC relative relocations when
@@ -1499,63 +1681,76 @@ sh_force_relocation (fix)
 
   return (fix->fx_pcrel
          || SWITCH_TABLE (fix)
-         || fix->fx_r_type == R_SH_COUNT
-         || fix->fx_r_type == R_SH_ALIGN
-         || fix->fx_r_type == R_SH_CODE
-         || fix->fx_r_type == R_SH_DATA
-         || fix->fx_r_type == R_SH_LABEL);
+         || fix->fx_r_type == BFD_RELOC_SH_COUNT
+         || fix->fx_r_type == BFD_RELOC_SH_ALIGN
+         || fix->fx_r_type == BFD_RELOC_SH_CODE
+         || fix->fx_r_type == BFD_RELOC_SH_DATA
+         || fix->fx_r_type == BFD_RELOC_SH_LABEL);
 }
 
 /* Apply a fixup to the object file.  */
 
+#ifdef BFD_ASSEMBLER
+int
+md_apply_fix (fixP, valp)
+     fixS *fixP;
+     valueT *valp;
+#else
 void
 md_apply_fix (fixP, val)
      fixS *fixP;
      long val;
+#endif
 {
   char *buf = fixP->fx_where + fixP->fx_frag->fr_literal;
   int lowbyte = target_big_endian ? 1 : 0;
   int highbyte = target_big_endian ? 0 : 1;
+#ifdef BFD_ASSEMBLER
+  long val = *valp;
+#endif
 
+#ifndef BFD_ASSEMBLER
   if (fixP->fx_r_type == 0)
     {
       if (fixP->fx_size == 2)
-       fixP->fx_r_type = R_SH_IMM16;
+       fixP->fx_r_type = BFD_RELOC_16;
       else if (fixP->fx_size == 4)
-       fixP->fx_r_type = R_SH_IMM32;
+       fixP->fx_r_type = BFD_RELOC_32;
       else if (fixP->fx_size == 1)
-       fixP->fx_r_type = R_SH_IMM8;
+       fixP->fx_r_type = BFD_RELOC_SH_IMM8;
       else
        abort ();
     }
+#endif
 
   switch (fixP->fx_r_type)
     {
-    case R_SH_IMM4:
+    case BFD_RELOC_SH_IMM4:
       *buf = (*buf & 0xf0) | (val & 0xf);
       break;
 
-    case R_SH_IMM4BY2:
+    case BFD_RELOC_SH_IMM4BY2:
       *buf = (*buf & 0xf0) | ((val >> 1) & 0xf);
       break;
 
-    case R_SH_IMM4BY4:
+    case BFD_RELOC_SH_IMM4BY4:
       *buf = (*buf & 0xf0) | ((val >> 2) & 0xf);
       break;
 
-    case R_SH_IMM8BY2:
+    case BFD_RELOC_SH_IMM8BY2:
       *buf = val >> 1;
       break;
 
-    case R_SH_IMM8BY4:
+    case BFD_RELOC_SH_IMM8BY4:
       *buf = val >> 2;
       break;
 
-    case R_SH_IMM8:
+    case BFD_RELOC_8:
+    case BFD_RELOC_SH_IMM8:
       *buf++ = val;
       break;
 
-    case R_SH_PCRELIMM8BY4:
+    case BFD_RELOC_SH_PCRELIMM8BY4:
       /* The lower two bits of the PC are cleared before the
          displacement is added in.  We can assume that the destination
          is on a 4 byte bounday.  If this instruction is also on a 4
@@ -1575,21 +1770,21 @@ md_apply_fix (fixP, val)
       buf[lowbyte] = val;
       break;
 
-    case R_SH_PCRELIMM8BY2:
+    case BFD_RELOC_SH_PCRELIMM8BY2:
       val /= 2;
       if (val & ~0xff)
        as_bad_where (fixP->fx_file, fixP->fx_line, "pcrel too far");
       buf[lowbyte] = val;
       break;
 
-    case R_SH_PCDISP8BY2:
+    case BFD_RELOC_SH_PCDISP8BY2:
       val /= 2;
       if (val < -0x80 || val > 0x7f)
        as_bad_where (fixP->fx_file, fixP->fx_line, "pcrel too far");
       buf[lowbyte] = val;
       break;
 
-    case R_SH_PCDISP:
+    case BFD_RELOC_SH_PCDISP12BY2:
       val /= 2;
       if (val < -0x800 || val >= 0x7ff)
        as_bad_where (fixP->fx_file, fixP->fx_line, "pcrel too far");
@@ -1597,7 +1792,7 @@ md_apply_fix (fixP, val)
       buf[highbyte] |= (val >> 8) & 0xf;
       break;
 
-    case R_SH_IMM32:
+    case BFD_RELOC_32:
       if (! target_big_endian) 
        {
          *buf++ = val >> 0;
@@ -1614,7 +1809,7 @@ md_apply_fix (fixP, val)
        }
       break;
 
-    case R_SH_IMM16:
+    case BFD_RELOC_16:
       if (! target_big_endian)
        {
          *buf++ = val >> 0;
@@ -1627,22 +1822,26 @@ md_apply_fix (fixP, val)
        }
       break;
 
-    case R_SH_USES:
+    case BFD_RELOC_SH_USES:
       /* Pass the value into sh_coff_reloc_mangle.  */
       fixP->fx_addnumber = val;
       break;
 
-    case R_SH_COUNT:
-    case R_SH_ALIGN:
-    case R_SH_CODE:
-    case R_SH_DATA:
-    case R_SH_LABEL:
+    case BFD_RELOC_SH_COUNT:
+    case BFD_RELOC_SH_ALIGN:
+    case BFD_RELOC_SH_CODE:
+    case BFD_RELOC_SH_DATA:
+    case BFD_RELOC_SH_LABEL:
       /* Nothing to do here.  */
       break;
 
     default:
       abort ();
     }
+
+#ifdef BFD_ASSEMBLER
+  return 0;
+#endif
 }
 
 int md_long_jump_size;
@@ -1729,6 +1928,8 @@ md_pcrel_from (fixP)
   return fixP->fx_size + fixP->fx_where + fixP->fx_frag->fr_address + 2;
 }
 
+#ifdef OBJ_COFF
+
 int
 tc_coff_sizemachdep (frag)
      fragS *frag;
@@ -1736,20 +1937,24 @@ tc_coff_sizemachdep (frag)
   return md_relax_table[frag->fr_subtype].rlx_length;
 }
 
+#endif /* OBJ_COFF */
+
 /* When we align the .text section, insert the correct NOP pattern.  */
 
 int
-sh_do_align (n, fill, len)
+sh_do_align (n, fill, len, max)
      int n;
      const char *fill;
      int len;
+     int max;
 {
-  if ((fill == NULL || (*fill == 0 && len == 1))
-      && (now_seg == text_section
+  if (fill == NULL
 #ifdef BFD_ASSEMBLER
-         || (now_seg->flags & SEC_CODE) != 0
+      && (now_seg->flags & SEC_CODE) != 0
+#else
+      && now_seg != data_section
+      && now_seg != bss_section
 #endif
-         || strcmp (obj_segment_name (now_seg), ".init") == 0)
       && n > 1)
     {
       static const unsigned char big_nop_pattern[] = { 0x00, 0x09 };
@@ -1757,19 +1962,55 @@ sh_do_align (n, fill, len)
 
       /* First align to a 2 byte boundary, in case there is an odd
          .byte.  */
-      frag_align (1, 0);
+      frag_align (1, 0, 0);
       if (target_big_endian)
-       frag_align_pattern (n, big_nop_pattern, sizeof big_nop_pattern);
+       frag_align_pattern (n, big_nop_pattern, sizeof big_nop_pattern, max);
       else
-       frag_align_pattern (n, little_nop_pattern, sizeof little_nop_pattern);
+       frag_align_pattern (n, little_nop_pattern, sizeof little_nop_pattern,
+                           max);
       return 1;
     }
 
   return 0;
 }
 
+#ifndef BFD_ASSEMBLER
 #ifdef OBJ_COFF
 
+/* Map BFD relocs to SH COFF relocs.  */
+
+struct reloc_map
+{
+  bfd_reloc_code_real_type bfd_reloc;
+  int sh_reloc;
+};
+
+static const struct reloc_map coff_reloc_map[] =
+{
+  { BFD_RELOC_32, R_SH_IMM32 },
+  { BFD_RELOC_16, R_SH_IMM16 },
+  { BFD_RELOC_8, R_SH_IMM8 },
+  { BFD_RELOC_SH_PCDISP8BY2, R_SH_PCDISP8BY2 },
+  { BFD_RELOC_SH_PCDISP12BY2, R_SH_PCDISP },
+  { BFD_RELOC_SH_IMM4, R_SH_IMM4 },
+  { BFD_RELOC_SH_IMM4BY2, R_SH_IMM4BY2 },
+  { BFD_RELOC_SH_IMM4BY4, R_SH_IMM4BY4 },
+  { BFD_RELOC_SH_IMM8, R_SH_IMM8 },
+  { BFD_RELOC_SH_IMM8BY2, R_SH_IMM8BY2 },
+  { BFD_RELOC_SH_IMM8BY4, R_SH_IMM8BY4 },
+  { BFD_RELOC_SH_PCRELIMM8BY2, R_SH_PCRELIMM8BY2 },
+  { BFD_RELOC_SH_PCRELIMM8BY4, R_SH_PCRELIMM8BY4 },
+  { BFD_RELOC_SH_SWITCH16, R_SH_SWITCH16 },
+  { BFD_RELOC_SH_SWITCH32, R_SH_SWITCH32 },
+  { BFD_RELOC_SH_USES, R_SH_USES },
+  { BFD_RELOC_SH_COUNT, R_SH_COUNT },
+  { BFD_RELOC_SH_ALIGN, R_SH_ALIGN },
+  { BFD_RELOC_SH_CODE, R_SH_CODE },
+  { BFD_RELOC_SH_DATA, R_SH_DATA },
+  { BFD_RELOC_SH_LABEL, R_SH_LABEL },
+  { BFD_RELOC_UNUSED, 0 }
+};
+
 /* Adjust a reloc for the SH.  This is similar to the generic code,
    but does some minor tweaking.  */
 
@@ -1787,16 +2028,25 @@ sh_coff_reloc_mangle (seg, fix, intr, paddr)
 
   if (! SWITCH_TABLE (fix))
     {
-      intr->r_type = fix->fx_r_type;
+      const struct reloc_map *rm;
+
+      for (rm = coff_reloc_map; rm->bfd_reloc != BFD_RELOC_UNUSED; rm++)
+       if (rm->bfd_reloc == (bfd_reloc_code_real_type) fix->fx_r_type)
+         break;
+      if (rm->bfd_reloc == BFD_RELOC_UNUSED)
+       as_bad_where (fix->fx_file, fix->fx_line,
+                     "Can not represent %s relocation in this object file format",
+                     bfd_get_reloc_code_name (fix->fx_r_type));
+      intr->r_type = rm->sh_reloc;
       intr->r_offset = 0;
     }
   else
     {
       know (sh_relax);
 
-      if (fix->fx_r_type == R_SH_IMM16)
+      if (fix->fx_r_type == BFD_RELOC_16)
        intr->r_type = R_SH_SWITCH16;
-      else if (fix->fx_r_type == R_SH_IMM32)
+      else if (fix->fx_r_type == BFD_RELOC_32)
        intr->r_type = R_SH_SWITCH32;
       else
        abort ();
@@ -1813,11 +2063,11 @@ sh_coff_reloc_mangle (seg, fix, intr, paddr)
     {
       switch (fix->fx_r_type)
        {
-       case R_SH_PCRELIMM8BY2:
-       case R_SH_PCRELIMM8BY4:
-       case R_SH_PCDISP8BY2:
-       case R_SH_PCDISP:
-       case R_SH_USES:
+       case BFD_RELOC_SH_PCRELIMM8BY2:
+       case BFD_RELOC_SH_PCRELIMM8BY4:
+       case BFD_RELOC_SH_PCDISP8BY2:
+       case BFD_RELOC_SH_PCDISP12BY2:
+       case BFD_RELOC_SH_USES:
          symbol_ptr = seg->dot;
          break;
        default:
@@ -1825,14 +2075,14 @@ sh_coff_reloc_mangle (seg, fix, intr, paddr)
        }
     }
 
-  if (fix->fx_r_type == R_SH_USES)
+  if (fix->fx_r_type == BFD_RELOC_SH_USES)
     {
       /* We can't store the offset in the object file, since this
         reloc does not take up any space, so we store it in r_offset.
         The fx_addnumber field was set in md_apply_fix.  */
       intr->r_offset = fix->fx_addnumber;
     }
-  else if (fix->fx_r_type == R_SH_COUNT)
+  else if (fix->fx_r_type == BFD_RELOC_SH_COUNT)
     {
       /* We can't store the count in the object file, since this reloc
          does not take up any space, so we store it in r_offset.  The
@@ -1842,16 +2092,16 @@ sh_coff_reloc_mangle (seg, fix, intr, paddr)
       /* This reloc is always absolute.  */
       symbol_ptr = NULL;
     }
-  else if (fix->fx_r_type == R_SH_ALIGN)
+  else if (fix->fx_r_type == BFD_RELOC_SH_ALIGN)
     {
       /* Store the alignment in the r_offset field.  */
       intr->r_offset = fix->fx_offset;
       /* This reloc is always absolute.  */
       symbol_ptr = NULL;
     }
-  else if (fix->fx_r_type == R_SH_CODE
-          || fix->fx_r_type == R_SH_DATA
-          || fix->fx_r_type == R_SH_LABEL)
+  else if (fix->fx_r_type == BFD_RELOC_SH_CODE
+          || fix->fx_r_type == BFD_RELOC_SH_DATA
+          || fix->fx_r_type == BFD_RELOC_SH_LABEL)
     {
       /* These relocs are always absolute.  */
       symbol_ptr = NULL;
@@ -1870,4 +2120,60 @@ sh_coff_reloc_mangle (seg, fix, intr, paddr)
     intr->r_symndx = -1;
 }
 
-#endif
+#endif /* OBJ_COFF */
+#endif /* ! BFD_ASSEMBLER */
+
+#ifdef BFD_ASSEMBLER
+
+/* Create a reloc.  */
+
+arelent *
+tc_gen_reloc (section, fixp)
+     asection *section;
+     fixS *fixp;
+{
+  arelent *rel;
+  bfd_reloc_code_real_type r_type;
+
+  rel = (arelent *) xmalloc (sizeof (arelent));
+  rel->sym_ptr_ptr = &fixp->fx_addsy->bsym;
+  rel->address = fixp->fx_frag->fr_address + fixp->fx_where;
+
+  r_type = fixp->fx_r_type;
+
+  if (SWITCH_TABLE (fixp))
+    {
+      rel->addend = rel->address - S_GET_VALUE (fixp->fx_subsy);
+      if (r_type == BFD_RELOC_16)
+       r_type = BFD_RELOC_SH_SWITCH16;
+      else if (r_type == BFD_RELOC_32)
+       r_type = BFD_RELOC_SH_SWITCH32;
+      else
+       abort ();
+    }
+  else if (r_type == BFD_RELOC_SH_USES)
+    rel->addend = fixp->fx_addnumber;
+  else if (r_type == BFD_RELOC_SH_COUNT)
+    rel->addend = fixp->fx_offset;
+  else if (r_type == BFD_RELOC_SH_ALIGN)
+    rel->addend = fixp->fx_offset;
+  else if (fixp->fx_pcrel)
+    rel->addend = fixp->fx_addnumber;
+  else
+    rel->addend = 0;
+
+  rel->howto = bfd_reloc_type_lookup (stdoutput, r_type);
+  if (rel->howto == NULL)
+    {
+      as_bad_where (fixp->fx_file, fixp->fx_line,
+                   "Cannot represent relocation type %s",
+                   bfd_get_reloc_code_name (r_type));
+      /* Set howto to a garbage value so that we can keep going.  */
+      rel->howto = bfd_reloc_type_lookup (stdoutput, BFD_RELOC_32);
+      assert (rel->howto != NULL);
+    }
+
+  return rel;
+}
+
+#endif /* BFD_ASSEMBLER */