Add support for m32rx processor.
authorNick Clifton <nickc@redhat.com>
Mon, 15 Dec 1997 23:10:11 +0000 (23:10 +0000)
committerNick Clifton <nickc@redhat.com>
Mon, 15 Dec 1997 23:10:11 +0000 (23:10 +0000)
bfd/ChangeLog
bfd/bfd-in2.h
bfd/cpu-m32r.c
bfd/elf32-m32r.c
include/elf/ChangeLog
include/elf/m32r.h [new file with mode: 0644]

index 25359f13e924d5af3e2addc3cbffe85b90e33434..ef8b0e6a218c793ebd37d38ad297debeb4be8ff0 100644 (file)
@@ -1,3 +1,28 @@
+Mon Dec 15 15:01:15 1997  Nick Clifton  <nickc@cygnus.com>
+
+       * elf32-m32r.c (m32r_elf_object_p): New Function.
+       (m32r_elf_final_write_processing):  New Function.
+       (m32r_elf_set_private_flags):  New Function.
+       (m32r_elf_copy_private_bfd_data):  New Function.
+       (m32r_elf_merge_private_bfd_data):  New Function.
+       (m32r_elf_print_private_bfd_data):  New Function.
+       (elf_backend_object_p): Point to m32r_object_p.
+       (elf_backend_final_write_processing): Point to
+       m32r_elf_final_write_processing. 
+       (bfd_elf32_bfd_copy_private_bfd_data): Point to
+       m32r_elf_copy_private_bfd_data. 
+       (bfd_elf32_bfd_merge_private_bfd_data): Point to
+       m32r_elf_merge_private_bfd_data. 
+       (bfd_elf32_bfd_set_private_flags): Point to
+       m32r_elf_set_private_bfd_data. 
+       (bfd_elf32_bfd_print_private_bfd_data): Point to
+       m32r_elf_print_private_bfd_data. 
+
+       * cpu-m32r.c: Add m32rx cpu architecture.
+
+       * bfd-in2.h (bfd_mach_m32r, bfd_mach_m32rx): Add identifiers for
+       M32R and M32RX architecture machines.
+
 Fri Dec 12 11:30:28 1997  Brendan Kehoe  <brendan@canuck.cygnus.com>
 
        * configure: Only build libbfd shared if --enable-shared's value
index b3c03fde8af3bf275583552790b8965d17019ee7..364ab4e09ab7dae1acb79f27b62ad6042414e71f 100644 (file)
@@ -1258,7 +1258,9 @@ enum bfd_architecture
   /* end-sanitize-v850e */
   bfd_arch_arc,        /* Argonaut RISC Core */
 #define bfd_mach_arc_base 0
-  bfd_arch_m32r,       /* Mitsubishi M32R/D */
+  bfd_arch_m32r,       /* Mitsubishi M32R/D/X */
+#define bfd_mach_m32r          0 /* backwards compatibility */
+#define bfd_mach_m32rx         'x'
   bfd_arch_mn10200,    /* Matsushita MN10200 */
   bfd_arch_mn10300,    /* Matsushita MN10300 */
   bfd_arch_last
index 7022c29d2a0e9408d79cfd7182203dc2a0bf1c84..d7e7a780a04648dbfad700b1525c0e28fb56a42c 100644 (file)
@@ -21,18 +21,13 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.  */
 #include "sysdep.h"
 #include "libbfd.h"
 
-const bfd_arch_info_type bfd_m32r_arch =
+#define N(number, print, default, next)  \
+{  32, 32, 8, bfd_arch_m32r, number, "m32r", print, 4, default, bfd_default_compatible, bfd_default_scan, next }
+
+static const bfd_arch_info_type arch_info_struct[2] = 
 {
-    32,        /* bits in a word */
-    32,        /* bits in an address */
-    8, /* bits in a byte */
-    bfd_arch_m32r,
-    0,
-    "d10v",
-    "d10v",
-    4, /* section alignment power */
-    true, /* the default */
-    bfd_default_compatible,
-    bfd_default_scan,
-    0
+  N( bfd_mach_m32rx, "m32rx", false, NULL ),
 };
+
+const bfd_arch_info_type bfd_m32r_arch =
+  N( bfd_mach_m32r, "m32r", true, & arch_info_struct[0] );
index b1ea706cb5f3d1a761bd1779d2d2d3d07dc42393..3da71e27bc1a061a71152dcc5c3d7a8564b6be32 100644 (file)
@@ -25,17 +25,44 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.  */
 
 static bfd_reloc_status_type m32r_elf_10_pcrel_reloc
   PARAMS ((bfd *, arelent *, asymbol *, PTR, asection *, bfd *, char **));
-static bfd_reloc_status_type m32r_elf_hi16_slo_reloc
+static bfd_reloc_status_type m32r_elf_do_10_pcrel_reloc
+  PARAMS ((bfd *, reloc_howto_type *, asection *,
+          bfd_byte *, bfd_vma, asection *, bfd_vma, bfd_vma));
+static bfd_reloc_status_type m32r_elf_hi16_reloc
+  PARAMS ((bfd *, arelent *, asymbol *, PTR, asection *, bfd *, char **));
+static void m32r_elf_relocate_hi16
+  PARAMS ((bfd *, int, Elf_Internal_Rela *, Elf_Internal_Rela *,
+          bfd_byte *, bfd_vma));
+bfd_reloc_status_type m32r_elf_lo16_reloc
+  PARAMS ((bfd *, arelent *, asymbol *, PTR, asection *, bfd *, char **));
+static bfd_reloc_status_type m32r_elf_sda16_reloc
   PARAMS ((bfd *, arelent *, asymbol *, PTR, asection *, bfd *, char **));
 static reloc_howto_type *bfd_elf32_bfd_reloc_type_lookup
   PARAMS ((bfd *abfd, bfd_reloc_code_real_type code));
 static void m32r_info_to_howto_rel
   PARAMS ((bfd *, arelent *, Elf32_Internal_Rel *));
+boolean _bfd_m32r_elf_section_from_bfd_section
+  PARAMS ((bfd *, Elf32_Internal_Shdr *, asection *, int *));
+void _bfd_m32r_elf_symbol_processing
+  PARAMS ((bfd *, asymbol *));
+static boolean m32r_elf_add_symbol_hook
+  PARAMS ((bfd *, struct bfd_link_info *, const Elf_Internal_Sym *,
+          const char **, flagword *, asection **, bfd_vma *));
+static boolean m32r_elf_relocate_section
+  PARAMS ((bfd *, struct bfd_link_info *, bfd *, asection *, bfd_byte *,
+          Elf_Internal_Rela *, Elf_Internal_Sym *, asection **));
+#if 0 /* not yet */
+static boolean m32r_elf_relax_delete_bytes
+  PARAMS ((bfd *, asection *, bfd_vma, int));
+#endif
 
-/* Use REL instead of RELA to save space.  */
+/* Use REL instead of RELA to save space.
+   This only saves space in libraries and object files, but perhaps
+   relocs will be put in ROM?  All in all though, REL relocs are a pain
+   to work with.  */
 #define USE_REL
 
-static reloc_howto_type elf_m32r_howto_table[] =
+static reloc_howto_type m32r_elf_howto_table[] =
 {
   /* This reloc does nothing.  */
   HOWTO (R_M32R_NONE,          /* type */
@@ -101,6 +128,10 @@ static reloc_howto_type elf_m32r_howto_table[] =
      This reloc is complicated because relocations are relative to pc & -4.
      i.e. branches in the right insn slot use the address of the left insn
      slot for pc.  */
+  /* ??? It's not clear whether this should have partial_inplace set or not.
+     Branch relaxing in the assembler can store the addend in the insn,
+     and if bfd_install_relocation gets called the addend may get added
+     again.  */
   HOWTO (R_M32R_10_PCREL,      /* type */
         2,                     /* rightshift */
         1,                     /* size (0 = byte, 1 = short, 2 = long) */
@@ -131,6 +162,10 @@ static reloc_howto_type elf_m32r_howto_table[] =
         true),                 /* pcrel_offset */
 
   /* A relative 26 bit relocation, right shifted by 2.  */
+  /* ??? It's not clear whether this should have partial_inplace set or not.
+     Branch relaxing in the assembler can store the addend in the insn,
+     and if bfd_install_relocation gets called the addend may get added
+     again.  */
   HOWTO (R_M32R_26_PCREL,      /* type */
         2,                     /* rightshift */
         2,                     /* size (0 = byte, 1 = short, 2 = long) */
@@ -153,7 +188,7 @@ static reloc_howto_type elf_m32r_howto_table[] =
         false,                 /* pc_relative */
         0,                     /* bitpos */
         complain_overflow_dont, /* complain_on_overflow */
-        bfd_elf_generic_reloc, /* special_function */
+        m32r_elf_hi16_reloc,   /* special_function */
         "R_M32R_HI16_ULO",     /* name */
         true,                  /* partial_inplace */
         0x0000ffff,            /* src_mask */
@@ -168,7 +203,7 @@ static reloc_howto_type elf_m32r_howto_table[] =
         false,                 /* pc_relative */
         0,                     /* bitpos */
         complain_overflow_dont, /* complain_on_overflow */
-        m32r_elf_hi16_slo_reloc, /* special_function */
+        m32r_elf_hi16_reloc,   /* special_function */
         "R_M32R_HI16_SLO",     /* name */
         true,                  /* partial_inplace */
         0x0000ffff,            /* src_mask */
@@ -183,14 +218,29 @@ static reloc_howto_type elf_m32r_howto_table[] =
         false,                 /* pc_relative */
         0,                     /* bitpos */
         complain_overflow_dont, /* complain_on_overflow */
-        bfd_elf_generic_reloc, /* special_function */
+        m32r_elf_lo16_reloc,   /* special_function */
         "R_M32R_LO16",         /* name */
         true,                  /* partial_inplace */
         0x0000ffff,            /* src_mask */
         0x0000ffff,            /* dst_mask */
         false),                /* pcrel_offset */
-};
 
+  /* Small data area 16 bits offset.  */
+  HOWTO (R_M32R_SDA16,         /* type */
+        0,                     /* rightshift */
+        2,                     /* size (0 = byte, 1 = short, 2 = long) */
+        16,                    /* bitsize */
+        false,                 /* pc_relative */
+        0,                     /* bitpos */
+        complain_overflow_signed, /* complain_on_overflow */
+        m32r_elf_sda16_reloc,  /* special_function */
+        "R_M32R_SDA16",        /* name */
+        true,                  /* partial_inplace */  /* FIXME: correct? */
+        0x0000ffff,            /* src_mask */
+        0x0000ffff,            /* dst_mask */
+        false),                /* pcrel_offset */
+};
+\f
 /* Handle the R_M32R_10_PCREL reloc.  */
 
 static bfd_reloc_status_type
@@ -204,11 +254,7 @@ m32r_elf_10_pcrel_reloc (abfd, reloc_entry, symbol, data,
      bfd *output_bfd;
      char **error_message;
 {
-  bfd_vma relocation;
-  bfd_vma x;
-  reloc_howto_type *howto;
-
-  /* This part if from bfd_elf_generic_reloc.  */
+  /* This part is from bfd_elf_generic_reloc.  */
   if (output_bfd != (bfd *) NULL
       && (symbol->flags & BSF_SECTION_SYM) == 0
       && (! reloc_entry->howto->partial_inplace
@@ -224,43 +270,90 @@ m32r_elf_10_pcrel_reloc (abfd, reloc_entry, symbol, data,
       return bfd_reloc_continue;
     }
 
-  /* The rest is copied from bfd_perform_relocation, modified to suit us.  */
+  return m32r_elf_do_10_pcrel_reloc (abfd, reloc_entry->howto,
+                                    input_section,
+                                    data, reloc_entry->address,
+                                    symbol->section,
+                                    (symbol->value
+                                     + symbol->section->output_section->vma
+                                     + symbol->section->output_offset),
+                                    reloc_entry->addend);
+}
 
-  if (reloc_entry->address > input_section->_cooked_size)
+/* Utility to actually perform an R_M32R_10_PCREL reloc.  */
+
+static bfd_reloc_status_type
+m32r_elf_do_10_pcrel_reloc (abfd, howto, input_section, data, offset,
+                           symbol_section, symbol_value, addend)
+     bfd *abfd;
+     reloc_howto_type *howto;
+     asection *input_section;
+     bfd_byte *data;
+     bfd_vma offset;
+     asection *symbol_section;
+     bfd_vma symbol_value;
+     bfd_vma addend;
+{
+  bfd_signed_vma relocation;
+  unsigned long x;
+  bfd_reloc_status_type status;
+
+  /* Sanity check the address (offset in section).  */
+  if (offset > input_section->_cooked_size)
     return bfd_reloc_outofrange;
 
-  relocation = (symbol->value
-               + symbol->section->output_section->vma
-               + symbol->section->output_offset);
-  relocation += reloc_entry->addend;
+  relocation = symbol_value + addend;
+  /* Make it pc relative.  */
   relocation -=        (input_section->output_section->vma
                 + input_section->output_offset);
-  relocation -= (reloc_entry->address & -4L);
+  /* These jumps mask off the lower two bits of the current address
+     before doing pcrel calculations.  */
+  relocation -= (offset & -4L);
 
-  howto = reloc_entry->howto;
-  x = bfd_get_16 (abfd, (char *) data + reloc_entry->address);
+  if (relocation < -0x200 || relocation > 0x1ff)
+    status = bfd_reloc_overflow;
+  else
+    status = bfd_reloc_ok;
+
+  x = bfd_get_16 (abfd, data + offset);
   relocation >>= howto->rightshift;
   relocation <<= howto->bitpos;
   x = (x & ~howto->dst_mask) | (((x & howto->src_mask) + relocation) & howto->dst_mask);
-  bfd_put_16 (abfd, x, (char *) data + reloc_entry->address);
+  bfd_put_16 (abfd, x, data + offset);
 
-  if ((bfd_signed_vma) relocation < - 0x80
-      || (bfd_signed_vma) relocation > 0x7f)
-    return bfd_reloc_overflow;
-  else
-    return bfd_reloc_ok;
+  return status;
 }
 
-/* Handle the R_M32R_HI16_SLO reloc.
-   This reloc is used in load/store with displacement instructions.
-   The lower 16 bits are sign extended when added to the high 16 bytes
-   so if the lower 16 bits are negative (bit 15 == 1) then we must add one
-   to the high 16 bytes (which will get subtracted off when the low 16 bits
-   are added.  */
+/* Handle the R_M32R_HI16_[SU]LO relocs.
+   HI16_SLO is for the add3 and load/store with displacement instructions.
+   HI16_ULO is for the or3 instruction.
+   For R_M32R_HI16_SLO, the lower 16 bits are sign extended when added to
+   the high 16 bytes so if the lower 16 bits are negative (bit 15 == 1) then
+   we must add one to the high 16 bytes (which will get subtracted off when
+   the low 16 bits are added).
+   These relocs have to be done in combination with an R_M32R_LO16 reloc
+   because there is a carry from the LO16 to the HI16.  Here we just save
+   the information we need; we do the actual relocation when we see the LO16.
+   This code is copied from the elf32-mips.c.  We also support an arbitrary
+   number of HI16 relocs to be associated with a single LO16 reloc.  The
+   assembler sorts the relocs to ensure each HI16 immediately precedes its
+   LO16.  However if there are multiple copies, the assembler may not find
+   the real LO16 so it picks the first one it finds.  */
+
+struct m32r_hi16
+{
+  struct m32r_hi16 *next;
+  bfd_byte *addr;
+  bfd_vma addend;
+};
+
+/* FIXME: This should not be a static variable.  */
+
+static struct m32r_hi16 *m32r_hi16_list;
 
 static bfd_reloc_status_type
-m32r_elf_hi16_slo_reloc (abfd, reloc_entry, symbol, data,
-                        input_section, output_bfd, error_message)
+m32r_elf_hi16_reloc (abfd, reloc_entry, symbol, data,
+                    input_section, output_bfd, error_message)
      bfd *abfd;
      arelent *reloc_entry;
      asymbol *symbol;
@@ -269,12 +362,166 @@ m32r_elf_hi16_slo_reloc (abfd, reloc_entry, symbol, data,
      bfd *output_bfd;
      char **error_message;
 {
+  bfd_reloc_status_type ret;
   bfd_vma relocation;
+  struct m32r_hi16 *n;
+
+  /* This part is from bfd_elf_generic_reloc.
+     If we're relocating, and this an external symbol, we don't want
+     to change anything.  */
+  if (output_bfd != (bfd *) NULL
+      && (symbol->flags & BSF_SECTION_SYM) == 0
+      && reloc_entry->addend == 0)
+    {
+      reloc_entry->address += input_section->output_offset;
+      return bfd_reloc_ok;
+    }
+
+  /* Sanity check the address (offset in section).  */
+  if (reloc_entry->address > input_section->_cooked_size)
+    return bfd_reloc_outofrange;
+
+  ret = bfd_reloc_ok;
+  if (bfd_is_und_section (symbol->section)
+      && output_bfd == (bfd *) NULL)
+    ret = bfd_reloc_undefined;
+
+  if (bfd_is_com_section (symbol->section))
+    relocation = 0;
+  else
+    relocation = symbol->value;
+
+  relocation += symbol->section->output_section->vma;
+  relocation += symbol->section->output_offset;
+  relocation += reloc_entry->addend;
+
+  /* Save the information, and let LO16 do the actual relocation.  */
+  n = (struct m32r_hi16 *) bfd_malloc (sizeof *n);
+  if (n == NULL)
+    return bfd_reloc_outofrange;
+  n->addr = (bfd_byte *) data + reloc_entry->address;
+  n->addend = relocation;
+  n->next = m32r_hi16_list;
+  m32r_hi16_list = n;
+
+  if (output_bfd != (bfd *) NULL)
+    reloc_entry->address += input_section->output_offset;
+
+  return ret;
+}
+
+/* Handle an M32R ELF HI16 reloc.  */
+
+static void
+m32r_elf_relocate_hi16 (input_bfd, type, relhi, rello, contents, addend)
+     bfd *input_bfd;
+     int type;
+     Elf_Internal_Rela *relhi;
+     Elf_Internal_Rela *rello;
+     bfd_byte *contents;
+     bfd_vma addend;
+{
+  unsigned long insn;
+  bfd_vma addlo;
+
+  insn = bfd_get_32 (input_bfd, contents + relhi->r_offset);
+
+  addlo = bfd_get_32 (input_bfd, contents + rello->r_offset);
+  if (type == R_M32R_HI16_SLO)
+    addlo = ((addlo & 0xffff) ^ 0x8000) - 0x8000;
+  else
+    addlo &= 0xffff;
+
+  addend += ((insn & 0xffff) << 16) + addlo;
+
+  /* Reaccount for sign extension of low part.  */
+  if (type == R_M32R_HI16_SLO
+      && (addend & 0x8000) != 0)
+    addend += 0x10000;
+
+  bfd_put_32 (input_bfd,
+             (insn & 0xffff0000) | ((addend >> 16) & 0xffff),
+             contents + relhi->r_offset);
+}
+
+/* Do an R_M32R_LO16 relocation.  This is a straightforward 16 bit
+   inplace relocation; this function exists in order to do the
+   R_M32R_HI16_[SU]LO relocation described above.  */
+
+bfd_reloc_status_type
+m32r_elf_lo16_reloc (abfd, reloc_entry, symbol, data,
+                    input_section, output_bfd, error_message)
+     bfd *abfd;
+     arelent *reloc_entry;
+     asymbol *symbol;
+     PTR data;
+     asection *input_section;
+     bfd *output_bfd;
+     char **error_message;
+{
+  if (m32r_hi16_list != NULL)
+    {
+      struct m32r_hi16 *l;
+
+      l = m32r_hi16_list;
+      while (l != NULL)
+       {
+         unsigned long insn;
+         unsigned long val;
+         unsigned long vallo;
+         struct m32r_hi16 *next;
+
+         /* Do the HI16 relocation.  Note that we actually don't need
+            to know anything about the LO16 itself, except where to
+            find the low 16 bits of the addend needed by the LO16.  */
+         insn = bfd_get_32 (abfd, l->addr);
+         vallo = ((bfd_get_32 (abfd, (bfd_byte *) data + reloc_entry->address)
+                  & 0xffff) ^ 0x8000) - 0x8000;
+         val = ((insn & 0xffff) << 16) + vallo;
+         val += l->addend;
+
+         /* Reaccount for sign extension of low part.  */
+         if ((val & 0x8000) != 0)
+           val += 0x10000;
+
+         insn = (insn &~ 0xffff) | ((val >> 16) & 0xffff);
+         bfd_put_32 (abfd, insn, l->addr);
+
+         next = l->next;
+         free (l);
+         l = next;
+       }
+
+      m32r_hi16_list = NULL;
+    }
+
+  /* Now do the LO16 reloc in the usual way.  */
+  return bfd_elf_generic_reloc (abfd, reloc_entry, symbol, data,
+                               input_section, output_bfd, error_message);
+}
+
+/* Handle the R_M32R_SDA16 reloc.
+   This reloc is used to compute the address of objects in the small data area
+   and to perform loads and stores from that area.
+   The lower 16 bits are sign extended and added to the register specified
+   in the instruction, which is assumed to point to _SDA_BASE_.  */
+
+static bfd_reloc_status_type
+m32r_elf_sda16_reloc (abfd, reloc_entry, symbol, data,
+                     input_section, output_bfd, error_message)
+     bfd *abfd;
+     arelent *reloc_entry;
+     asymbol *symbol;
+     PTR data;
+     asection *input_section;
+     bfd *output_bfd;
+     char **error_message;
+{
+  bfd_vma sda_base;
   unsigned long x;
-  int bit15;
   reloc_howto_type *howto;
 
-  /* This part if from bfd_elf_generic_reloc.  */
+  /* This part is from bfd_elf_generic_reloc.  */
   if (output_bfd != (bfd *) NULL
       && (symbol->flags & BSF_SECTION_SYM) == 0
       && (! reloc_entry->howto->partial_inplace
@@ -290,29 +537,11 @@ m32r_elf_hi16_slo_reloc (abfd, reloc_entry, symbol, data,
       return bfd_reloc_continue;
     }
 
-  /* The rest is copied from bfd_perform_relocation, modified to suit us.  */
-
-  if (reloc_entry->address > input_section->_cooked_size)
-    return bfd_reloc_outofrange;
-
-  relocation = (symbol->value
-               + symbol->section->output_section->vma
-               + symbol->section->output_offset);
-  relocation += reloc_entry->addend;
-
-  howto = reloc_entry->howto;
-  x = bfd_get_32 (abfd, (char *) data + reloc_entry->address);
-  bit15 = relocation & 0x8000;
-  relocation >>= howto->rightshift;
-  if (bit15)
-    relocation += 1;
-  relocation <<= howto->bitpos;
-  x = (x & ~howto->dst_mask) | (((x & howto->src_mask) + relocation) & howto->dst_mask);
-  bfd_put_32 (abfd, x, (char *) data + reloc_entry->address);
-
-  return bfd_reloc_ok;
+  /* FIXME: not sure what to do here yet.  But then again, the linker
+     may never call us.  */
+  abort ();
 }
-
+\f
 /* Map BFD reloc types to M32R ELF reloc types.  */
 
 struct m32r_reloc_map
@@ -333,6 +562,7 @@ static const struct m32r_reloc_map m32r_reloc_map[] =
   { BFD_RELOC_M32R_HI16_ULO, R_M32R_HI16_ULO },
   { BFD_RELOC_M32R_HI16_SLO, R_M32R_HI16_SLO },
   { BFD_RELOC_M32R_LO16, R_M32R_LO16 },
+  { BFD_RELOC_M32R_SDA16, R_M32R_SDA16 },
 };
 
 static reloc_howto_type *
@@ -347,7 +577,7 @@ bfd_elf32_bfd_reloc_type_lookup (abfd, code)
        i++)
     {
       if (m32r_reloc_map[i].bfd_reloc_val == code)
-       return &elf_m32r_howto_table[m32r_reloc_map[i].elf_reloc_val];
+       return &m32r_elf_howto_table[m32r_reloc_map[i].elf_reloc_val];
     }
 
   return NULL;
@@ -365,9 +595,1285 @@ m32r_info_to_howto_rel (abfd, cache_ptr, dst)
 
   r_type = ELF32_R_TYPE (dst->r_info);
   BFD_ASSERT (r_type < (unsigned int) R_M32R_max);
-  cache_ptr->howto = &elf_m32r_howto_table[r_type];
+  cache_ptr->howto = &m32r_elf_howto_table[r_type];
+}
+\f
+/* Given a BFD section, try to locate the corresponding ELF section
+   index.  */
+
+boolean
+_bfd_m32r_elf_section_from_bfd_section (abfd, hdr, sec, retval)
+     bfd *abfd;
+     Elf32_Internal_Shdr *hdr;
+     asection *sec;
+     int *retval;
+{
+  if (strcmp (bfd_get_section_name (abfd, sec), ".scommon") == 0)
+    {
+      *retval = SHN_M32R_SCOMMON;
+      return true;
+    }
+  return false;
+}
+
+/* M32R ELF uses two common sections.  One is the usual one, and the other
+   is for small objects.  All the small objects are kept together, and then
+   referenced via one register, which yields faster assembler code.  It is
+   up to the compiler to emit an instruction to load the register with
+   _SDA_BASE.  This is what we use for the small common section.  This
+   approach is copied from elf32-mips.c.  */
+static asection m32r_elf_scom_section;
+static asymbol m32r_elf_scom_symbol;
+static asymbol *m32r_elf_scom_symbol_ptr;
+
+/* Handle the special M32R section numbers that a symbol may use.  */
+
+void
+_bfd_m32r_elf_symbol_processing (abfd, asym)
+     bfd *abfd;
+     asymbol *asym;
+{
+  elf_symbol_type *elfsym;
+
+  elfsym = (elf_symbol_type *) asym;
+
+  switch (elfsym->internal_elf_sym.st_shndx)
+    {
+    case SHN_M32R_SCOMMON:
+      if (m32r_elf_scom_section.name == NULL)
+       {
+         /* Initialize the small common section.  */
+         m32r_elf_scom_section.name = ".scommon";
+         m32r_elf_scom_section.flags = SEC_IS_COMMON;
+         m32r_elf_scom_section.output_section = &m32r_elf_scom_section;
+         m32r_elf_scom_section.symbol = &m32r_elf_scom_symbol;
+         m32r_elf_scom_section.symbol_ptr_ptr = &m32r_elf_scom_symbol_ptr;
+         m32r_elf_scom_symbol.name = ".scommon";
+         m32r_elf_scom_symbol.flags = BSF_SECTION_SYM;
+         m32r_elf_scom_symbol.section = &m32r_elf_scom_section;
+         m32r_elf_scom_symbol_ptr = &m32r_elf_scom_symbol;
+       }
+      asym->section = &m32r_elf_scom_section;
+      asym->value = elfsym->internal_elf_sym.st_size;
+      break;
+    }
+}
+
+/* Hook called by the linker routine which adds symbols from an object
+   file.  We must handle the special M32R section numbers here.
+   We also keep watching for whether we need to create the sdata special
+   linker sections.  */
+
+static boolean
+m32r_elf_add_symbol_hook (abfd, info, sym, namep, flagsp, secp, valp)
+     bfd *abfd;
+     struct bfd_link_info *info;
+     const Elf_Internal_Sym *sym;
+     const char **namep;
+     flagword *flagsp;
+     asection **secp;
+     bfd_vma *valp;
+{
+  if (! info->relocateable
+      && (*namep)[0] == '_' && (*namep)[1] == 'S'
+      && strcmp (*namep, "_SDA_BASE_") == 0)
+    {
+      /* This is simpler than using _bfd_elf_create_linker_section
+        (our needs are simpler than ppc's needs).  Also
+        _bfd_elf_create_linker_section currently has a bug where if a .sdata
+        section already exists a new one is created that follows it which
+        screws of _SDA_BASE_ address calcs because output_offset != 0.  */
+      struct elf_link_hash_entry *h;
+      asection *s = bfd_get_section_by_name (abfd, ".sdata");
+
+      /* The following code was cobbled from elf32-ppc.c and elflink.c.  */
+
+      if (s == NULL)
+       {
+         int flags = (SEC_ALLOC | SEC_LOAD | SEC_HAS_CONTENTS
+                      | SEC_IN_MEMORY | SEC_LINKER_CREATED);
+
+         s = bfd_make_section_anyway (abfd, ".sdata");
+         if (s == NULL)
+           return false;
+         bfd_set_section_flags (abfd, s, flags);
+         bfd_set_section_alignment (abfd, s, 2);
+       }
+
+      h = (struct elf_link_hash_entry *)
+       bfd_link_hash_lookup (info->hash, "_SDA_BASE_", false, false, false);
+
+      if ((h == NULL || h->root.type == bfd_link_hash_undefined)
+         && !(_bfd_generic_link_add_one_symbol (info,
+                                                abfd,
+                                                "_SDA_BASE_",
+                                                BSF_GLOBAL,
+                                                s,
+                                                32768,
+                                                (const char *) NULL,
+                                                false,
+                                                get_elf_backend_data (abfd)->collect,
+                                                (struct bfd_link_hash_entry **) &h)))
+       return false;
+      h->type = STT_OBJECT;
+    }
+
+  switch (sym->st_shndx)
+    {
+    case SHN_M32R_SCOMMON:
+      *secp = bfd_make_section_old_way (abfd, ".scommon");
+      (*secp)->flags |= SEC_IS_COMMON;
+      *valp = sym->st_size;
+      break;
+    }
+
+  return true;
+}
+
+/* We have to figure out the SDA_BASE value, so that we can adjust the
+   symbol value correctly.  We look up the symbol _SDA_BASE_ in the output
+   BFD.  If we can't find it, we're stuck.  We cache it in the ELF
+   target data.  We don't need to adjust the symbol value for an
+   external symbol if we are producing relocateable output.  */
+
+static bfd_reloc_status_type
+m32r_elf_final_sda_base (output_bfd, info, error_message, psb)
+     bfd *output_bfd;
+     struct bfd_link_info *info;
+     const char **error_message;
+     bfd_vma *psb;
+{
+  if (elf_gp (output_bfd) == 0)
+    {
+      struct bfd_link_hash_entry *h;
+
+      h = bfd_link_hash_lookup (info->hash, "_SDA_BASE_", false, false, true);
+      if (h != (struct bfd_link_hash_entry *) NULL
+         && h->type == bfd_link_hash_defined)
+       elf_gp (output_bfd) = (h->u.def.value
+                              + h->u.def.section->output_section->vma
+                              + h->u.def.section->output_offset);
+      else
+       {
+         /* Only get the error once.  */
+         *psb = elf_gp (output_bfd) = 4;
+         *error_message =
+           (const char *) "SDA relocation when _SDA_BASE_ not defined";
+         return bfd_reloc_dangerous;
+       }
+    }
+  *psb = elf_gp (output_bfd);
+  return bfd_reloc_ok;
+}
+\f
+/* Relocate an M32R/D ELF section.
+   There is some attempt to make this function usable for many architectures,
+   both USE_REL and USE_RELA ['twould be nice if such a critter existed],
+   if only to serve as a learning tool.
+
+   The RELOCATE_SECTION function is called by the new ELF backend linker
+   to handle the relocations for a section.
+
+   The relocs are always passed as Rela structures; if the section
+   actually uses Rel structures, the r_addend field will always be
+   zero.
+
+   This function is responsible for adjust the section contents as
+   necessary, and (if using Rela relocs and generating a
+   relocateable output file) adjusting the reloc addend as
+   necessary.
+
+   This function does not have to worry about setting the reloc
+   address or the reloc symbol index.
+
+   LOCAL_SYMS is a pointer to the swapped in local symbols.
+
+   LOCAL_SECTIONS is an array giving the section in the input file
+   corresponding to the st_shndx field of each local symbol.
+
+   The global hash table entry for the global symbols can be found
+   via elf_sym_hashes (input_bfd).
+
+   When generating relocateable output, this function must handle
+   STB_LOCAL/STT_SECTION symbols specially.  The output symbol is
+   going to be the section symbol corresponding to the output
+   section, which means that the addend must be adjusted
+   accordingly.  */
+
+static boolean
+m32r_elf_relocate_section (output_bfd, info, input_bfd, input_section,
+                          contents, relocs, local_syms, local_sections)
+     bfd *output_bfd;
+     struct bfd_link_info *info;
+     bfd *input_bfd;
+     asection *input_section;
+     bfd_byte *contents;
+     Elf_Internal_Rela *relocs;
+     Elf_Internal_Sym *local_syms;
+     asection **local_sections;
+{
+  Elf_Internal_Shdr *symtab_hdr = &elf_tdata (input_bfd)->symtab_hdr;
+  struct elf_link_hash_entry **sym_hashes = elf_sym_hashes (input_bfd);
+  Elf_Internal_Rela *rel, *relend;
+  bfd *dynobj = elf_hash_table (info)->dynobj;
+  /* Assume success.  */
+  boolean ret = true;
+
+  rel = relocs;
+  relend = relocs + input_section->reloc_count;
+  for (; rel < relend; rel++)
+    {
+      int r_type;
+      reloc_howto_type *howto;
+      unsigned long r_symndx;
+      /* We can't modify r_addend here as elf_link_input_bfd has an assert to
+        ensure it's zero (we use REL relocs, not RELA).  Therefore this
+        should be assigning zero to `addend', but for clarity we use
+        `r_addend'.  */
+      bfd_vma addend = rel->r_addend;
+      bfd_vma offset = rel->r_offset;
+      struct elf_link_hash_entry *h;
+      Elf_Internal_Sym *sym;
+      asection *sec;
+      const char *sym_name;
+      bfd_reloc_status_type r;
+      const char *errmsg = NULL;
+
+      r_type = ELF32_R_TYPE (rel->r_info);
+      if (r_type < 0 || r_type >= (int) R_M32R_max)
+       {
+         (*_bfd_error_handler) ("%s: unknown relocation type %d",
+                                bfd_get_filename (input_bfd),
+                                (int) r_type);
+         bfd_set_error (bfd_error_bad_value);
+         ret = false;
+         continue;
+       }
+
+      howto = m32r_elf_howto_table + r_type;
+      r_symndx = ELF32_R_SYM (rel->r_info);
+
+      if (info->relocateable)
+       {
+         /* This is a relocateable link.  We don't have to change
+            anything, unless the reloc is against a section symbol,
+            in which case we have to adjust according to where the
+            section symbol winds up in the output section.  */
+         sec = NULL;
+         if (r_symndx >= symtab_hdr->sh_info)
+           {
+             /* External symbol.  */
+             continue;
+           }
+
+         /* Local symbol.  */
+         sym = local_syms + r_symndx;
+         sym_name = "<local symbol>";
+         /* STT_SECTION: symbol is associated with a section.  */
+         if (ELF_ST_TYPE (sym->st_info) != STT_SECTION)
+           {
+             /* Symbol isn't associated with a section.  Nothing to do.  */
+             continue;
+           }
+
+         sec = local_sections[r_symndx];
+         addend += sec->output_offset + sym->st_value;
+#ifndef USE_REL
+         /* This can't be done for USE_REL because it doesn't mean anything
+            and elf_link_input_bfd asserts this stays zero.  */
+         rel->r_addend = addend;
+#endif
+
+#ifndef USE_REL
+         /* Addends are stored with relocs.  We're done.  */
+         continue;
+#else /* USE_REL */
+         /* If partial_inplace, we need to store any additional addend
+            back in the section.  */
+         if (! howto->partial_inplace)
+           continue;
+         /* ??? Here is a nice place to call a special_function
+            like handler.  */
+         if (r_type != R_M32R_HI16_SLO && r_type != R_M32R_HI16_ULO)
+           r = _bfd_relocate_contents (howto, input_bfd,
+                                       addend, contents + offset);
+         else
+           {
+             Elf_Internal_Rela *lorel;
+
+             /* We allow an arbitrary number of HI16 relocs before the
+                LO16 reloc.  This permits gcc to emit the HI and LO relocs
+                itself.  */
+             for (lorel = rel + 1;
+                  (lorel < relend
+                   && (ELF32_R_TYPE (lorel->r_info) == R_M32R_HI16_SLO
+                       || ELF32_R_TYPE (lorel->r_info) == R_M32R_HI16_ULO));
+                  lorel++)
+               continue;
+             if (lorel < relend
+                 && ELF32_R_TYPE (lorel->r_info) == R_M32R_LO16)
+               {
+                 m32r_elf_relocate_hi16 (input_bfd, r_type, rel, lorel,
+                                         contents, addend);
+                 r = bfd_reloc_ok;
+               }
+             else
+               r = _bfd_relocate_contents (howto, input_bfd,
+                                           addend, contents + offset);
+           }
+#endif /* USE_REL */
+       }
+      else
+       {
+         bfd_vma relocation;
+
+         /* This is a final link.  */
+         h = NULL;
+         sym = NULL;
+         sec = NULL;
+
+         if (r_symndx < symtab_hdr->sh_info)
+           {
+             /* Local symbol.  */
+             sym = local_syms + r_symndx;
+             sec = local_sections[r_symndx];
+             sym_name = "<local symbol>";
+             relocation = (sec->output_section->vma
+                           + sec->output_offset
+                           + sym->st_value);
+           }
+         else
+           {
+             /* External symbol.  */
+             h = sym_hashes[r_symndx - symtab_hdr->sh_info];
+             while (h->root.type == bfd_link_hash_indirect
+                    || h->root.type == bfd_link_hash_warning)
+               h = (struct elf_link_hash_entry *) h->root.u.i.link;
+             sym_name = h->root.root.string;
+
+             if (h->root.type == bfd_link_hash_defined
+                 || h->root.type == bfd_link_hash_defweak)
+               {
+                 sec = h->root.u.def.section;
+                 if (sec->output_section == NULL)
+                   relocation = 0;
+                 else
+                   relocation = (h->root.u.def.value
+                                 + sec->output_section->vma
+                                 + sec->output_offset);
+               }
+             else if (h->root.type == bfd_link_hash_undefweak)
+               relocation = 0;
+             else
+               {
+                 if (! ((*info->callbacks->undefined_symbol)
+                        (info, h->root.root.string, input_bfd,
+                         input_section, offset)))
+                   return false;
+                 relocation = 0;
+               }
+           }
+
+         /* Sanity check the address.  */
+         if (offset > input_section->_raw_size)
+           {
+             r = bfd_reloc_outofrange;
+             goto check_reloc;
+           }
+
+         switch ((int) r_type)
+           {
+           case (int) R_M32R_10_PCREL :
+             r = m32r_elf_do_10_pcrel_reloc (input_bfd, howto, input_section,
+                                             contents, offset,
+                                             sec, relocation, addend);
+             break;
+
+           case (int) R_M32R_HI16_SLO :
+           case (int) R_M32R_HI16_ULO :
+             {
+               Elf_Internal_Rela *lorel;
+
+               /* We allow an arbitrary number of HI16 relocs before the
+                  LO16 reloc.  This permits gcc to emit the HI and LO relocs
+                  itself.  */
+               for (lorel = rel + 1;
+                    (lorel < relend
+                     && (ELF32_R_TYPE (lorel->r_info) == R_M32R_HI16_SLO
+                         || ELF32_R_TYPE (lorel->r_info) == R_M32R_HI16_ULO));
+                    lorel++)
+                 continue;
+               if (lorel < relend
+                   && ELF32_R_TYPE (lorel->r_info) == R_M32R_LO16)
+                 {
+                   m32r_elf_relocate_hi16 (input_bfd, r_type, rel, lorel,
+                                           contents, relocation + addend);
+                   r = bfd_reloc_ok;
+                 }
+               else
+                 r = _bfd_final_link_relocate (howto, input_bfd, input_section,
+                                               contents, offset,
+                                               relocation, addend);
+             }
+             break;
+
+           case (int) R_M32R_SDA16 :
+             {
+               const char *name;
+
+               BFD_ASSERT (sec != NULL);
+               name = bfd_get_section_name (abfd, sec);
+
+               if (strcmp (name, ".sdata") == 0
+                   || strcmp (name, ".sbss") == 0
+                   || strcmp (name, ".scommon") == 0)
+                 {
+                   bfd_vma sda_base;
+                   bfd *out_bfd = sec->output_section->owner;
+
+                   r = m32r_elf_final_sda_base (out_bfd, info,
+                                                &errmsg,
+                                                &sda_base);
+                   if (r != bfd_reloc_ok)
+                     {
+                       ret = false;
+                       goto check_reloc;
+                     }
+
+                   /* At this point `relocation' contains the object's
+                      address.  */
+                   relocation -= sda_base;
+                   /* Now it contains the offset from _SDA_BASE_.  */
+                 }
+               else
+                 {
+                   (*_bfd_error_handler) ("%s: The target (%s) of an %s relocation is in the wrong section (%s)",
+                                          bfd_get_filename (input_bfd),
+                                          sym_name,
+                                          m32r_elf_howto_table[(int) r_type].name,
+                                          bfd_get_section_name (abfd, sec));
+                   /*bfd_set_error (bfd_error_bad_value); ??? why? */
+                   ret = false;
+                   continue;
+                 }
+             }
+             /* fall through */
+
+           default :
+             r = _bfd_final_link_relocate (howto, input_bfd, input_section,
+                                           contents, offset,
+                                           relocation, addend);
+             break;
+           }
+       }
+
+    check_reloc:
+
+      if (r != bfd_reloc_ok)
+       {
+         /* FIXME: This should be generic enough to go in a utility.  */
+         const char *name;
+
+         if (h != NULL)
+           name = h->root.root.string;
+         else
+           {
+             name = (bfd_elf_string_from_elf_section
+                     (input_bfd, symtab_hdr->sh_link, sym->st_name));
+             if (name == NULL || *name == '\0')
+               name = bfd_section_name (input_bfd, sec);
+           }
+
+         if (errmsg != NULL)
+           goto common_error;
+
+         switch (r)
+           {
+           case bfd_reloc_overflow:
+             if (! ((*info->callbacks->reloc_overflow)
+                    (info, name, howto->name, (bfd_vma) 0,
+                     input_bfd, input_section, offset)))
+               return false;
+             break;
+
+           case bfd_reloc_undefined:
+             if (! ((*info->callbacks->undefined_symbol)
+                    (info, name, input_bfd, input_section,
+                     offset)))
+               return false;
+             break;
+
+           case bfd_reloc_outofrange:
+             errmsg = "internal error: out of range error";
+             goto common_error;
+
+           case bfd_reloc_notsupported:
+             errmsg = "internal error: unsupported relocation error";
+             goto common_error;
+
+           case bfd_reloc_dangerous:
+             errmsg = "internal error: dangerous error";
+             goto common_error;
+
+           default:
+             errmsg = "internal error: unknown error";
+             /* fall through */
+
+           common_error:
+             if (!((*info->callbacks->warning)
+                   (info, errmsg, name, input_bfd, input_section,
+                    offset)))
+               return false;
+             break;
+           }
+       }
+    }
+
+  return ret;
+}
+\f
+#if 0 /* relaxing not supported yet */
+
+/* This function handles relaxing for the m32r.
+   Relaxing on the m32r is tricky because of instruction alignment
+   requirements (4 byte instructions must be aligned on 4 byte boundaries).
+
+   The following relaxing opportunities are handled:
+
+   seth/add3/jl -> bl24 or bl8
+   seth/add3 -> ld24
+
+   It would be nice to handle bl24 -> bl8 but given:
+
+   - 4 byte insns must be on 4 byte boundaries
+   - branch instructions only branch to insns on 4 byte boundaries
+
+   this isn't much of a win because the insn in the 2 "deleted" bytes
+   must become a nop.  With some complexity some real relaxation could be
+   done but the frequency just wouldn't make it worth it; it's better to
+   try to do all the code compaction one can elsewhere.
+   When the chip supports parallel 16 bit insns, things may change.
+*/
+
+static boolean 
+m32r_elf_relax_section (abfd, sec, link_info, again)
+     bfd *abfd;
+     asection *sec;
+     struct bfd_link_info *link_info;
+     boolean *again;
+{
+  Elf_Internal_Shdr *symtab_hdr;
+  /* The Rela structures are used here because that's what
+     _bfd_elf32_link_read_relocs uses [for convenience - it sets the addend
+     field to 0].  */
+  Elf_Internal_Rela *internal_relocs;
+  Elf_Internal_Rela *free_relocs = NULL;
+  Elf_Internal_Rela *irel, *irelend;
+  bfd_byte *contents = NULL;
+  bfd_byte *free_contents = NULL;
+  Elf32_External_Sym *extsyms = NULL;
+  Elf32_External_Sym *free_extsyms = NULL;
+
+  /* Assume nothing changes.  */
+  *again = false;
+
+  /* We don't have to do anything for a relocateable link, if
+     this section does not have relocs, or if this is not a
+     code section.  */
+  if (link_info->relocateable
+      || (sec->flags & SEC_RELOC) == 0
+      || sec->reloc_count == 0
+      || (sec->flags & SEC_CODE) == 0
+      || 0 /* FIXME: check SHF_M32R_CAN_RELAX */)
+    return true;
+
+  /* If this is the first time we have been called for this section,
+     initialize the cooked size.  */
+  if (sec->_cooked_size == 0)
+    sec->_cooked_size = sec->_raw_size;
+
+  symtab_hdr = &elf_tdata (abfd)->symtab_hdr;
+
+  /* Get a copy of the native relocations.  */
+  internal_relocs = (_bfd_elf32_link_read_relocs
+                    (abfd, sec, (PTR) NULL, (Elf_Internal_Rela *) NULL,
+                     link_info->keep_memory));
+  if (internal_relocs == NULL)
+    goto error_return;
+  if (! link_info->keep_memory)
+    free_relocs = internal_relocs;
+
+  /* Walk through them looking for relaxing opportunities.  */
+  irelend = internal_relocs + sec->reloc_count;
+  for (irel = internal_relocs; irel < irelend; irel++)
+    {
+      bfd_vma symval;
+
+      /* If this isn't something that can be relaxed, then ignore
+        this reloc.  */
+      if (ELF32_R_TYPE (irel->r_info) != (int) R_M32R_HI16_SLO)
+       continue;
+
+      /* Get the section contents if we haven't done so already.  */
+      if (contents == NULL)
+       {
+         /* Get cached copy if it exists.  */
+         if (elf_section_data (sec)->this_hdr.contents != NULL)
+           contents = elf_section_data (sec)->this_hdr.contents;
+         else
+           {
+             /* Go get them off disk.  */
+             contents = (bfd_byte *) bfd_malloc (sec->_raw_size);
+             if (contents == NULL)
+               goto error_return;
+             free_contents = contents;
+
+             if (! bfd_get_section_contents (abfd, sec, contents,
+                                             (file_ptr) 0, sec->_raw_size))
+               goto error_return;
+           }
+       }
+
+      /* Read this BFD's symbols if we haven't done so already.  */
+      if (extsyms == NULL)
+       {
+         /* Get cached copy if it exists.  */
+         if (symtab_hdr->contents != NULL)
+           extsyms = (Elf32_External_Sym *) symtab_hdr->contents;
+         else
+           {
+             /* Go get them off disk.  */
+             extsyms = ((Elf32_External_Sym *)
+                        bfd_malloc (symtab_hdr->sh_size));
+             if (extsyms == NULL)
+               goto error_return;
+             free_extsyms = extsyms;
+             if (bfd_seek (abfd, symtab_hdr->sh_offset, SEEK_SET) != 0
+                 || (bfd_read (extsyms, 1, symtab_hdr->sh_size, abfd)
+                     != symtab_hdr->sh_size))
+               goto error_return;
+           }
+       }
+
+      /* Get the value of the symbol referred to by the reloc.  */
+      if (ELF32_R_SYM (irel->r_info) < symtab_hdr->sh_info)
+       {
+         Elf_Internal_Sym isym;
+         asection *sym_sec;
+
+         /* A local symbol.  */
+         bfd_elf32_swap_symbol_in (abfd,
+                                   extsyms + ELF32_R_SYM (irel->r_info),
+                                   &isym);
+
+         sym_sec = bfd_section_from_elf_index (abfd, isym.st_shndx);
+         symval = (isym.st_value
+                   + sym_sec->output_section->vma
+                   + sym_sec->output_offset);
+       }
+      else
+       {
+         unsigned long indx;
+         struct elf_link_hash_entry *h;
+
+         /* An external symbol.  */
+         indx = ELF32_R_SYM (irel->r_info) - symtab_hdr->sh_info;
+         h = elf_sym_hashes (abfd)[indx];
+         BFD_ASSERT (h != NULL);
+         if (h->root.type != bfd_link_hash_defined
+             && h->root.type != bfd_link_hash_defweak)
+           {
+             /* This appears to be a reference to an undefined
+                 symbol.  Just ignore it--it will be caught by the
+                 regular reloc processing.  */
+             continue;
+           }
+
+         symval = (h->root.u.def.value
+                   + h->root.u.def.section->output_section->vma
+                   + h->root.u.def.section->output_offset);
+       }
+
+      /* For simplicity of coding, we are going to modify the section
+        contents, the section relocs, and the BFD symbol table.  We
+        must tell the rest of the code not to free up this
+        information.  It would be possible to instead create a table
+        of changes which have to be made, as is done in coff-mips.c;
+        that would be more work, but would require less memory when
+        the linker is run.  */
+
+      /* Try to change a seth/add3/jl subroutine call to bl24 or bl8.
+        This sequence is generated by the compiler when compiling in
+        32 bit mode.  Also look for seth/add3 -> ld24.  */
+
+      if (ELF32_R_TYPE (irel->r_info) == (int) R_M32R_HI16_SLO)
+       {
+         Elf_Internal_Rela *nrel;
+         bfd_vma pc = (sec->output_section->vma + sec->output_offset
+                       + irel->r_offset);
+         bfd_signed_vma pcrel_value = symval - pc;
+         unsigned int code,reg;
+         int addend,nop_p,bl8_p,to_delete;
+
+         /* The tests are ordered so that we get out as quickly as possible
+            if this isn't something we can relax, taking into account that
+            we are looking for two separate possibilities (jl/ld24).  */
+
+         /* Do nothing if no room in the section for this to be what we're
+            looking for.  */
+         if (irel->r_offset > sec->_cooked_size - 8)
+           continue;
+
+         /* Make sure the next relocation applies to the next
+            instruction and that it's the add3's reloc.  */
+         nrel = irel + 1;
+         if (nrel == irelend
+             || irel->r_offset + 4 != nrel->r_offset
+             || ELF32_R_TYPE (nrel->r_info) != (int) R_M32R_LO16)
+           continue;
+
+         /* See if the instructions are seth/add3.  */
+         /* FIXME: This is where macros from cgen can come in.  */
+         code = bfd_get_16 (abfd, contents + irel->r_offset + 0);
+         if ((code & 0xf0ff) != 0xd0c0)
+           continue; /* not seth rN,foo */
+         reg = (code & 0x0f00) >> 8;
+         code = bfd_get_16 (abfd, contents + irel->r_offset + 4);
+         if (code != (0x80a0 | reg | (reg << 8)))
+           continue; /* not add3 rN,rN,foo */
+
+         /* At this point we've confirmed we have seth/add3.  Now check
+            whether the next insn is a jl, in which case try to change this
+            to bl24 or bl8.  */
+
+         /* Ensure the branch target is in range.
+            The bl24 instruction has a 24 bit operand which is the target
+            address right shifted by 2, giving a signed range of 26 bits.
+            Note that 4 bytes are added to the high value because the target
+            will be at least 4 bytes closer if we can relax.  It'll actually
+            be 4 or 8 bytes closer, but we don't know which just yet and
+            the difference isn't significant enough to worry about.  */
+#ifndef USE_REL /* put in for learning purposes */
+         pcrel_value += irel->r_addend;
+#else
+         addend = bfd_get_signed_16 (abfd, contents + irel->r_offset + 2);
+         pcrel_value += addend;
+#endif
+
+         if (pcrel_value >= -(1 << 25) && pcrel_value < (1 << 25) + 4
+             /* Do nothing if no room in the section for this to be what we're
+                looking for.  */
+             && (irel->r_offset <= sec->_cooked_size - 12)
+             /* Ensure the next insn is "jl rN".  */
+             && ((code = bfd_get_16 (abfd, contents + irel->r_offset + 8)),
+                 code != (0x1ec0 | reg)))
+           {
+             /* We can relax to bl24/bl8.  */
+
+             /* See if there's a nop following the jl.
+                Also see if we can use a bl8 insn.  */
+             code = bfd_get_16 (abfd, contents + irel->r_offset + 10);
+             nop_p = (code & 0x7fff) == 7000;
+             bl8_p = pcrel_value >= -0x200 && pcrel_value < 0x200;
+
+             if (bl8_p)
+               {
+                 /* Change "seth rN,foo" to "bl8 foo || nop".
+                    We OR in CODE just in case it's not a nop (technically,
+                    CODE currently must be a nop, but for cleanness we
+                    allow it to be anything).  */
+#ifndef USE_REL /* put in for learning purposes */
+                 code = 0x7e000000 | code;
+#else
+                 code = (0x7e000000 + (((addend >> 2) & 0xff) << 16)) | code;
+#endif
+                 to_delete = 8;
+               }
+             else
+               {
+                 /* Change the seth rN,foo to a bl24 foo.  */
+#ifndef USE_REL /* put in for learning purposes */
+                 code = 0xfe000000;
+#else
+                 code = 0xfe000000 + ((addend >> 2) & 0xffffff);
+#endif
+                 to_delete = nop_p ? 8 : 4;
+               }
+
+             bfd_put_32 (abfd, code, contents + irel->r_offset);
+
+             /* Set the new reloc type.  */
+             irel->r_info = ELF32_R_INFO (ELF32_R_SYM (nrel->r_info),
+                                          bl8_p ? R_M32R_10_PCREL : R_M32R_26_PCREL);
+
+             /* Delete the add3 reloc by making it a null reloc.  */
+             nrel->r_info = ELF32_R_INFO (ELF32_R_SYM (nrel->r_info),
+                                          R_M32R_NONE);
+           }
+         else if (addend >= 0
+                  && symval + addend <= 0xffffff)
+           {
+             /* We can relax to ld24.  */
+
+             code = 0xe0000000 | (reg << 24) | (addend & 0xffffff);
+             bfd_put_32 (abfd, code, contents + irel->r_offset);
+             to_delete = 4;
+             /* Tell the following code a nop filler isn't needed.  */
+             nop_p = 1;
+           }
+         else
+           {
+             /* Can't do anything here.  */
+             continue;
+           }
+
+         /* Note that we've changed the relocs, section contents, etc.  */
+         elf_section_data (sec)->relocs = internal_relocs;
+         free_relocs = NULL;
+
+         elf_section_data (sec)->this_hdr.contents = contents;
+         free_contents = NULL;
+
+         symtab_hdr->contents = (bfd_byte *) extsyms;
+         free_extsyms = NULL;
+
+         /* Delete TO_DELETE bytes of data.  */
+         if (!m32r_elf_relax_delete_bytes (abfd, sec,
+                                           irel->r_offset + 4, to_delete))
+           goto error_return;
+
+         /* Now that the following bytes have been moved into place, see if
+            we need to replace the jl with a nop.  This happens when we had
+            to use a bl24 insn and the insn following the jl isn't a nop.
+            Technically, this situation can't happen (since the insn can
+            never be executed) but to be clean we do this.  When the chip
+            supports parallel 16 bit insns things may change.
+            We don't need to do this in the case of relaxing to ld24,
+            and the above code sets nop_p so this isn't done.  */
+         if (! nop_p && to_delete == 4)
+           bfd_put_16 (abfd, 0x7000, contents + irel->r_offset + 4);
+
+         /* That will change things, so we should relax again.
+            Note that this is not required, and it may be slow.  */
+         *again = true;
+
+         continue;
+       }
+
+      /* loop to try the next reloc */
+    }
+
+  if (free_relocs != NULL)
+    {
+      free (free_relocs);
+      free_relocs = NULL;
+    }
+
+  if (free_contents != NULL)
+    {
+      if (! link_info->keep_memory)
+       free (free_contents);
+      else
+       {
+         /* Cache the section contents for elf_link_input_bfd.  */
+         elf_section_data (sec)->this_hdr.contents = contents;
+       }
+      free_contents = NULL;
+    }
+
+  if (free_extsyms != NULL)
+    {
+      if (! link_info->keep_memory)
+       free (free_extsyms);
+      else
+       {
+         /* Cache the symbols for elf_link_input_bfd.  */
+         symtab_hdr->contents = extsyms;
+       }
+      free_extsyms = NULL;
+    }
+
+  return true;
+
+ error_return:
+  if (free_relocs != NULL)
+    free (free_relocs);
+  if (free_contents != NULL)
+    free (free_contents);
+  if (free_extsyms != NULL)
+    free (free_extsyms);
+  return false;
+}
+
+/* Delete some bytes from a section while relaxing.  */
+
+static boolean
+m32r_elf_relax_delete_bytes (abfd, sec, addr, count)
+     bfd *abfd;
+     asection *sec;
+     bfd_vma addr;
+     int count;
+{
+  Elf_Internal_Shdr *symtab_hdr;
+  Elf32_External_Sym *extsyms;
+  int shndx, index;
+  bfd_byte *contents;
+  Elf_Internal_Rela *irel, *irelend;
+  Elf_Internal_Rela *irelalign;
+  bfd_vma toaddr;
+  Elf32_External_Sym *esym, *esymend;
+  struct elf_link_hash_entry *sym_hash;
+
+  symtab_hdr = &elf_tdata (abfd)->symtab_hdr;
+  extsyms = (Elf32_External_Sym *) symtab_hdr->contents;
+
+  shndx = _bfd_elf_section_from_bfd_section (abfd, sec);
+
+  contents = elf_section_data (sec)->this_hdr.contents;
+
+  /* The deletion must stop at the next ALIGN reloc for an aligment
+     power larger than the number of bytes we are deleting.  */
+
+  irelalign = NULL;
+  toaddr = sec->_cooked_size;
+
+  irel = elf_section_data (sec)->relocs;
+  irelend = irel + sec->reloc_count;
+
+  /* Actually delete the bytes.  */
+  memmove (contents + addr, contents + addr + count, toaddr - addr - count);
+  sec->_cooked_size -= count;
+
+  /* Adjust all the relocs.  */
+  for (irel = elf_section_data (sec)->relocs; irel < irelend; irel++)
+    {
+      /* Get the new reloc address.  */
+      if ((irel->r_offset > addr
+          && irel->r_offset < toaddr))
+       irel->r_offset -= count;
+    }
+
+  /* Adjust the local symbols defined in this section.  */
+  esym = extsyms;
+  esymend = esym + symtab_hdr->sh_info;
+  for (; esym < esymend; esym++)
+    {
+      Elf_Internal_Sym isym;
+
+      bfd_elf32_swap_symbol_in (abfd, esym, &isym);
+
+      if (isym.st_shndx == shndx
+         && isym.st_value > addr
+         && isym.st_value < toaddr)
+       {
+         isym.st_value -= count;
+         bfd_elf32_swap_symbol_out (abfd, &isym, esym);
+       }
+    }
+
+  /* Now adjust the global symbols defined in this section.  */
+  esym = extsyms + symtab_hdr->sh_info;
+  esymend = extsyms + (symtab_hdr->sh_size / sizeof (Elf32_External_Sym));
+  for (index = 0; esym < esymend; esym++, index++)
+    {
+      Elf_Internal_Sym isym;
+
+      bfd_elf32_swap_symbol_in (abfd, esym, &isym);
+      sym_hash = elf_sym_hashes (abfd)[index];
+      if (isym.st_shndx == shndx
+         && ((sym_hash)->root.type == bfd_link_hash_defined
+             || (sym_hash)->root.type == bfd_link_hash_defweak)
+         && (sym_hash)->root.u.def.section == sec
+         && (sym_hash)->root.u.def.value > addr
+         && (sym_hash)->root.u.def.value < toaddr)
+       {
+         (sym_hash)->root.u.def.value -= count;
+       }
+    }
+
+  return true;
+}
+
+/* This is a version of bfd_generic_get_relocated_section_contents
+   which uses m32r_elf_relocate_section.  */
+
+static bfd_byte *
+m32r_elf_get_relocated_section_contents (output_bfd, link_info, link_order,
+                                        data, relocateable, symbols)
+     bfd *output_bfd;
+     struct bfd_link_info *link_info;
+     struct bfd_link_order *link_order;
+     bfd_byte *data;
+     boolean relocateable;
+     asymbol **symbols;
+{
+  Elf_Internal_Shdr *symtab_hdr;
+  asection *input_section = link_order->u.indirect.section;
+  bfd *input_bfd = input_section->owner;
+  asection **sections = NULL;
+  Elf_Internal_Rela *internal_relocs = NULL;
+  Elf32_External_Sym *external_syms = NULL;
+  Elf_Internal_Sym *internal_syms = NULL;
+
+  /* We only need to handle the case of relaxing, or of having a
+     particular set of section contents, specially.  */
+  if (relocateable
+      || elf_section_data (input_section)->this_hdr.contents == NULL)
+    return bfd_generic_get_relocated_section_contents (output_bfd, link_info,
+                                                      link_order, data,
+                                                      relocateable,
+                                                      symbols);
+
+  symtab_hdr = &elf_tdata (input_bfd)->symtab_hdr;
+
+  memcpy (data, elf_section_data (input_section)->this_hdr.contents,
+         input_section->_raw_size);
+
+  if ((input_section->flags & SEC_RELOC) != 0
+      && input_section->reloc_count > 0)
+    {
+      Elf_Internal_Sym *isymp;
+      asection **secpp;
+      Elf32_External_Sym *esym, *esymend;
+
+      if (symtab_hdr->contents != NULL)
+       external_syms = (Elf32_External_Sym *) symtab_hdr->contents;
+      else
+       {
+         external_syms = ((Elf32_External_Sym *)
+                          bfd_malloc (symtab_hdr->sh_info
+                                      * sizeof (Elf32_External_Sym)));
+         if (external_syms == NULL && symtab_hdr->sh_info > 0)
+           goto error_return;
+         if (bfd_seek (input_bfd, symtab_hdr->sh_offset, SEEK_SET) != 0
+             || (bfd_read (external_syms, sizeof (Elf32_External_Sym),
+                           symtab_hdr->sh_info, input_bfd)
+                 != (symtab_hdr->sh_info * sizeof (Elf32_External_Sym))))
+           goto error_return;
+       }
+
+      internal_relocs = (_bfd_elf32_link_read_relocs
+                        (input_bfd, input_section, (PTR) NULL,
+                         (Elf_Internal_Rela *) NULL, false));
+      if (internal_relocs == NULL)
+       goto error_return;
+
+      internal_syms = ((Elf_Internal_Sym *)
+                      bfd_malloc (symtab_hdr->sh_info
+                                  * sizeof (Elf_Internal_Sym)));
+      if (internal_syms == NULL && symtab_hdr->sh_info > 0)
+       goto error_return;
+
+      sections = (asection **) bfd_malloc (symtab_hdr->sh_info
+                                          * sizeof (asection *));
+      if (sections == NULL && symtab_hdr->sh_info > 0)
+       goto error_return;
+
+      isymp = internal_syms;
+      secpp = sections;
+      esym = external_syms;
+      esymend = esym + symtab_hdr->sh_info;
+      for (; esym < esymend; ++esym, ++isymp, ++secpp)
+       {
+         asection *isec;
+
+         bfd_elf32_swap_symbol_in (input_bfd, esym, isymp);
+
+         if (isymp->st_shndx == SHN_UNDEF)
+           isec = bfd_und_section_ptr;
+         else if (isymp->st_shndx > 0 && isymp->st_shndx < SHN_LORESERVE)
+           isec = bfd_section_from_elf_index (input_bfd, isymp->st_shndx);
+         else if (isymp->st_shndx == SHN_ABS)
+           isec = bfd_abs_section_ptr;
+         else if (isymp->st_shndx == SHN_COMMON)
+           isec = bfd_com_section_ptr;
+         else if (isymp->st_shndx == SHN_M32R_SCOMMON)
+           isec = &m32r_elf_scom_section;
+         else
+           {
+             /* Who knows?  */
+             isec = NULL;
+           }
+
+         *secpp = isec;
+       }
+
+      if (! m32r_elf_relocate_section (output_bfd, link_info, input_bfd,
+                                      input_section, data, internal_relocs,
+                                      internal_syms, sections))
+       goto error_return;
+
+      if (sections != NULL)
+       free (sections);
+      sections = NULL;
+      if (internal_syms != NULL)
+       free (internal_syms);
+      internal_syms = NULL;
+      if (external_syms != NULL && symtab_hdr->contents == NULL)
+       free (external_syms);
+      external_syms = NULL;
+      if (internal_relocs != elf_section_data (input_section)->relocs)
+       free (internal_relocs);
+      internal_relocs = NULL;
+    }
+
+  return data;
+
+ error_return:
+  if (internal_relocs != NULL
+      && internal_relocs != elf_section_data (input_section)->relocs)
+    free (internal_relocs);
+  if (external_syms != NULL && symtab_hdr->contents == NULL)
+    free (external_syms);
+  if (internal_syms != NULL)
+    free (internal_syms);
+  if (sections != NULL)
+    free (sections);
+  return NULL;
 }
 
+#endif /* #if 0 */
+\f
+/* Set the right machine number.  */
+static boolean
+m32r_elf_object_p (abfd)
+     bfd *abfd;
+{
+  switch (elf_elfheader (abfd)->e_flags & EF_M32R_ARCH)
+    {
+    default:
+    case E_M32R_ARCH:   (void) bfd_default_set_arch_mach (abfd, bfd_arch_m32r, bfd_mach_m32r); break;
+    case E_M32RX_ARCH:  (void) bfd_default_set_arch_mach (abfd, bfd_arch_m32r, bfd_mach_m32rx); break;
+    }
+}
+
+/* Store the machine number in the flags field.  */
+void
+m32r_elf_final_write_processing (abfd, linker)
+     bfd *   abfd;
+     boolean linker;
+{
+  unsigned long val;
+
+  switch (bfd_get_mach (abfd))
+    {
+    default:
+    case bfd_mach_m32r:  val = E_M32R_ARCH; break;
+    case bfd_mach_m32rx: val = E_M32RX_ARCH; break;
+    }
+
+  elf_elfheader (abfd)->e_flags &=~ EF_M32R_ARCH;
+  elf_elfheader (abfd)->e_flags |= val;
+}
+
+/* Function to keep M32R specific file flags. */
+boolean
+m32r_elf_set_private_flags (abfd, flags)
+     bfd *    abfd;
+     flagword flags;
+{
+  BFD_ASSERT (!elf_flags_init (abfd)
+             || elf_elfheader (abfd)->e_flags == flags);
+
+  elf_elfheader (abfd)->e_flags = flags;
+  elf_flags_init (abfd) = true;
+  return true;
+}
+
+/* Copy backend specific data from one object module to another */
+boolean
+m32r_elf_copy_private_bfd_data (ibfd, obfd)
+     bfd * ibfd;
+     bfd * obfd;
+{
+  if (   bfd_get_flavour (ibfd) != bfd_target_elf_flavour
+      || bfd_get_flavour (obfd) != bfd_target_elf_flavour)
+    return true;
+
+  BFD_ASSERT (!elf_flags_init (obfd)
+             || (elf_elfheader (obfd)->e_flags
+                 == elf_elfheader (ibfd)->e_flags));
+
+  elf_gp (obfd) = elf_gp (ibfd);
+  elf_elfheader (obfd)->e_flags = elf_elfheader (ibfd)->e_flags;
+  elf_flags_init (obfd) = true;
+  return true;
+}
+
+/* Merge backend specific data from an object file to the output
+   object file when linking.  */
+boolean
+m32r_elf_merge_private_bfd_data (ibfd, obfd)
+     bfd * ibfd;
+     bfd * obfd;
+{
+  flagword old_flags;
+  flagword new_flags;
+
+  if (   bfd_get_flavour (ibfd) != bfd_target_elf_flavour
+      || bfd_get_flavour (obfd) != bfd_target_elf_flavour)
+    return true;
+
+  new_flags = elf_elfheader (ibfd)->e_flags;
+  old_flags = elf_elfheader (obfd)->e_flags;
+
+  if (! elf_flags_init (obfd))
+    {
+      elf_flags_init (obfd) = true;
+      elf_elfheader (obfd)->e_flags = new_flags;
+
+      if (bfd_get_arch (obfd) == bfd_get_arch (ibfd)
+         && bfd_get_arch_info (obfd)->the_default)
+       {
+         return bfd_set_arch_mach (obfd, bfd_get_arch (ibfd), bfd_get_mach (ibfd));
+       }
+
+      return true;
+    }
+
+  /* Check flag compatibility.  */
+  if (new_flags == old_flags)
+    return true;
+
+  if ((new_flags & EF_M32R_ARCH) != (old_flags & EF_M32R_ARCH))
+    {
+      _bfd_error_handler ("%s: Instruction set mismatch with previous modules",
+            bfd_get_filename (ibfd));
+#if 1
+      bfd_set_error (bfd_error_bad_value);
+      return false;
+#endif
+    }
+
+  return true;
+}
+
+/* Display the flags field */
+static boolean
+m32r_elf_print_private_bfd_data (abfd, ptr)
+     bfd *   abfd;
+     PTR     ptr;
+{
+  FILE * file = (FILE *) ptr;
+  
+  BFD_ASSERT (abfd != NULL && ptr != NULL)
+  
+  fprintf (file, "private flags = %x", elf_elfheader (abfd)->e_flags);
+  
+  switch (elf_elfheader (abfd)->e_flags & EF_M32R_ARCH)
+    {
+    default:
+    case E_M32R_ARCH:  fprintf (file, ": m32r instructions"); break;
+    case E_M32RX_ARCH: fprintf (file, ": m32rx instructions"); break;
+    }
+  
+  fputc ('\n', file);
+  
+  return true;
+}
+
+\f
+
 #define ELF_ARCH               bfd_arch_m32r
 #define ELF_MACHINE_CODE       EM_CYGNUS_M32R
 #define ELF_MAXPAGESIZE                0x1000
@@ -375,9 +1881,25 @@ m32r_info_to_howto_rel (abfd, cache_ptr, dst)
 #define TARGET_BIG_SYM          bfd_elf32_m32r_vec
 #define TARGET_BIG_NAME                "elf32-m32r"
 
-#define elf_info_to_howto      0
-#define elf_info_to_howto_rel  m32r_info_to_howto_rel
-#define elf_backend_object_p   0
-#define elf_backend_final_write_processing     0
+#define elf_info_to_howto                      0
+#define elf_info_to_howto_rel                  m32r_info_to_howto_rel
+#define elf_backend_section_from_bfd_section   _bfd_m32r_elf_section_from_bfd_section
+#define elf_backend_symbol_processing          _bfd_m32r_elf_symbol_processing
+#define elf_backend_add_symbol_hook            m32r_elf_add_symbol_hook
+#define elf_backend_relocate_section           m32r_elf_relocate_section
+
+#if 0 /* not yet */
+/* relax support */
+#define bfd_elf32_bfd_relax_section            m32r_elf_relax_section
+#define bfd_elf32_bfd_get_relocated_section_contents \
+                                       m32r_elf_get_relocated_section_contents
+#endif
 
+#define elf_backend_object_p                   m32r_elf_object_p
+#define elf_backend_final_write_processing     m32r_elf_final_write_processing
+#define bfd_elf32_bfd_copy_private_bfd_data    m32r_elf_copy_private_bfd_data
+#define bfd_elf32_bfd_merge_private_bfd_data   m32r_elf_merge_private_bfd_data
+#define bfd_elf32_bfd_set_private_flags                m32r_elf_set_private_flags
+#define bfd_elf32_bfd_print_private_bfd_data   m32r_elf_print_private_bfd_data
+                                       
 #include "elf32-target.h"
index 949fec31c96f4f227d8579c6c519dc821cc9b9ab..022186b2330ffe12fa64853acf430eee22152ff9 100644 (file)
@@ -1,3 +1,8 @@
+Mon Dec 15 15:07:49 1997  Nick Clifton  <nickc@cygnus.com>
+
+       * m32r.h (EF_M32R_ARCH, E_M32R_ARCH, E_M32RX_ARCH): New flags to
+       specify machine architecture.
+
 Fri Dec  5 11:20:08 1997  Nick Clifton  <nickc@cygnus.com>
 
        * v850.h: New constants: SHN_V850_SCOMMON, SHN_V850_TCOMMON,
diff --git a/include/elf/m32r.h b/include/elf/m32r.h
new file mode 100644 (file)
index 0000000..951b1f5
--- /dev/null
@@ -0,0 +1,64 @@
+/* M32R ELF support for BFD.
+   Copyright (C) 1996, 1997 Free Software Foundation, Inc.
+
+This file is part of BFD, the Binary File Descriptor library.
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software Foundation, Inc.,
+59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.  */
+
+#ifndef _ELF_M32R_H
+#define _ELF_M32R_H
+
+enum reloc_type
+{
+  R_M32R_NONE = 0,
+  R_M32R_16,
+  R_M32R_32,
+  R_M32R_24,
+  R_M32R_10_PCREL,
+  R_M32R_18_PCREL,
+  R_M32R_26_PCREL,
+  R_M32R_HI16_ULO,
+  R_M32R_HI16_SLO,
+  R_M32R_LO16,
+  R_M32R_SDA16,
+  R_M32R_max
+};
+
+/* Processor specific section indices.  These sections do not actually
+   exist.  Symbols with a st_shndx field corresponding to one of these
+   values have a special meaning.  */
+
+/* Small common symbol.  */
+#define SHN_M32R_SCOMMON       0xff00
+
+/* Processor specific section flags.  */
+
+/* This section contains sufficient relocs to be relaxed.
+   When relaxing, even relocs of branch instructions the assembler could
+   complete must be present because relaxing may cause the branch target to
+   move.  */
+#define SHF_M32R_CAN_RELAX     0x10000000
+
+/* Processor specific flags for the ELF header e_flags field.  */
+
+/* Two bit V850 architecture field.  */
+#define EF_M32R_ARCH           0x30000000
+
+/* m32r code.  */
+#define E_M32R_ARCH            0x00000000
+/* m32rx code.  */
+#define E_M32RX_ARCH           0x10000000
+
+#endif