daily update
[deliverable/binutils-gdb.git] / bfd / elf-m10300.c
index 4849ffd205c5fd1ec7fa529d5f6a04f308247efa..d5e183df21a3f5c4896d2283e2198a8bb1f87725 100644 (file)
@@ -1,6 +1,6 @@
 /* Matsushita 10300 specific support for 32-bit ELF
    Copyright 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005,
-   2006, 2007 Free Software Foundation, Inc.
+   2006, 2007, 2008, 2009, 2010, 2011 Free Software Foundation, Inc.
 
    This file is part of BFD, the Binary File Descriptor library.
 
 #include "libbfd.h"
 #include "elf-bfd.h"
 #include "elf/mn10300.h"
-
-static bfd_reloc_status_type mn10300_elf_final_link_relocate
-  PARAMS ((reloc_howto_type *, bfd *, bfd *, asection *, bfd_byte *,
-          bfd_vma, bfd_vma, bfd_vma,
-          struct elf_link_hash_entry *, unsigned long, struct bfd_link_info *,
-          asection *, int));
-static bfd_boolean mn10300_elf_relocate_section
-  PARAMS ((bfd *, struct bfd_link_info *, bfd *, asection *, bfd_byte *,
-          Elf_Internal_Rela *, Elf_Internal_Sym *, asection **));
-static bfd_boolean mn10300_elf_relax_section
-  PARAMS ((bfd *, asection *, struct bfd_link_info *, bfd_boolean *));
-static bfd_byte * mn10300_elf_get_relocated_section_contents
-  PARAMS ((bfd *, struct bfd_link_info *, struct bfd_link_order *,
-          bfd_byte *, bfd_boolean, asymbol **));
-static unsigned long elf_mn10300_mach
-  PARAMS ((flagword));
-void _bfd_mn10300_elf_final_write_processing
-  PARAMS ((bfd *, bfd_boolean));
-bfd_boolean _bfd_mn10300_elf_object_p
-  PARAMS ((bfd *));
-bfd_boolean _bfd_mn10300_elf_merge_private_bfd_data
-  PARAMS ((bfd *,bfd *));
+#include "libiberty.h"
 
 /* The mn10300 linker needs to keep track of the number of relocs that
    it decides to copy in check_relocs for each symbol.  This is so
@@ -53,7 +32,8 @@ bfd_boolean _bfd_mn10300_elf_merge_private_bfd_data
    linking with -Bsymbolic.  We store the information in a field
    extending the regular ELF linker hash table.  */
 
-struct elf32_mn10300_link_hash_entry {
+struct elf32_mn10300_link_hash_entry
+{
   /* The basic elf link hash table entry.  */
   struct elf_link_hash_entry root;
 
@@ -89,12 +69,21 @@ struct elf32_mn10300_link_hash_entry {
 
   /* Calculated value.  */
   bfd_vma value;
+
+#define GOT_UNKNOWN    0
+#define GOT_NORMAL     1
+#define GOT_TLS_GD     2
+#define GOT_TLS_LD     3
+#define GOT_TLS_IE     4
+  /* Used to distinguish GOT entries for TLS types from normal GOT entries.  */
+  unsigned char tls_type;
 };
 
 /* We derive a hash table from the main elf linker hash table so
    we can store state variables and a secondary hash table without
    resorting to global variables.  */
-struct elf32_mn10300_link_hash_table {
+struct elf32_mn10300_link_hash_table
+{
   /* The main hash table.  */
   struct elf_link_hash_table root;
 
@@ -106,60 +95,51 @@ struct elf32_mn10300_link_hash_table {
   /* Random linker state flags.  */
 #define MN10300_HASH_ENTRIES_INITIALIZED 0x1
   char flags;
+  struct
+  {
+    bfd_signed_vma  refcount;
+    bfd_vma         offset;
+    char            got_allocated;
+    char            rel_emitted;
+  } tls_ldm_got;
+};
+
+#define elf_mn10300_hash_entry(ent) ((struct elf32_mn10300_link_hash_entry *)(ent))
+
+struct elf_mn10300_obj_tdata
+{
+  struct elf_obj_tdata root;
+
+  /* tls_type for each local got entry.  */
+  char * local_got_tls_type;
 };
 
+#define elf_mn10300_tdata(abfd) \
+  ((struct elf_mn10300_obj_tdata *) (abfd)->tdata.any)
+
+#define elf_mn10300_local_got_tls_type(abfd) \
+  (elf_mn10300_tdata (abfd)->local_got_tls_type)
+
+#ifndef streq
+#define streq(a, b) (strcmp ((a),(b)) == 0)
+#endif
+
 /* For MN10300 linker hash table.  */
 
 /* Get the MN10300 ELF linker hash table from a link_info structure.  */
 
 #define elf32_mn10300_hash_table(p) \
-  ((struct elf32_mn10300_link_hash_table *) ((p)->hash))
+  (elf_hash_table_id ((struct elf_link_hash_table *) ((p)->hash)) \
+  == MN10300_ELF_DATA ? ((struct elf32_mn10300_link_hash_table *) ((p)->hash)) : NULL)
 
 #define elf32_mn10300_link_hash_traverse(table, func, info)            \
   (elf_link_hash_traverse                                              \
    (&(table)->root,                                                    \
-    (bfd_boolean (*) PARAMS ((struct elf_link_hash_entry *, PTR))) (func), \
+    (bfd_boolean (*) (struct elf_link_hash_entry *, void *)) (func),   \
     (info)))
 
-static struct bfd_hash_entry *elf32_mn10300_link_hash_newfunc
-  PARAMS ((struct bfd_hash_entry *, struct bfd_hash_table *, const char *));
-static struct bfd_link_hash_table *elf32_mn10300_link_hash_table_create
-  PARAMS ((bfd *));
-static void elf32_mn10300_link_hash_table_free
-  PARAMS ((struct bfd_link_hash_table *));
-
-static reloc_howto_type *bfd_elf32_bfd_reloc_type_lookup
-  PARAMS ((bfd *abfd, bfd_reloc_code_real_type code));
-static void mn10300_info_to_howto
-  PARAMS ((bfd *, arelent *, Elf_Internal_Rela *));
-static bfd_boolean mn10300_elf_check_relocs
-  PARAMS ((bfd *, struct bfd_link_info *, asection *,
-          const Elf_Internal_Rela *));
-static bfd_boolean mn10300_elf_relax_delete_bytes
-  PARAMS ((bfd *, asection *, bfd_vma, int));
-static bfd_boolean mn10300_elf_symbol_address_p
-  PARAMS ((bfd *, asection *, Elf_Internal_Sym *, bfd_vma));
-static bfd_boolean elf32_mn10300_finish_hash_table_entry
-  PARAMS ((struct bfd_hash_entry *, PTR));
-static void compute_function_info
-  PARAMS ((bfd *, struct elf32_mn10300_link_hash_entry *,
-          bfd_vma, unsigned char *));
-
-static bfd_boolean _bfd_mn10300_elf_create_got_section
-  PARAMS ((bfd *, struct bfd_link_info *));
-static bfd_boolean _bfd_mn10300_elf_create_dynamic_sections
-  PARAMS ((bfd *, struct bfd_link_info *));
-static bfd_boolean _bfd_mn10300_elf_adjust_dynamic_symbol
-  PARAMS ((struct bfd_link_info *, struct elf_link_hash_entry *));
-static bfd_boolean _bfd_mn10300_elf_size_dynamic_sections
-  PARAMS ((bfd *, struct bfd_link_info *));
-static bfd_boolean _bfd_mn10300_elf_finish_dynamic_symbol
-  PARAMS ((bfd *, struct bfd_link_info *, struct elf_link_hash_entry *,
-          Elf_Internal_Sym *));
-static bfd_boolean _bfd_mn10300_elf_finish_dynamic_sections
-  PARAMS ((bfd *, struct bfd_link_info *));
-
-static reloc_howto_type elf_mn10300_howto_table[] = {
+static reloc_howto_type elf_mn10300_howto_table[] =
+{
   /* Dummy relocation.  Does nothing.  */
   HOWTO (R_MN10300_NONE,
         0,
@@ -259,7 +239,7 @@ static reloc_howto_type elf_mn10300_howto_table[] = {
         0xff,
         TRUE),
 
-  /* GNU extension to record C++ vtable hierarchy */
+  /* GNU extension to record C++ vtable hierarchy */
   HOWTO (R_MN10300_GNU_VTINHERIT, /* type */
         0,                     /* rightshift */
         0,                     /* size (0 = byte, 1 = short, 2 = long) */
@@ -499,14 +479,169 @@ static reloc_howto_type elf_mn10300_howto_table[] = {
         0xffffffff,            /* dst_mask */
         FALSE),                /* pcrel_offset */
 
+  HOWTO (R_MN10300_TLS_GD,     /* type */
+        0,                     /* rightshift */
+        2,                     /* size (0 = byte, 1 = short, 2 = long) */
+        32,                    /* bitsize */
+        FALSE,                 /* pc_relative */
+        0,                     /* bitpos */
+        complain_overflow_bitfield, /* complain_on_overflow */
+        bfd_elf_generic_reloc, /* */
+        "R_MN10300_TLS_GD",    /* name */
+        FALSE,                 /* partial_inplace */
+        0xffffffff,            /* src_mask */
+        0xffffffff,            /* dst_mask */
+        FALSE),                /* pcrel_offset */
+
+  HOWTO (R_MN10300_TLS_LD,     /* type */
+        0,                     /* rightshift */
+        2,                     /* size (0 = byte, 1 = short, 2 = long) */
+        32,                    /* bitsize */
+        FALSE,                 /* pc_relative */
+        0,                     /* bitpos */
+        complain_overflow_bitfield, /* complain_on_overflow */
+        bfd_elf_generic_reloc, /* */
+        "R_MN10300_TLS_LD",    /* name */
+        FALSE,                 /* partial_inplace */
+        0xffffffff,            /* src_mask */
+        0xffffffff,            /* dst_mask */
+        FALSE),                /* pcrel_offset */
+
+  HOWTO (R_MN10300_TLS_LDO,    /* type */
+        0,                     /* rightshift */
+        2,                     /* size (0 = byte, 1 = short, 2 = long) */
+        32,                    /* bitsize */
+        FALSE,                 /* pc_relative */
+        0,                     /* bitpos */
+        complain_overflow_bitfield, /* complain_on_overflow */
+        bfd_elf_generic_reloc, /* */
+        "R_MN10300_TLS_LDO",   /* name */
+        FALSE,                 /* partial_inplace */
+        0xffffffff,            /* src_mask */
+        0xffffffff,            /* dst_mask */
+        FALSE),                /* pcrel_offset */
+
+  HOWTO (R_MN10300_TLS_GOTIE,  /* type */
+        0,                     /* rightshift */
+        2,                     /* size (0 = byte, 1 = short, 2 = long) */
+        32,                    /* bitsize */
+        FALSE,                 /* pc_relative */
+        0,                     /* bitpos */
+        complain_overflow_bitfield, /* complain_on_overflow */
+        bfd_elf_generic_reloc, /* */
+        "R_MN10300_TLS_GOTIE", /* name */
+        FALSE,                 /* partial_inplace */
+        0xffffffff,            /* src_mask */
+        0xffffffff,            /* dst_mask */
+        FALSE),                /* pcrel_offset */
+
+  HOWTO (R_MN10300_TLS_IE,     /* type */
+        0,                     /* rightshift */
+        2,                     /* size (0 = byte, 1 = short, 2 = long) */
+        32,                    /* bitsize */
+        FALSE,                 /* pc_relative */
+        0,                     /* bitpos */
+        complain_overflow_bitfield, /* complain_on_overflow */
+        bfd_elf_generic_reloc, /* */
+        "R_MN10300_TLS_IE",    /* name */
+        FALSE,                 /* partial_inplace */
+        0xffffffff,            /* src_mask */
+        0xffffffff,            /* dst_mask */
+        FALSE),                /* pcrel_offset */
+
+  HOWTO (R_MN10300_TLS_LE,     /* type */
+        0,                     /* rightshift */
+        2,                     /* size (0 = byte, 1 = short, 2 = long) */
+        32,                    /* bitsize */
+        FALSE,                 /* pc_relative */
+        0,                     /* bitpos */
+        complain_overflow_bitfield, /* complain_on_overflow */
+        bfd_elf_generic_reloc, /* */
+        "R_MN10300_TLS_LE",    /* name */
+        FALSE,                 /* partial_inplace */
+        0xffffffff,            /* src_mask */
+        0xffffffff,            /* dst_mask */
+        FALSE),                /* pcrel_offset */
+
+  HOWTO (R_MN10300_TLS_DTPMOD, /* type */
+        0,                     /* rightshift */
+        2,                     /* size (0 = byte, 1 = short, 2 = long) */
+        32,                    /* bitsize */
+        FALSE,                 /* pc_relative */
+        0,                     /* bitpos */
+        complain_overflow_bitfield, /* complain_on_overflow */
+        bfd_elf_generic_reloc, /* */
+        "R_MN10300_TLS_DTPMOD",        /* name */
+        FALSE,                 /* partial_inplace */
+        0xffffffff,            /* src_mask */
+        0xffffffff,            /* dst_mask */
+        FALSE),                /* pcrel_offset */
+
+  HOWTO (R_MN10300_TLS_DTPOFF, /* type */
+        0,                     /* rightshift */
+        2,                     /* size (0 = byte, 1 = short, 2 = long) */
+        32,                    /* bitsize */
+        FALSE,                 /* pc_relative */
+        0,                     /* bitpos */
+        complain_overflow_bitfield, /* complain_on_overflow */
+        bfd_elf_generic_reloc, /* */
+        "R_MN10300_TLS_DTPOFF",        /* name */
+        FALSE,                 /* partial_inplace */
+        0xffffffff,            /* src_mask */
+        0xffffffff,            /* dst_mask */
+        FALSE),                /* pcrel_offset */
+
+  HOWTO (R_MN10300_TLS_TPOFF,  /* type */
+        0,                     /* rightshift */
+        2,                     /* size (0 = byte, 1 = short, 2 = long) */
+        32,                    /* bitsize */
+        FALSE,                 /* pc_relative */
+        0,                     /* bitpos */
+        complain_overflow_bitfield, /* complain_on_overflow */
+        bfd_elf_generic_reloc, /* */
+        "R_MN10300_TLS_TPOFF", /* name */
+        FALSE,                 /* partial_inplace */
+        0xffffffff,            /* src_mask */
+        0xffffffff,            /* dst_mask */
+        FALSE),                /* pcrel_offset */
+  
+  HOWTO (R_MN10300_SYM_DIFF,   /* type */
+        0,                     /* rightshift */
+        2,                     /* size (0 = byte, 1 = short, 2 = long) */
+        32,                    /* bitsize */
+        FALSE,                 /* pc_relative */
+        0,                     /* bitpos */
+        complain_overflow_dont,/* complain_on_overflow */
+        NULL,                  /* special handler.  */
+        "R_MN10300_SYM_DIFF",  /* name */
+        FALSE,                 /* partial_inplace */
+        0xffffffff,            /* src_mask */
+        0xffffffff,            /* dst_mask */
+        FALSE),                /* pcrel_offset */
+
+  HOWTO (R_MN10300_ALIGN,      /* type */
+        0,                     /* rightshift */
+        0,                     /* size (0 = byte, 1 = short, 2 = long) */
+        32,                    /* bitsize */
+        FALSE,                 /* pc_relative */
+        0,                     /* bitpos */
+        complain_overflow_dont,/* complain_on_overflow */
+        NULL,                  /* special handler.  */
+        "R_MN10300_ALIGN",     /* name */
+        FALSE,                 /* partial_inplace */
+        0,                     /* src_mask */
+        0,                     /* dst_mask */
+        FALSE)                 /* pcrel_offset */
 };
 
-struct mn10300_reloc_map {
+struct mn10300_reloc_map
+{
   bfd_reloc_code_real_type bfd_reloc_val;
   unsigned char elf_reloc_val;
 };
 
-static const struct mn10300_reloc_map mn10300_reloc_map[] = {
+static const struct mn10300_reloc_map mn10300_reloc_map[] =
+{
   { BFD_RELOC_NONE, R_MN10300_NONE, },
   { BFD_RELOC_32, R_MN10300_32, },
   { BFD_RELOC_16, R_MN10300_16, },
@@ -531,14 +666,24 @@ static const struct mn10300_reloc_map mn10300_reloc_map[] = {
   { BFD_RELOC_MN10300_GLOB_DAT, R_MN10300_GLOB_DAT },
   { BFD_RELOC_MN10300_JMP_SLOT, R_MN10300_JMP_SLOT },
   { BFD_RELOC_MN10300_RELATIVE, R_MN10300_RELATIVE },
+  { BFD_RELOC_MN10300_TLS_GD, R_MN10300_TLS_GD },
+  { BFD_RELOC_MN10300_TLS_LD, R_MN10300_TLS_LD },
+  { BFD_RELOC_MN10300_TLS_LDO, R_MN10300_TLS_LDO },
+  { BFD_RELOC_MN10300_TLS_GOTIE, R_MN10300_TLS_GOTIE },
+  { BFD_RELOC_MN10300_TLS_IE, R_MN10300_TLS_IE },
+  { BFD_RELOC_MN10300_TLS_LE, R_MN10300_TLS_LE },
+  { BFD_RELOC_MN10300_TLS_DTPMOD, R_MN10300_TLS_DTPMOD },
+  { BFD_RELOC_MN10300_TLS_DTPOFF, R_MN10300_TLS_DTPOFF },
+  { BFD_RELOC_MN10300_TLS_TPOFF, R_MN10300_TLS_TPOFF },
+  { BFD_RELOC_MN10300_SYM_DIFF, R_MN10300_SYM_DIFF },
+  { BFD_RELOC_MN10300_ALIGN, R_MN10300_ALIGN }
 };
 
 /* Create the GOT section.  */
 
 static bfd_boolean
-_bfd_mn10300_elf_create_got_section (abfd, info)
-     bfd * abfd;
-     struct bfd_link_info * info;
+_bfd_mn10300_elf_create_got_section (bfd * abfd,
+                                    struct bfd_link_info * info)
 {
   flagword   flags;
   flagword   pltflags;
@@ -621,19 +766,14 @@ _bfd_mn10300_elf_create_got_section (abfd, info)
 }
 
 static reloc_howto_type *
-bfd_elf32_bfd_reloc_type_lookup (abfd, code)
-     bfd *abfd ATTRIBUTE_UNUSED;
-     bfd_reloc_code_real_type code;
+bfd_elf32_bfd_reloc_type_lookup (bfd *abfd ATTRIBUTE_UNUSED,
+                                bfd_reloc_code_real_type code)
 {
   unsigned int i;
 
-  for (i = 0;
-       i < sizeof (mn10300_reloc_map) / sizeof (struct mn10300_reloc_map);
-       i++)
-    {
-      if (mn10300_reloc_map[i].bfd_reloc_val == code)
-       return &elf_mn10300_howto_table[mn10300_reloc_map[i].elf_reloc_val];
-    }
+  for (i = ARRAY_SIZE (mn10300_reloc_map); i--;)
+    if (mn10300_reloc_map[i].bfd_reloc_val == code)
+      return &elf_mn10300_howto_table[mn10300_reloc_map[i].elf_reloc_val];
 
   return NULL;
 }
@@ -644,13 +784,10 @@ bfd_elf32_bfd_reloc_name_lookup (bfd *abfd ATTRIBUTE_UNUSED,
 {
   unsigned int i;
 
-  for (i = 0;
-       i < (sizeof (elf_mn10300_howto_table)
-           / sizeof (elf_mn10300_howto_table[0]));
-       i++)
+  for (i = ARRAY_SIZE (elf_mn10300_howto_table); i--;)
     if (elf_mn10300_howto_table[i].name != NULL
        && strcasecmp (elf_mn10300_howto_table[i].name, r_name) == 0)
-      return &elf_mn10300_howto_table[i];
+      return elf_mn10300_howto_table + i;
 
   return NULL;
 }
@@ -658,16 +795,232 @@ bfd_elf32_bfd_reloc_name_lookup (bfd *abfd ATTRIBUTE_UNUSED,
 /* Set the howto pointer for an MN10300 ELF reloc.  */
 
 static void
-mn10300_info_to_howto (abfd, cache_ptr, dst)
-     bfd *abfd ATTRIBUTE_UNUSED;
-     arelent *cache_ptr;
-     Elf_Internal_Rela *dst;
+mn10300_info_to_howto (bfd *abfd ATTRIBUTE_UNUSED,
+                      arelent *cache_ptr,
+                      Elf_Internal_Rela *dst)
 {
   unsigned int r_type;
 
   r_type = ELF32_R_TYPE (dst->r_info);
   BFD_ASSERT (r_type < (unsigned int) R_MN10300_MAX);
-  cache_ptr->howto = &elf_mn10300_howto_table[r_type];
+  cache_ptr->howto = elf_mn10300_howto_table + r_type;
+}
+
+static int
+elf_mn10300_tls_transition (struct bfd_link_info *        info,
+                           int                           r_type,
+                           struct elf_link_hash_entry *  h,
+                           asection *                    sec,
+                           bfd_boolean                   counting)
+{
+  bfd_boolean is_local;
+
+  if (r_type == R_MN10300_TLS_GD
+      && h != NULL
+      && elf_mn10300_hash_entry (h)->tls_type == GOT_TLS_IE)
+    return R_MN10300_TLS_GOTIE;
+
+  if (info->shared)
+    return r_type;
+
+  if (! (sec->flags & SEC_CODE))
+    return r_type;
+
+  if (! counting && h != NULL && ! elf_hash_table (info)->dynamic_sections_created)
+    is_local = TRUE;
+  else
+    is_local = SYMBOL_CALLS_LOCAL (info, h);
+
+  /* For the main program, these are the transitions we do.  */
+  switch (r_type)
+    {
+    case R_MN10300_TLS_GD: return is_local ? R_MN10300_TLS_LE : R_MN10300_TLS_GOTIE;
+    case R_MN10300_TLS_LD: return R_MN10300_NONE;
+    case R_MN10300_TLS_LDO: return R_MN10300_TLS_LE;
+    case R_MN10300_TLS_IE:
+    case R_MN10300_TLS_GOTIE: return is_local ? R_MN10300_TLS_LE : r_type;
+    }
+
+  return r_type;
+}
+
+/* Return the relocation value for @tpoff relocation
+   if STT_TLS virtual address is ADDRESS.  */
+
+static bfd_vma
+dtpoff (struct bfd_link_info * info, bfd_vma address)
+{
+  struct elf_link_hash_table *htab = elf_hash_table (info);
+
+  /* If tls_sec is NULL, we should have signalled an error already.  */
+  if (htab->tls_sec == NULL)
+    return 0;
+  return address - htab->tls_sec->vma;
+}
+
+/* Return the relocation value for @tpoff relocation
+   if STT_TLS virtual address is ADDRESS.  */
+
+static bfd_vma
+tpoff (struct bfd_link_info * info, bfd_vma address)
+{
+  struct elf_link_hash_table *htab = elf_hash_table (info);
+
+  /* If tls_sec is NULL, we should have signalled an error already.  */
+  if (htab->tls_sec == NULL)
+    return 0;
+  return address - (htab->tls_size + htab->tls_sec->vma);
+}
+
+/* Returns nonzero if there's a R_MN10300_PLT32 reloc that we now need
+   to skip, after this one.  The actual value is the offset between
+   this reloc and the PLT reloc.  */
+
+static int
+mn10300_do_tls_transition (bfd *         input_bfd,
+                          unsigned int  r_type,
+                          unsigned int  tls_r_type,
+                          bfd_byte *    contents,
+                          bfd_vma       offset)
+{
+  bfd_byte *op = contents + offset;
+  int gotreg = 0;
+
+#define TLS_PAIR(r1,r2) ((r1) * R_MN10300_MAX + (r2))
+
+  /* This is common to all GD/LD transitions, so break it out.  */
+  if (r_type == R_MN10300_TLS_GD
+      || r_type == R_MN10300_TLS_LD)
+    {
+      op -= 2;
+      /* mov imm,d0.  */
+      BFD_ASSERT (bfd_get_8 (input_bfd, op) == 0xFC);
+      BFD_ASSERT (bfd_get_8 (input_bfd, op + 1) == 0xCC);
+      /* add aN,d0.  */
+      BFD_ASSERT (bfd_get_8 (input_bfd, op + 6) == 0xF1);
+      gotreg = (bfd_get_8 (input_bfd, op + 7) & 0x0c) >> 2;
+      /* Call.  */
+      BFD_ASSERT (bfd_get_8 (input_bfd, op + 8) == 0xDD);
+    }
+
+  switch (TLS_PAIR (r_type, tls_r_type))
+    {
+    case TLS_PAIR (R_MN10300_TLS_GD, R_MN10300_TLS_GOTIE):
+      {
+       /* Keep track of which register we put GOTptr in.  */
+       /* mov (_x@indntpoff,a2),a0.  */
+       memcpy (op, "\xFC\x20\x00\x00\x00\x00", 6);
+       op[1] |= gotreg;
+       /* add e2,a0.  */
+       memcpy (op+6, "\xF9\x78\x28", 3);
+       /* or  0x00000000, d0 - six byte nop.  */
+       memcpy (op+9, "\xFC\xE4\x00\x00\x00\x00", 6);
+      }
+      return 7;
+
+    case TLS_PAIR (R_MN10300_TLS_GD, R_MN10300_TLS_LE):
+      {
+       /* Register is *always* a0.  */
+       /* mov _x@tpoff,a0.  */
+       memcpy (op, "\xFC\xDC\x00\x00\x00\x00", 6);
+       /* add e2,a0.  */
+       memcpy (op+6, "\xF9\x78\x28", 3);
+       /* or  0x00000000, d0 - six byte nop.  */
+       memcpy (op+9, "\xFC\xE4\x00\x00\x00\x00", 6);
+      }
+      return 7;
+    case TLS_PAIR (R_MN10300_TLS_LD, R_MN10300_NONE):
+      {
+       /* Register is *always* a0.  */
+       /* mov e2,a0.  */
+       memcpy (op, "\xF5\x88", 2);
+       /* or  0x00000000, d0 - six byte nop.  */
+       memcpy (op+2, "\xFC\xE4\x00\x00\x00\x00", 6);
+       /* or  0x00000000, e2 - seven byte nop.  */
+       memcpy (op+8, "\xFE\x19\x22\x00\x00\x00\x00", 7);
+      }
+      return 7;
+
+    case TLS_PAIR (R_MN10300_TLS_LDO, R_MN10300_TLS_LE):
+      /* No changes needed, just the reloc change.  */
+      return 0;
+
+    /*  These are a little tricky, because we have to detect which
+       opcode is being used (they're different sizes, with the reloc
+       at different offsets within the opcode) and convert each
+       accordingly, copying the operands as needed.  The conversions
+       we do are as follows (IE,GOTIE,LE):
+
+                  1111 1100  1010 01Dn  [-- abs32 --]  MOV (x@indntpoff),Dn
+                  1111 1100  0000 DnAm  [-- abs32 --]  MOV (x@gotntpoff,Am),Dn
+                  1111 1100  1100 11Dn  [-- abs32 --]  MOV x@tpoff,Dn
+
+                  1111 1100  1010 00An  [-- abs32 --]  MOV (x@indntpoff),An
+                  1111 1100  0010 AnAm  [-- abs32 --]  MOV (x@gotntpoff,Am),An
+                  1111 1100  1101 11An  [-- abs32 --]  MOV x@tpoff,An
+
+       1111 1110  0000 1110  Rnnn Xxxx  [-- abs32 --]  MOV (x@indntpoff),Rn
+       1111 1110  0000 1010  Rnnn Rmmm  [-- abs32 --]  MOV (x@indntpoff,Rm),Rn
+       1111 1110  0000 1000  Rnnn Xxxx  [-- abs32 --]  MOV x@tpoff,Rn
+
+       Since the GOT pointer is always $a2, we assume the last
+       normally won't happen, but let's be paranoid and plan for the
+       day that GCC optimizes it somewhow.  */
+
+    case TLS_PAIR (R_MN10300_TLS_IE, R_MN10300_TLS_LE):
+      if (op[-2] == 0xFC)
+       {
+         op -= 2;
+         if ((op[1] & 0xFC) == 0xA4) /* Dn */
+           {
+             op[1] &= 0x03; /* Leaves Dn.  */
+             op[1] |= 0xCC;
+           }
+         else /* An */
+           {
+             op[1] &= 0x03; /* Leaves An. */
+             op[1] |= 0xDC;
+           }
+       }
+      else if (op[-3] == 0xFE)
+       op[-2] = 0x08;
+      else
+       abort ();
+      break;
+
+    case TLS_PAIR (R_MN10300_TLS_GOTIE, R_MN10300_TLS_LE):
+      if (op[-2] == 0xFC)
+       {
+         op -= 2;
+         if ((op[1] & 0xF0) == 0x00) /* Dn */
+           {
+             op[1] &= 0x0C; /* Leaves Dn.  */
+             op[1] >>= 2;
+             op[1] |= 0xCC;
+           }
+         else /* An */
+           {
+             op[1] &= 0x0C; /* Leaves An.  */
+             op[1] >>= 2;
+             op[1] |= 0xDC;
+           }
+       }
+      else if (op[-3] == 0xFE)
+       op[-2] = 0x08;
+      else
+       abort ();
+      break;
+
+    default:
+      (*_bfd_error_handler)
+       (_("%s: Unsupported transition from %s to %s"),
+        bfd_get_filename (input_bfd),
+        elf_mn10300_howto_table[r_type].name,
+        elf_mn10300_howto_table[tls_r_type].name);
+      break;
+    }
+#undef TLS_PAIR
+  return 0;
 }
 
 /* Look through the relocs for a section during the first phase.
@@ -675,13 +1028,15 @@ mn10300_info_to_howto (abfd, cache_ptr, dst)
    virtual table relocs for gc.  */
 
 static bfd_boolean
-mn10300_elf_check_relocs (abfd, info, sec, relocs)
-     bfd *abfd;
-     struct bfd_link_info *info;
-     asection *sec;
-     const Elf_Internal_Rela *relocs;
+mn10300_elf_check_relocs (bfd *abfd,
+                         struct bfd_link_info *info,
+                         asection *sec,
+                         const Elf_Internal_Rela *relocs)
 {
+  struct elf32_mn10300_link_hash_table * htab = elf32_mn10300_hash_table (info);
+  bfd_boolean sym_diff_reloc_seen;
   Elf_Internal_Shdr *symtab_hdr;
+  Elf_Internal_Sym * isymbuf = NULL;
   struct elf_link_hash_entry **sym_hashes;
   const Elf_Internal_Rela *rel;
   const Elf_Internal_Rela *rel_end;
@@ -690,6 +1045,7 @@ mn10300_elf_check_relocs (abfd, info, sec, relocs)
   asection * sgot;
   asection * srelgot;
   asection * sreloc;
+  bfd_boolean result = FALSE;
 
   sgot    = NULL;
   srelgot = NULL;
@@ -699,15 +1055,20 @@ mn10300_elf_check_relocs (abfd, info, sec, relocs)
     return TRUE;
 
   symtab_hdr = &elf_tdata (abfd)->symtab_hdr;
+  isymbuf = (Elf_Internal_Sym *) symtab_hdr->contents;
   sym_hashes = elf_sym_hashes (abfd);
 
   dynobj = elf_hash_table (info)->dynobj;
   local_got_offsets = elf_local_got_offsets (abfd);
   rel_end = relocs + sec->reloc_count;
+  sym_diff_reloc_seen = FALSE;
+
   for (rel = relocs; rel < rel_end; rel++)
     {
       struct elf_link_hash_entry *h;
       unsigned long r_symndx;
+      unsigned int r_type;
+      int tls_type = GOT_NORMAL;
 
       r_symndx = ELF32_R_SYM (rel->r_info);
       if (r_symndx < symtab_hdr->sh_info)
@@ -720,10 +1081,13 @@ mn10300_elf_check_relocs (abfd, info, sec, relocs)
            h = (struct elf_link_hash_entry *) h->root.u.i.link;
        }
 
+      r_type = ELF32_R_TYPE (rel->r_info);
+      r_type = elf_mn10300_tls_transition (info, r_type, h, sec, TRUE);
+
       /* Some relocs require a global offset table.  */
       if (dynobj == NULL)
        {
-         switch (ELF32_R_TYPE (rel->r_info))
+         switch (r_type)
            {
            case R_MN10300_GOT32:
            case R_MN10300_GOT24:
@@ -733,9 +1097,13 @@ mn10300_elf_check_relocs (abfd, info, sec, relocs)
            case R_MN10300_GOTOFF16:
            case R_MN10300_GOTPC32:
            case R_MN10300_GOTPC16:
+           case R_MN10300_TLS_GD:
+           case R_MN10300_TLS_LD:
+           case R_MN10300_TLS_GOTIE:
+           case R_MN10300_TLS_IE:
              elf_hash_table (info)->dynobj = dynobj = abfd;
              if (! _bfd_mn10300_elf_create_got_section (dynobj, info))
-               return FALSE;
+               goto fail;
              break;
 
            default:
@@ -743,13 +1111,13 @@ mn10300_elf_check_relocs (abfd, info, sec, relocs)
            }
        }
 
-      switch (ELF32_R_TYPE (rel->r_info))
+      switch (r_type)
        {
        /* This relocation describes the C++ object vtable hierarchy.
           Reconstruct it for later use during GC.  */
        case R_MN10300_GNU_VTINHERIT:
          if (!bfd_elf_gc_record_vtinherit (abfd, sec, h, rel->r_offset))
-           return FALSE;
+           goto fail;
          break;
 
        /* This relocation describes which C++ vtable entries are actually
@@ -758,13 +1126,38 @@ mn10300_elf_check_relocs (abfd, info, sec, relocs)
          BFD_ASSERT (h != NULL);
          if (h != NULL
              && !bfd_elf_gc_record_vtentry (abfd, sec, h, rel->r_addend))
-           return FALSE;
+           goto fail;
          break;
+
+       case R_MN10300_TLS_LD:
+         htab->tls_ldm_got.refcount ++;
+         tls_type = GOT_TLS_LD;
+
+         if (htab->tls_ldm_got.got_allocated)
+           break;
+         goto create_got;
+
+       case R_MN10300_TLS_IE:
+       case R_MN10300_TLS_GOTIE:
+         if (info->shared)
+           info->flags |= DF_STATIC_TLS;
+         /* Fall through */
+         
+       case R_MN10300_TLS_GD:
        case R_MN10300_GOT32:
        case R_MN10300_GOT24:
        case R_MN10300_GOT16:
+       create_got:
          /* This symbol requires a global offset table entry.  */
 
+         switch (r_type)
+           {
+           case R_MN10300_TLS_IE:
+           case R_MN10300_TLS_GOTIE: tls_type = GOT_TLS_IE; break;
+           case R_MN10300_TLS_GD:    tls_type = GOT_TLS_GD; break;
+           default:                  tls_type = GOT_NORMAL; break;
+           }
+
          if (sgot == NULL)
            {
              sgot = bfd_get_section_by_name (dynobj, ".got");
@@ -787,26 +1180,52 @@ mn10300_elf_check_relocs (abfd, info, sec, relocs)
                                                          | SEC_READONLY));
                  if (srelgot == NULL
                      || ! bfd_set_section_alignment (dynobj, srelgot, 2))
-                   return FALSE;
+                   goto fail;
                }
            }
 
-         if (h != NULL)
+         if (r_type == R_MN10300_TLS_LD)
+           {
+             htab->tls_ldm_got.offset = sgot->size;
+             htab->tls_ldm_got.got_allocated ++;
+           }
+         else if (h != NULL)
            {
+             if (elf_mn10300_hash_entry (h)->tls_type != tls_type
+                 && elf_mn10300_hash_entry (h)->tls_type != GOT_UNKNOWN)
+               {
+                 if (tls_type == GOT_TLS_IE
+                     && elf_mn10300_hash_entry (h)->tls_type == GOT_TLS_GD)
+                   /* No change - this is ok.  */;
+                 else if (tls_type == GOT_TLS_GD
+                     && elf_mn10300_hash_entry (h)->tls_type == GOT_TLS_IE)
+                   /* Transition GD->IE.  */
+                   tls_type = GOT_TLS_IE;
+                 else
+                   (*_bfd_error_handler)
+                     (_("%B: %s' accessed both as normal and thread local symbol"),
+                      abfd, h ? h->root.root.string : "<local>");
+               }
+
+             elf_mn10300_hash_entry (h)->tls_type = tls_type;
+
              if (h->got.offset != (bfd_vma) -1)
                /* We have already allocated space in the .got.  */
                break;
 
              h->got.offset = sgot->size;
 
-             /* Make sure this symbol is output as a dynamic symbol.  */
-             if (h->dynindx == -1)
+             if (ELF_ST_VISIBILITY (h->other) != STV_INTERNAL
+                 /* Make sure this symbol is output as a dynamic symbol.  */
+                 && h->dynindx == -1)
                {
                  if (! bfd_elf_link_record_dynamic_symbol (info, h))
-                   return FALSE;
+                   goto fail;
                }
 
              srelgot->size += sizeof (Elf32_External_Rela);
+             if (r_type == R_MN10300_TLS_GD)
+               srelgot->size += sizeof (Elf32_External_Rela);
            }
          else
            {
@@ -817,12 +1236,15 @@ mn10300_elf_check_relocs (abfd, info, sec, relocs)
                  size_t       size;
                  unsigned int i;
 
-                 size = symtab_hdr->sh_info * sizeof (bfd_vma);
-                 local_got_offsets = (bfd_vma *) bfd_alloc (abfd, size);
+                 size = symtab_hdr->sh_info * (sizeof (bfd_vma) + sizeof (char));
+                 local_got_offsets = bfd_alloc (abfd, size);
 
                  if (local_got_offsets == NULL)
-                   return FALSE;
+                   goto fail;
+
                  elf_local_got_offsets (abfd) = local_got_offsets;
+                 elf_mn10300_local_got_tls_type (abfd)
+                     = (char *) (local_got_offsets + symtab_hdr->sh_info);
 
                  for (i = 0; i < symtab_hdr->sh_info; i++)
                    local_got_offsets[i] = (bfd_vma) -1;
@@ -835,15 +1257,26 @@ mn10300_elf_check_relocs (abfd, info, sec, relocs)
              local_got_offsets[r_symndx] = sgot->size;
 
              if (info->shared)
-               /* If we are generating a shared object, we need to
-                  output a R_MN10300_RELATIVE reloc so that the dynamic
-                  linker can adjust this GOT entry.  */
-               srelgot->size += sizeof (Elf32_External_Rela);
+               {
+                 /* If we are generating a shared object, we need to
+                    output a R_MN10300_RELATIVE reloc so that the dynamic
+                    linker can adjust this GOT entry.  */
+                 srelgot->size += sizeof (Elf32_External_Rela);
+
+                 if (r_type == R_MN10300_TLS_GD)
+                   /* And a R_MN10300_TLS_DTPOFF reloc as well.  */
+                   srelgot->size += sizeof (Elf32_External_Rela);
+               }
+
+             elf_mn10300_local_got_tls_type (abfd) [r_symndx] = tls_type;
            }
 
          sgot->size += 4;
+         if (r_type == R_MN10300_TLS_GD
+             || r_type == R_MN10300_TLS_LD)
+           sgot->size += 4;
 
-         break;
+         goto need_shared_relocs;
 
        case R_MN10300_PLT32:
        case R_MN10300_PLT16:
@@ -864,7 +1297,6 @@ mn10300_elf_check_relocs (abfd, info, sec, relocs)
            break;
 
          h->needs_plt = 1;
-
          break;
 
        case R_MN10300_24:
@@ -877,59 +1309,83 @@ mn10300_elf_check_relocs (abfd, info, sec, relocs)
            h->non_got_ref = 1;
          break;
 
+       case R_MN10300_SYM_DIFF:
+         sym_diff_reloc_seen = TRUE;
+         break;
+
        case R_MN10300_32:
          if (h != NULL)
            h->non_got_ref = 1;
 
-         /* If we are creating a shared library, then we need to copy
-            the reloc into the shared library.  */
+       need_shared_relocs:
+         /* If we are creating a shared library, then we
+            need to copy the reloc into the shared library.  */
          if (info->shared
-             && (sec->flags & SEC_ALLOC) != 0)
+             && (sec->flags & SEC_ALLOC) != 0
+             /* Do not generate a dynamic reloc for a
+                reloc associated with a SYM_DIFF operation.  */
+             && ! sym_diff_reloc_seen)
            {
-             /* When creating a shared object, we must copy these
-                reloc types into the output file.  We create a reloc
-                section in dynobj and make room for this reloc.  */
-             if (sreloc == NULL)
-               {
-                 const char * name;
+             asection * sym_section = NULL;
 
-                 name = (bfd_elf_string_from_elf_section
-                         (abfd,
-                          elf_elfheader (abfd)->e_shstrndx,
-                          elf_section_data (sec)->rel_hdr.sh_name));
-                 if (name == NULL)
-                   return FALSE;
-
-                 BFD_ASSERT (CONST_STRNEQ (name, ".rela")
-                             && strcmp (bfd_get_section_name (abfd, sec),
-                                        name + 5) == 0);
+             /* Find the section containing the
+                symbol involved in the relocation.  */
+             if (h == NULL)
+               {
+                 Elf_Internal_Sym * isym;
 
-                 sreloc = bfd_get_section_by_name (dynobj, name);
-                 if (sreloc == NULL)
+                 if (isymbuf == NULL)
+                   isymbuf = bfd_elf_get_elf_syms (abfd, symtab_hdr,
+                                                   symtab_hdr->sh_info, 0,
+                                                   NULL, NULL, NULL);
+                 if (isymbuf)
                    {
-                     flagword flags;
-
-                     flags = (SEC_HAS_CONTENTS | SEC_READONLY
-                              | SEC_IN_MEMORY | SEC_LINKER_CREATED);
-                     if ((sec->flags & SEC_ALLOC) != 0)
-                       flags |= SEC_ALLOC | SEC_LOAD;
-                     sreloc = bfd_make_section_with_flags (dynobj,
-                                                           name,
-                                                           flags);
-                     if (sreloc == NULL
-                         || ! bfd_set_section_alignment (dynobj, sreloc, 2))
-                       return FALSE;
+                     isym = isymbuf + r_symndx;
+                     /* All we care about is whether this local symbol is absolute.  */
+                     if (isym->st_shndx == SHN_ABS)
+                       sym_section = bfd_abs_section_ptr;
                    }
                }
+             else
+               {
+                 if (h->root.type == bfd_link_hash_defined
+                     || h->root.type == bfd_link_hash_defweak)
+                   sym_section = h->root.u.def.section;
+               }
 
-             sreloc->size += sizeof (Elf32_External_Rela);
+             /* If the symbol is absolute then the relocation can
+                be resolved during linking and there is no need for
+                a dynamic reloc.  */
+             if (sym_section != bfd_abs_section_ptr)
+               {
+                 /* When creating a shared object, we must copy these
+                    reloc types into the output file.  We create a reloc
+                    section in dynobj and make room for this reloc.  */
+                 if (sreloc == NULL)
+                   {
+                     sreloc = _bfd_elf_make_dynamic_reloc_section
+                       (sec, dynobj, 2, abfd, /*rela?*/ TRUE);
+                     if (sreloc == NULL)
+                       goto fail;
+                   }
+
+                 sreloc->size += sizeof (Elf32_External_Rela);
+               }
            }
 
          break;
        }
+
+      if (ELF32_R_TYPE (rel->r_info) != R_MN10300_SYM_DIFF)
+       sym_diff_reloc_seen = FALSE;
     }
 
-  return TRUE;
+  result = TRUE;
+ fail:
+  if (isymbuf != NULL)
+    free (isymbuf);
+
+  return result;
 }
 
 /* Return the section that should be marked against GC for a given
@@ -954,35 +1410,34 @@ mn10300_elf_gc_mark_hook (asection *sec,
 }
 
 /* Perform a relocation as part of a final link.  */
+
 static bfd_reloc_status_type
-mn10300_elf_final_link_relocate (howto, input_bfd, output_bfd,
-                                input_section, contents, offset, value,
-                                addend, h, symndx, info, sym_sec, is_local)
-     reloc_howto_type *howto;
-     bfd *input_bfd;
-     bfd *output_bfd ATTRIBUTE_UNUSED;
-     asection *input_section;
-     bfd_byte *contents;
-     bfd_vma offset;
-     bfd_vma value;
-     bfd_vma addend;
-     struct elf_link_hash_entry * h;
-     unsigned long symndx;
-     struct bfd_link_info *info;
-     asection *sym_sec ATTRIBUTE_UNUSED;
-     int is_local ATTRIBUTE_UNUSED;
+mn10300_elf_final_link_relocate (reloc_howto_type *howto,
+                                bfd *input_bfd,
+                                bfd *output_bfd ATTRIBUTE_UNUSED,
+                                asection *input_section,
+                                bfd_byte *contents,
+                                bfd_vma offset,
+                                bfd_vma value,
+                                bfd_vma addend,
+                                struct elf_link_hash_entry * h,
+                                unsigned long symndx,
+                                struct bfd_link_info *info,
+                                asection *sym_sec ATTRIBUTE_UNUSED,
+                                int is_local ATTRIBUTE_UNUSED)
 {
+  struct elf32_mn10300_link_hash_table * htab = elf32_mn10300_hash_table (info);
+  static asection *  sym_diff_section;
+  static bfd_vma     sym_diff_value;
+  bfd_boolean is_sym_diff_reloc;
   unsigned long r_type = howto->type;
-  bfd_byte *hit_data = contents + offset;
+  bfd_byte * hit_data = contents + offset;
   bfd *      dynobj;
-  bfd_vma *  local_got_offsets;
   asection * sgot;
   asection * splt;
   asection * sreloc;
 
   dynobj = elf_hash_table (info)->dynobj;
-  local_got_offsets = elf_local_got_offsets (input_bfd);
-
   sgot   = NULL;
   splt   = NULL;
   sreloc = NULL;
@@ -1003,15 +1458,79 @@ mn10300_elf_final_link_relocate (howto, input_bfd, output_bfd,
          && h != NULL
          && ! SYMBOL_REFERENCES_LOCAL (info, h))
        return bfd_reloc_dangerous;
+    case R_MN10300_GOT32:
+      /* Issue 2052223:
+        Taking the address of a protected function in a shared library
+        is illegal.  Issue an error message here.  */
+      if (info->shared
+         && (input_section->flags & SEC_ALLOC) != 0
+         && h != NULL
+         && ELF_ST_VISIBILITY (h->other) == STV_PROTECTED
+         && (h->type == STT_FUNC || h->type == STT_GNU_IFUNC)
+         && ! SYMBOL_REFERENCES_LOCAL (info, h))
+       return bfd_reloc_dangerous;
+    }
+
+  is_sym_diff_reloc = FALSE;
+  if (sym_diff_section != NULL)
+    {
+      BFD_ASSERT (sym_diff_section == input_section);
+
+      switch (r_type)
+       {
+       case R_MN10300_32:
+       case R_MN10300_24:
+       case R_MN10300_16:
+       case R_MN10300_8:
+         value -= sym_diff_value;
+         /* If we are computing a 32-bit value for the location lists
+            and the result is 0 then we add one to the value.  A zero
+            value can result because of linker relaxation deleteing
+            prologue instructions and using a value of 1 (for the begin
+            and end offsets in the location list entry) results in a
+            nul entry which does not prevent the following entries from
+            being parsed.  */
+         if (r_type == R_MN10300_32
+             && value == 0
+             && strcmp (input_section->name, ".debug_loc") == 0)
+           value = 1;
+         sym_diff_section = NULL;
+         is_sym_diff_reloc = TRUE;
+         break;
+
+       default:
+         sym_diff_section = NULL;
+         break;
+       }
     }
 
   switch (r_type)
     {
+    case R_MN10300_SYM_DIFF:
+      BFD_ASSERT (addend == 0);
+      /* Cache the input section and value.
+        The offset is unreliable, since relaxation may
+        have reduced the following reloc's offset.  */
+      sym_diff_section = input_section;
+      sym_diff_value = value;
+      return bfd_reloc_ok;
+
+    case R_MN10300_ALIGN:
     case R_MN10300_NONE:
       return bfd_reloc_ok;
 
     case R_MN10300_32:
       if (info->shared
+         /* Do not generate relocs when an R_MN10300_32 has been used
+            with an R_MN10300_SYM_DIFF to compute a difference of two
+            symbols.  */
+         && is_sym_diff_reloc == FALSE
+         /* Also, do not generate a reloc when the symbol associated
+            with the R_MN10300_32 reloc is absolute - there is no
+            need for a run time computation in this case.  */
+         && sym_sec != bfd_abs_section_ptr
+         /* If the section is not going to be allocated at load time
+            then there is no need to generate relocs for it.  */
          && (input_section->flags & SEC_ALLOC) != 0)
        {
          Elf_Internal_Rela outrel;
@@ -1022,22 +1541,10 @@ mn10300_elf_final_link_relocate (howto, input_bfd, output_bfd,
             time.  */
          if (sreloc == NULL)
            {
-             const char * name;
-
-             name = (bfd_elf_string_from_elf_section
-                     (input_bfd,
-                      elf_elfheader (input_bfd)->e_shstrndx,
-                      elf_section_data (input_section)->rel_hdr.sh_name));
-             if (name == NULL)
+             sreloc = _bfd_elf_get_dynamic_reloc_section
+               (input_bfd, input_section, /*rela?*/ TRUE);
+             if (sreloc == NULL)
                return FALSE;
-
-             BFD_ASSERT (CONST_STRNEQ (name, ".rela")
-                         && strcmp (bfd_get_section_name (input_bfd,
-                                                          input_section),
-                                    name + 5) == 0);
-
-             sreloc = bfd_get_section_by_name (dynobj, name);
-             BFD_ASSERT (sreloc != NULL);
            }
 
          skip = FALSE;
@@ -1126,7 +1633,7 @@ mn10300_elf_final_link_relocate (howto, input_bfd, output_bfd,
       value -= offset;
       value += addend;
 
-      if ((long) value > 0xff || (long) value < -0x100)
+      if ((long) value > 0x7f || (long) value < -0x80)
        return bfd_reloc_overflow;
 
       bfd_put_8 (input_bfd, value, hit_data);
@@ -1138,7 +1645,7 @@ mn10300_elf_final_link_relocate (howto, input_bfd, output_bfd,
       value -= offset;
       value += addend;
 
-      if ((long) value > 0xffff || (long) value < -0x10000)
+      if ((long) value > 0x7fff || (long) value < -0x8000)
        return bfd_reloc_overflow;
 
       bfd_put_16 (input_bfd, value, hit_data);
@@ -1158,8 +1665,10 @@ mn10300_elf_final_link_relocate (howto, input_bfd, output_bfd,
       return bfd_reloc_ok;
 
     case R_MN10300_GOTPC32:
-      /* Use global offset table as symbol value.  */
+      if (dynobj == NULL)
+       return bfd_reloc_dangerous;
 
+      /* Use global offset table as symbol value.  */
       value = bfd_get_section_by_name (dynobj,
                                       ".got")->output_section->vma;
       value -= (input_section->output_section->vma
@@ -1171,8 +1680,10 @@ mn10300_elf_final_link_relocate (howto, input_bfd, output_bfd,
       return bfd_reloc_ok;
 
     case R_MN10300_GOTPC16:
-      /* Use global offset table as symbol value.  */
+      if (dynobj == NULL)
+       return bfd_reloc_dangerous;
 
+      /* Use global offset table as symbol value.  */
       value = bfd_get_section_by_name (dynobj,
                                       ".got")->output_section->vma;
       value -= (input_section->output_section->vma
@@ -1180,13 +1691,16 @@ mn10300_elf_final_link_relocate (howto, input_bfd, output_bfd,
       value -= offset;
       value += addend;
 
-      if ((long) value > 0xffff || (long) value < -0x10000)
+      if ((long) value > 0x7fff || (long) value < -0x8000)
        return bfd_reloc_overflow;
 
       bfd_put_16 (input_bfd, value, hit_data);
       return bfd_reloc_ok;
 
     case R_MN10300_GOTOFF32:
+      if (dynobj == NULL)
+       return bfd_reloc_dangerous;
+
       value -= bfd_get_section_by_name (dynobj,
                                        ".got")->output_section->vma;
       value += addend;
@@ -1195,6 +1709,9 @@ mn10300_elf_final_link_relocate (howto, input_bfd, output_bfd,
       return bfd_reloc_ok;
 
     case R_MN10300_GOTOFF24:
+      if (dynobj == NULL)
+       return bfd_reloc_dangerous;
+
       value -= bfd_get_section_by_name (dynobj,
                                        ".got")->output_section->vma;
       value += addend;
@@ -1208,11 +1725,14 @@ mn10300_elf_final_link_relocate (howto, input_bfd, output_bfd,
       return bfd_reloc_ok;
 
     case R_MN10300_GOTOFF16:
+      if (dynobj == NULL)
+       return bfd_reloc_dangerous;
+
       value -= bfd_get_section_by_name (dynobj,
                                        ".got")->output_section->vma;
       value += addend;
 
-      if ((long) value > 0xffff || (long) value < -0x10000)
+      if ((long) value > 0x7fff || (long) value < -0x8000)
        return bfd_reloc_overflow;
 
       bfd_put_16 (input_bfd, value, hit_data);
@@ -1224,7 +1744,8 @@ mn10300_elf_final_link_relocate (howto, input_bfd, output_bfd,
          && ELF_ST_VISIBILITY (h->other) != STV_HIDDEN
          && h->plt.offset != (bfd_vma) -1)
        {
-         asection * splt;
+         if (dynobj == NULL)
+           return bfd_reloc_dangerous;
 
          splt = bfd_get_section_by_name (dynobj, ".plt");
 
@@ -1247,7 +1768,8 @@ mn10300_elf_final_link_relocate (howto, input_bfd, output_bfd,
          && ELF_ST_VISIBILITY (h->other) != STV_HIDDEN
          && h->plt.offset != (bfd_vma) -1)
        {
-         asection * splt;
+         if (dynobj == NULL)
+           return bfd_reloc_dangerous;
 
          splt = bfd_get_section_by_name (dynobj, ".plt");
 
@@ -1261,49 +1783,108 @@ mn10300_elf_final_link_relocate (howto, input_bfd, output_bfd,
       value -= offset;
       value += addend;
 
-      if ((long) value > 0xffff || (long) value < -0x10000)
+      if ((long) value > 0x7fff || (long) value < -0x8000)
        return bfd_reloc_overflow;
 
       bfd_put_16 (input_bfd, value, hit_data);
       return bfd_reloc_ok;
 
+    case R_MN10300_TLS_LDO:
+      value = dtpoff (info, value);
+      bfd_put_32 (input_bfd, value + addend, hit_data);
+      return bfd_reloc_ok;
+
+    case R_MN10300_TLS_LE:
+      value = tpoff (info, value);
+      bfd_put_32 (input_bfd, value + addend, hit_data);
+      return bfd_reloc_ok;
+
+    case R_MN10300_TLS_LD:
+      if (dynobj == NULL)
+       return bfd_reloc_dangerous;
+
+      sgot = bfd_get_section_by_name (dynobj, ".got");
+
+      BFD_ASSERT (sgot != NULL);
+      value = htab->tls_ldm_got.offset + sgot->output_offset;
+      bfd_put_32 (input_bfd, value, hit_data);
+
+      if (!htab->tls_ldm_got.rel_emitted)
+       {
+         asection * srelgot = bfd_get_section_by_name (dynobj, ".rela.got");
+         Elf_Internal_Rela rel;
+
+         BFD_ASSERT (srelgot != NULL);
+         htab->tls_ldm_got.rel_emitted ++;
+         rel.r_offset = (sgot->output_section->vma
+                         + sgot->output_offset
+                         + htab->tls_ldm_got.offset);
+         bfd_put_32 (output_bfd, (bfd_vma) 0, sgot->contents + htab->tls_ldm_got.offset);
+         bfd_put_32 (output_bfd, (bfd_vma) 0, sgot->contents + htab->tls_ldm_got.offset+4);
+         rel.r_info = ELF32_R_INFO (0, R_MN10300_TLS_DTPMOD);
+         rel.r_addend = 0;
+         bfd_elf32_swap_reloca_out (output_bfd, & rel,
+                                    (bfd_byte *) ((Elf32_External_Rela *) srelgot->contents
+                                                  + srelgot->reloc_count));
+         ++ srelgot->reloc_count;
+       }
+
+      return bfd_reloc_ok;
+
+    case R_MN10300_TLS_GOTIE:
+      value = tpoff (info, value);
+      /* Fall Through.  */
+
+    case R_MN10300_TLS_GD:
+    case R_MN10300_TLS_IE:
     case R_MN10300_GOT32:
     case R_MN10300_GOT24:
     case R_MN10300_GOT16:
-      {
-       asection * sgot;
+      if (dynobj == NULL)
+       return bfd_reloc_dangerous;
 
-       sgot = bfd_get_section_by_name (dynobj, ".got");
+      sgot = bfd_get_section_by_name (dynobj, ".got");
 
-         if (h != NULL)
-           {
-             bfd_vma off;
+      if (r_type == R_MN10300_TLS_GD)
+       value = dtpoff (info, value);
 
-             off = h->got.offset;
-             BFD_ASSERT (off != (bfd_vma) -1);
+      if (h != NULL)
+       {
+         bfd_vma off;
+
+         off = h->got.offset;
+         /* Offsets in the GOT are allocated in check_relocs
+            which is not called for shared libraries... */
+         if (off == (bfd_vma) -1)
+           off = 0;
+
+         if (sgot->contents != NULL
+             && (! elf_hash_table (info)->dynamic_sections_created
+                 || SYMBOL_REFERENCES_LOCAL (info, h)))
+           /* This is actually a static link, or it is a
+              -Bsymbolic link and the symbol is defined
+              locally, or the symbol was forced to be local
+              because of a version file.  We must initialize
+              this entry in the global offset table.
+
+              When doing a dynamic link, we create a .rela.got
+              relocation entry to initialize the value.  This
+              is done in the finish_dynamic_symbol routine.  */
+           bfd_put_32 (output_bfd, value,
+                       sgot->contents + off);
+
+         value = sgot->output_offset + off;
+       }
+      else
+       {
+         bfd_vma off;
 
-             if (! elf_hash_table (info)->dynamic_sections_created
-                 || SYMBOL_REFERENCES_LOCAL (info, h))
-               /* This is actually a static link, or it is a
-                  -Bsymbolic link and the symbol is defined
-                  locally, or the symbol was forced to be local
-                  because of a version file.  We must initialize
-                  this entry in the global offset table.
-
-                  When doing a dynamic link, we create a .rela.got
-                  relocation entry to initialize the value.  This
-                  is done in the finish_dynamic_symbol routine.  */
-               bfd_put_32 (output_bfd, value,
-                           sgot->contents + off);
-
-             value = sgot->output_offset + off;
-           }
+         off = elf_local_got_offsets (input_bfd)[symndx];
+
+         if (off & 1)
+           bfd_put_32 (output_bfd, value, sgot->contents + (off & ~ 1));
          else
            {
-             bfd_vma off;
-
-             off = elf_local_got_offsets (input_bfd)[symndx];
-
              bfd_put_32 (output_bfd, value, sgot->contents + off);
 
              if (info->shared)
@@ -1317,22 +1898,58 @@ mn10300_elf_final_link_relocate (howto, input_bfd, output_bfd,
                  outrel.r_offset = (sgot->output_section->vma
                                     + sgot->output_offset
                                     + off);
-                 outrel.r_info = ELF32_R_INFO (0, R_MN10300_RELATIVE);
+                 switch (r_type)
+                   {
+                   case R_MN10300_TLS_GD:
+                     outrel.r_info = ELF32_R_INFO (0, R_MN10300_TLS_DTPOFF);
+                     outrel.r_offset = (sgot->output_section->vma
+                                        + sgot->output_offset
+                                        + off + 4);
+                     bfd_elf32_swap_reloca_out (output_bfd, & outrel,
+                                                (bfd_byte *) (((Elf32_External_Rela *)
+                                                               srelgot->contents)
+                                                              + srelgot->reloc_count));
+                     ++ srelgot->reloc_count;
+                     outrel.r_info = ELF32_R_INFO (0, R_MN10300_TLS_DTPMOD);
+                     break;
+                   case R_MN10300_TLS_GOTIE:
+                   case R_MN10300_TLS_IE:
+                     outrel.r_info = ELF32_R_INFO (0, R_MN10300_TLS_TPOFF);
+                     break;
+                   default:
+                     outrel.r_info = ELF32_R_INFO (0, R_MN10300_RELATIVE);
+                     break;
+                   }
+
                  outrel.r_addend = value;
                  bfd_elf32_swap_reloca_out (output_bfd, &outrel,
                                             (bfd_byte *) (((Elf32_External_Rela *)
                                                            srelgot->contents)
                                                           + srelgot->reloc_count));
                  ++ srelgot->reloc_count;
+                 elf_local_got_offsets (input_bfd)[symndx] |= 1;
                }
 
-             value = sgot->output_offset + off;
+             value = sgot->output_offset + (off & ~(bfd_vma) 1);
            }
-      }
+       }
 
       value += addend;
 
-      if (r_type == R_MN10300_GOT32)
+      if (r_type == R_MN10300_TLS_IE)
+       {
+         value += sgot->output_section->vma;
+         bfd_put_32 (input_bfd, value, hit_data);
+         return bfd_reloc_ok;
+       }
+      else if (r_type == R_MN10300_TLS_GOTIE
+              || r_type == R_MN10300_TLS_GD
+              || r_type == R_MN10300_TLS_LD)
+       {
+         bfd_put_32 (input_bfd, value, hit_data);
+         return bfd_reloc_ok;
+       }
+      else if (r_type == R_MN10300_GOT32)
        {
          bfd_put_32 (input_bfd, value, hit_data);
          return bfd_reloc_ok;
@@ -1349,7 +1966,7 @@ mn10300_elf_final_link_relocate (howto, input_bfd, output_bfd,
        }
       else if (r_type == R_MN10300_GOT16)
        {
-         if ((long) value > 0xffff || (long) value < -0x10000)
+         if ((long) value > 0x7fff || (long) value < -0x8000)
            return bfd_reloc_overflow;
 
          bfd_put_16 (input_bfd, value, hit_data);
@@ -1363,21 +1980,21 @@ mn10300_elf_final_link_relocate (howto, input_bfd, output_bfd,
 }
 \f
 /* Relocate an MN10300 ELF section.  */
+
 static bfd_boolean
-mn10300_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;
+mn10300_elf_relocate_section (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;
   struct elf_link_hash_entry **sym_hashes;
   Elf_Internal_Rela *rel, *relend;
+  Elf_Internal_Rela * trel;
 
   symtab_hdr = &elf_tdata (input_bfd)->symtab_hdr;
   sym_hashes = elf_sym_hashes (input_bfd);
@@ -1394,7 +2011,12 @@ mn10300_elf_relocate_section (output_bfd, info, input_bfd, input_section,
       struct elf32_mn10300_link_hash_entry *h;
       bfd_vma relocation;
       bfd_reloc_status_type r;
+      int tls_r_type;
+      bfd_boolean unresolved_reloc = FALSE;
+      bfd_boolean warned;
+      struct elf_link_hash_entry * hh;
 
+      relocation = 0;
       r_symndx = ELF32_R_SYM (rel->r_info);
       r_type = ELF32_R_TYPE (rel->r_info);
       howto = elf_mn10300_howto_table + r_type;
@@ -1408,24 +2030,42 @@ mn10300_elf_relocate_section (output_bfd, info, input_bfd, input_section,
       sym = NULL;
       sec = NULL;
       if (r_symndx < symtab_hdr->sh_info)
-       {
-         sym = local_syms + r_symndx;
-         sec = local_sections[r_symndx];
-         relocation = _bfd_elf_rela_local_sym (output_bfd, sym, &sec, rel);
-       }
+       hh = NULL;
       else
        {
-         bfd_boolean unresolved_reloc;
-         bfd_boolean warned;
-         struct elf_link_hash_entry *hh;
-
          RELOC_FOR_GLOBAL_SYMBOL (info, input_bfd, input_section, rel,
                                   r_symndx, symtab_hdr, sym_hashes,
                                   hh, sec, relocation,
                                   unresolved_reloc, warned);
+       }
+      h = elf_mn10300_hash_entry (hh);
 
-         h = (struct elf32_mn10300_link_hash_entry *) hh;
+      tls_r_type = elf_mn10300_tls_transition (info, r_type, hh, input_section, 0);
+      if (tls_r_type != r_type)
+       {
+         bfd_boolean had_plt;
+
+         had_plt = mn10300_do_tls_transition (input_bfd, r_type, tls_r_type,
+                                              contents, rel->r_offset);
+         r_type = tls_r_type;
+         howto = elf_mn10300_howto_table + r_type;
+
+         if (had_plt)
+           for (trel = rel+1; trel < relend; trel++)
+             if ((ELF32_R_TYPE (trel->r_info) == R_MN10300_PLT32
+                  || ELF32_R_TYPE (trel->r_info) == R_MN10300_PCREL32)
+                 && rel->r_offset + had_plt == trel->r_offset)
+               trel->r_info = ELF32_R_INFO (0, R_MN10300_NONE);
+       }
 
+      if (r_symndx < symtab_hdr->sh_info)
+       {
+         sym = local_syms + r_symndx;
+         sec = local_sections[r_symndx];
+         relocation = _bfd_elf_rela_local_sym (output_bfd, sym, &sec, rel);
+       }
+      else
+       {
          if ((h->root.root.type == bfd_link_hash_defined
              || h->root.root.type == bfd_link_hash_defweak)
              && (   r_type == R_MN10300_GOTPC32
@@ -1437,10 +2077,18 @@ mn10300_elf_relocate_section (output_bfd, info, input_bfd, input_section,
                      && h->root.plt.offset != (bfd_vma) -1)
                  || ((   r_type == R_MN10300_GOT32
                       || r_type == R_MN10300_GOT24
+                      || r_type == R_MN10300_TLS_GD
+                      || r_type == R_MN10300_TLS_LD
+                      || r_type == R_MN10300_TLS_GOTIE
+                      || r_type == R_MN10300_TLS_IE
                       || r_type == R_MN10300_GOT16)
                      && elf_hash_table (info)->dynamic_sections_created
                      && !SYMBOL_REFERENCES_LOCAL (info, hh))
                  || (r_type == R_MN10300_32
+                     /* _32 relocs in executables force _COPY relocs,
+                        such that the address of the symbol ends up
+                        being local.  */
+                     && !info->executable
                      && !SYMBOL_REFERENCES_LOCAL (info, hh)
                      && ((input_section->flags & SEC_ALLOC) != 0
                          /* DWARF will emit R_MN10300_32 relocations
@@ -1454,7 +2102,10 @@ mn10300_elf_relocate_section (output_bfd, info, input_bfd, input_section,
               obscure cases sec->output_section will be NULL.  */
            relocation = 0;
 
-         else if (!info->relocatable && unresolved_reloc)
+         else if (!info->relocatable && unresolved_reloc
+                  && _bfd_elf_section_offset (output_bfd, info, input_section,
+                                              rel->r_offset) != (bfd_vma) -1)
+
            (*_bfd_error_handler)
              (_("%B(%A+0x%lx): unresolvable %s relocation against symbol `%s'"),
               input_bfd,
@@ -1465,15 +2116,8 @@ mn10300_elf_relocate_section (output_bfd, info, input_bfd, input_section,
        }
 
       if (sec != NULL && elf_discarded_section (sec))
-       {
-         /* For relocs against symbols from removed linkonce sections,
-            or sections discarded by a linker script, we just want the
-            section contents zeroed.  Avoid any special processing.  */
-         _bfd_clear_contents (howto, input_bfd, contents + rel->r_offset);
-         rel->r_info = 0;
-         rel->r_addend = 0;
-         continue;
-       }
+       RELOC_AGAINST_DISCARDED_SECTION (info, input_bfd, input_section,
+                                        rel, relend, howto, contents);
 
       if (info->relocatable)
        continue;
@@ -1482,176 +2126,488 @@ mn10300_elf_relocate_section (output_bfd, info, input_bfd, input_section,
                                           input_section,
                                           contents, rel->r_offset,
                                           relocation, rel->r_addend,
-                                          (struct elf_link_hash_entry *)h,
+                                          (struct elf_link_hash_entry *) h,
                                           r_symndx,
                                           info, sec, h == NULL);
 
-      if (r != bfd_reloc_ok)
-       {
-         const char *name;
-         const char *msg = (const char *) 0;
+      if (r != bfd_reloc_ok)
+       {
+         const char *name;
+         const char *msg = NULL;
+
+         if (h != NULL)
+           name = h->root.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);
+           }
+
+         switch (r)
+           {
+           case bfd_reloc_overflow:
+             if (! ((*info->callbacks->reloc_overflow)
+                    (info, (h ? &h->root.root : NULL), name,
+                     howto->name, (bfd_vma) 0, input_bfd,
+                     input_section, rel->r_offset)))
+               return FALSE;
+             break;
+
+           case bfd_reloc_undefined:
+             if (! ((*info->callbacks->undefined_symbol)
+                    (info, name, input_bfd, input_section,
+                     rel->r_offset, TRUE)))
+               return FALSE;
+             break;
+
+           case bfd_reloc_outofrange:
+             msg = _("internal error: out of range error");
+             goto common_error;
+
+           case bfd_reloc_notsupported:
+             msg = _("internal error: unsupported relocation error");
+             goto common_error;
+
+           case bfd_reloc_dangerous:
+             if (r_type == R_MN10300_PCREL32)
+               msg = _("error: inappropriate relocation type for shared"
+                       " library (did you forget -fpic?)");
+             else if (r_type == R_MN10300_GOT32)
+               msg = _("%B: taking the address of protected function"
+                       " '%s' cannot be done when making a shared library");
+             else
+               msg = _("internal error: suspicious relocation type used"
+                       " in shared library");
+             goto common_error;
+
+           default:
+             msg = _("internal error: unknown error");
+             /* Fall through.  */
+
+           common_error:
+             _bfd_error_handler (msg, input_bfd, name);
+             bfd_set_error (bfd_error_bad_value);
+             return FALSE;
+           }
+       }
+    }
+
+  return TRUE;
+}
+
+/* Finish initializing one hash table entry.  */
+
+static bfd_boolean
+elf32_mn10300_finish_hash_table_entry (struct bfd_hash_entry *gen_entry,
+                                      void * in_args)
+{
+  struct elf32_mn10300_link_hash_entry *entry;
+  struct bfd_link_info *link_info = (struct bfd_link_info *) in_args;
+  unsigned int byte_count = 0;
+
+  entry = (struct elf32_mn10300_link_hash_entry *) gen_entry;
+
+  /* If we already know we want to convert "call" to "calls" for calls
+     to this symbol, then return now.  */
+  if (entry->flags == MN10300_CONVERT_CALL_TO_CALLS)
+    return TRUE;
+
+  /* If there are no named calls to this symbol, or there's nothing we
+     can move from the function itself into the "call" instruction,
+     then note that all "call" instructions should be converted into
+     "calls" instructions and return.  If a symbol is available for
+     dynamic symbol resolution (overridable or overriding), avoid
+     custom calling conventions.  */
+  if (entry->direct_calls == 0
+      || (entry->stack_size == 0 && entry->movm_args == 0)
+      || (elf_hash_table (link_info)->dynamic_sections_created
+         && ELF_ST_VISIBILITY (entry->root.other) != STV_INTERNAL
+         && ELF_ST_VISIBILITY (entry->root.other) != STV_HIDDEN))
+    {
+      /* Make a note that we should convert "call" instructions to "calls"
+        instructions for calls to this symbol.  */
+      entry->flags |= MN10300_CONVERT_CALL_TO_CALLS;
+      return TRUE;
+    }
+
+  /* We may be able to move some instructions from the function itself into
+     the "call" instruction.  Count how many bytes we might be able to
+     eliminate in the function itself.  */
+
+  /* A movm instruction is two bytes.  */
+  if (entry->movm_args)
+    byte_count += 2;
+
+  /* Count the insn to allocate stack space too.  */
+  if (entry->stack_size > 0)
+    {
+      if (entry->stack_size <= 128)
+       byte_count += 3;
+      else
+       byte_count += 4;
+    }
+
+  /* If using "call" will result in larger code, then turn all
+     the associated "call" instructions into "calls" instructions.  */
+  if (byte_count < entry->direct_calls)
+    entry->flags |= MN10300_CONVERT_CALL_TO_CALLS;
+
+  /* This routine never fails.  */
+  return TRUE;
+}
+
+/* Used to count hash table entries.  */
+
+static bfd_boolean
+elf32_mn10300_count_hash_table_entries (struct bfd_hash_entry *gen_entry ATTRIBUTE_UNUSED,
+                                       void * in_args)
+{
+  int *count = (int *) in_args;
+
+  (*count) ++;
+  return TRUE;
+}
+
+/* Used to enumerate hash table entries into a linear array.  */
+
+static bfd_boolean
+elf32_mn10300_list_hash_table_entries (struct bfd_hash_entry *gen_entry,
+                                      void * in_args)
+{
+  struct bfd_hash_entry ***ptr = (struct bfd_hash_entry ***) in_args;
+
+  **ptr = gen_entry;
+  (*ptr) ++;
+  return TRUE;
+}
+
+/* Used to sort the array created by the above.  */
+
+static int
+sort_by_value (const void *va, const void *vb)
+{
+  struct elf32_mn10300_link_hash_entry *a
+    = *(struct elf32_mn10300_link_hash_entry **) va;
+  struct elf32_mn10300_link_hash_entry *b
+    = *(struct elf32_mn10300_link_hash_entry **) vb;
+
+  return a->value - b->value;
+}
+
+/* Compute the stack size and movm arguments for the function
+   referred to by HASH at address ADDR in section with
+   contents CONTENTS, store the information in the hash table.  */
+
+static void
+compute_function_info (bfd *abfd,
+                      struct elf32_mn10300_link_hash_entry *hash,
+                      bfd_vma addr,
+                      unsigned char *contents)
+{
+  unsigned char byte1, byte2;
+  /* We only care about a very small subset of the possible prologue
+     sequences here.  Basically we look for:
+
+     movm [d2,d3,a2,a3],sp (optional)
+     add <size>,sp (optional, and only for sizes which fit in an unsigned
+                   8 bit number)
+
+     If we find anything else, we quit.  */
+
+  /* Look for movm [regs],sp.  */
+  byte1 = bfd_get_8 (abfd, contents + addr);
+  byte2 = bfd_get_8 (abfd, contents + addr + 1);
+
+  if (byte1 == 0xcf)
+    {
+      hash->movm_args = byte2;
+      addr += 2;
+      byte1 = bfd_get_8 (abfd, contents + addr);
+      byte2 = bfd_get_8 (abfd, contents + addr + 1);
+    }
+
+  /* Now figure out how much stack space will be allocated by the movm
+     instruction.  We need this kept separate from the function's normal
+     stack space.  */
+  if (hash->movm_args)
+    {
+      /* Space for d2.  */
+      if (hash->movm_args & 0x80)
+       hash->movm_stack_size += 4;
+
+      /* Space for d3.  */
+      if (hash->movm_args & 0x40)
+       hash->movm_stack_size += 4;
+
+      /* Space for a2.  */
+      if (hash->movm_args & 0x20)
+       hash->movm_stack_size += 4;
+
+      /* Space for a3.  */
+      if (hash->movm_args & 0x10)
+       hash->movm_stack_size += 4;
+
+      /* "other" space.  d0, d1, a0, a1, mdr, lir, lar, 4 byte pad.  */
+      if (hash->movm_args & 0x08)
+       hash->movm_stack_size += 8 * 4;
+
+      if (bfd_get_mach (abfd) == bfd_mach_am33
+         || bfd_get_mach (abfd) == bfd_mach_am33_2)
+       {
+         /* "exother" space.  e0, e1, mdrq, mcrh, mcrl, mcvf */
+         if (hash->movm_args & 0x1)
+           hash->movm_stack_size += 6 * 4;
+
+         /* exreg1 space.  e4, e5, e6, e7 */
+         if (hash->movm_args & 0x2)
+           hash->movm_stack_size += 4 * 4;
+
+         /* exreg0 space.  e2, e3  */
+         if (hash->movm_args & 0x4)
+           hash->movm_stack_size += 2 * 4;
+       }
+    }
+
+  /* Now look for the two stack adjustment variants.  */
+  if (byte1 == 0xf8 && byte2 == 0xfe)
+    {
+      int temp = bfd_get_8 (abfd, contents + addr + 2);
+      temp = ((temp & 0xff) ^ (~0x7f)) + 0x80;
+
+      hash->stack_size = -temp;
+    }
+  else if (byte1 == 0xfa && byte2 == 0xfe)
+    {
+      int temp = bfd_get_16 (abfd, contents + addr + 2);
+      temp = ((temp & 0xffff) ^ (~0x7fff)) + 0x8000;
+      temp = -temp;
+
+      if (temp < 255)
+       hash->stack_size = temp;
+    }
 
-         if (h != NULL)
-           name = h->root.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 the total stack to be allocated by the call instruction is more
+     than 255 bytes, then we can't remove the stack adjustment by using
+     "call" (we might still be able to remove the "movm" instruction.  */
+  if (hash->stack_size + hash->movm_stack_size > 255)
+    hash->stack_size = 0;
+}
 
-         switch (r)
-           {
-           case bfd_reloc_overflow:
-             if (! ((*info->callbacks->reloc_overflow)
-                    (info, (h ? &h->root.root : NULL), name,
-                     howto->name, (bfd_vma) 0, input_bfd,
-                     input_section, rel->r_offset)))
-               return FALSE;
-             break;
+/* Delete some bytes from a section while relaxing.  */
 
-           case bfd_reloc_undefined:
-             if (! ((*info->callbacks->undefined_symbol)
-                    (info, name, input_bfd, input_section,
-                     rel->r_offset, TRUE)))
-               return FALSE;
-             break;
+static bfd_boolean
+mn10300_elf_relax_delete_bytes (bfd *abfd,
+                               asection *sec,
+                               bfd_vma addr,
+                               int count)
+{
+  Elf_Internal_Shdr *symtab_hdr;
+  unsigned int sec_shndx;
+  bfd_byte *contents;
+  Elf_Internal_Rela *irel, *irelend;
+  Elf_Internal_Rela *irelalign;
+  bfd_vma toaddr;
+  Elf_Internal_Sym *isym, *isymend;
+  struct elf_link_hash_entry **sym_hashes;
+  struct elf_link_hash_entry **end_hashes;
+  unsigned int symcount;
 
-           case bfd_reloc_outofrange:
-             msg = _("internal error: out of range error");
-             goto common_error;
+  sec_shndx = _bfd_elf_section_from_bfd_section (abfd, sec);
 
-           case bfd_reloc_notsupported:
-             msg = _("internal error: unsupported relocation error");
-             goto common_error;
+  contents = elf_section_data (sec)->this_hdr.contents;
 
-           case bfd_reloc_dangerous:
-             if (r_type == R_MN10300_PCREL32)
-               msg = _("error: inappropriate relocation type for shared"
-                       " library (did you forget -fpic?)");
-             else
-               msg = _("internal error: suspicious relocation type used"
-                       " in shared library");
-             goto common_error;
+  irelalign = NULL;
+  toaddr = sec->size;
 
-           default:
-             msg = _("internal error: unknown error");
-             /* fall through */
+  irel = elf_section_data (sec)->relocs;
+  irelend = irel + sec->reloc_count;
 
-           common_error:
-             if (!((*info->callbacks->warning)
-                   (info, msg, name, input_bfd, input_section,
-                    rel->r_offset)))
-               return FALSE;
+  if (sec->reloc_count > 0)
+    {
+      /* If there is an align reloc at the end of the section ignore it.
+        GAS creates these relocs for reasons of its own, and they just
+        serve to keep the section artifically inflated.  */
+      if (ELF32_R_TYPE ((irelend - 1)->r_info) == (int) R_MN10300_ALIGN)
+       --irelend;
+      
+      /* The deletion must stop at the next ALIGN reloc for an aligment
+        power larger than, or not a multiple of, the number of bytes we
+        are deleting.  */
+      for (; irel < irelend; irel++)
+       {
+         int alignment = 1 << irel->r_addend;
+
+         if (ELF32_R_TYPE (irel->r_info) == (int) R_MN10300_ALIGN
+             && irel->r_offset > addr
+             && irel->r_offset < toaddr
+             && (count < alignment
+                 || alignment % count != 0))
+           {
+             irelalign = irel;
+             toaddr = irel->r_offset;
              break;
            }
        }
     }
 
-  return TRUE;
-}
+  /* Actually delete the bytes.  */
+  memmove (contents + addr, contents + addr + count,
+          (size_t) (toaddr - addr - count));
 
-/* Finish initializing one hash table entry.  */
-static bfd_boolean
-elf32_mn10300_finish_hash_table_entry (gen_entry, in_args)
-     struct bfd_hash_entry *gen_entry;
-     PTR in_args;
-{
-  struct elf32_mn10300_link_hash_entry *entry;
-  struct bfd_link_info *link_info = (struct bfd_link_info *)in_args;
-  unsigned int byte_count = 0;
+  /* Adjust the section's size if we are shrinking it, or else
+     pad the bytes between the end of the shrunken region and
+     the start of the next region with NOP codes.  */
+  if (irelalign == NULL)
+    {
+      sec->size -= count;
+      /* Include symbols at the end of the section, but
+        not at the end of a sub-region of the section.  */
+      toaddr ++;
+    }
+  else
+    {
+      int i;
 
-  entry = (struct elf32_mn10300_link_hash_entry *) gen_entry;
+#define NOP_OPCODE 0xcb
 
-  if (entry->root.root.type == bfd_link_hash_warning)
-    entry = (struct elf32_mn10300_link_hash_entry *) entry->root.root.u.i.link;
+      for (i = 0; i < count; i ++)
+       bfd_put_8 (abfd, (bfd_vma) NOP_OPCODE, contents + toaddr - count + i);
+    }
 
-  /* If we already know we want to convert "call" to "calls" for calls
-     to this symbol, then return now.  */
-  if (entry->flags == MN10300_CONVERT_CALL_TO_CALLS)
-    return TRUE;
+  /* 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)
+         || (ELF32_R_TYPE (irel->r_info) == (int) R_MN10300_ALIGN
+             && irel->r_offset == toaddr))
+       irel->r_offset -= count;
+    }
 
-  /* If there are no named calls to this symbol, or there's nothing we
-     can move from the function itself into the "call" instruction,
-     then note that all "call" instructions should be converted into
-     "calls" instructions and return.  If a symbol is available for
-     dynamic symbol resolution (overridable or overriding), avoid
-     custom calling conventions.  */
-  if (entry->direct_calls == 0
-      || (entry->stack_size == 0 && entry->movm_args == 0)
-      || (elf_hash_table (link_info)->dynamic_sections_created
-         && ELF_ST_VISIBILITY (entry->root.other) != STV_INTERNAL
-         && ELF_ST_VISIBILITY (entry->root.other) != STV_HIDDEN))
+  /* Adjust the local symbols in the section, reducing their value
+     by the number of bytes deleted.  Note - symbols within the deleted
+     region are moved to the address of the start of the region, which
+     actually means that they will address the byte beyond the end of
+     the region once the deletion has been completed.  */
+  symtab_hdr = &elf_tdata (abfd)->symtab_hdr;
+  isym = (Elf_Internal_Sym *) symtab_hdr->contents;
+  for (isymend = isym + symtab_hdr->sh_info; isym < isymend; isym++)
     {
-      /* Make a note that we should convert "call" instructions to "calls"
-        instructions for calls to this symbol.  */
-      entry->flags |= MN10300_CONVERT_CALL_TO_CALLS;
-      return TRUE;
+      if (isym->st_shndx == sec_shndx
+         && isym->st_value > addr
+         && isym->st_value < toaddr)
+       {
+         if (isym->st_value < addr + count)
+           isym->st_value = addr;
+         else
+           isym->st_value -= count;
+       }
+      /* Adjust the function symbol's size as well.  */
+      else if (isym->st_shndx == sec_shndx
+              && ELF_ST_TYPE (isym->st_info) == STT_FUNC
+              && isym->st_value + isym->st_size > addr
+              && isym->st_value + isym->st_size < toaddr)
+       isym->st_size -= count;
     }
 
-  /* We may be able to move some instructions from the function itself into
-     the "call" instruction.  Count how many bytes we might be able to
-     eliminate in the function itself.  */
+  /* Now adjust the global symbols defined in this section.  */
+  symcount = (symtab_hdr->sh_size / sizeof (Elf32_External_Sym)
+             - symtab_hdr->sh_info);
+  sym_hashes = elf_sym_hashes (abfd);
+  end_hashes = sym_hashes + symcount;
+  for (; sym_hashes < end_hashes; sym_hashes++)
+    {
+      struct elf_link_hash_entry *sym_hash = *sym_hashes;
 
-  /* A movm instruction is two bytes.  */
-  if (entry->movm_args)
-    byte_count += 2;
+      if ((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)
+       {
+         if (sym_hash->root.u.def.value < addr + count)
+           sym_hash->root.u.def.value = addr;
+         else
+           sym_hash->root.u.def.value -= count;
+       }
+      /* Adjust the function symbol's size as well.  */
+      else if (sym_hash->root.type == bfd_link_hash_defined
+              && sym_hash->root.u.def.section == sec
+              && sym_hash->type == STT_FUNC
+              && sym_hash->root.u.def.value + sym_hash->size > addr
+              && sym_hash->root.u.def.value + sym_hash->size < toaddr)
+       sym_hash->size -= count;
+    }
 
-  /* Count the insn to allocate stack space too.  */
-  if (entry->stack_size > 0)
+  /* See if we can move the ALIGN reloc forward.
+     We have adjusted r_offset for it already.  */
+  if (irelalign != NULL)
     {
-      if (entry->stack_size <= 128)
-       byte_count += 3;
-      else
-       byte_count += 4;
-    }
+      bfd_vma alignto, alignaddr;
 
-  /* If using "call" will result in larger code, then turn all
-     the associated "call" instructions into "calls" instructions.  */
-  if (byte_count < entry->direct_calls)
-    entry->flags |= MN10300_CONVERT_CALL_TO_CALLS;
+      if ((int) irelalign->r_addend > 0)
+       {
+         /* This is the old address.  */
+         alignto = BFD_ALIGN (toaddr, 1 << irelalign->r_addend);
+         /* This is where the align points to now.  */
+         alignaddr = BFD_ALIGN (irelalign->r_offset,
+                                1 << irelalign->r_addend);
+         if (alignaddr < alignto)
+           /* Tail recursion.  */
+           return mn10300_elf_relax_delete_bytes (abfd, sec, alignaddr,
+                                                  (int) (alignto - alignaddr));
+       }
+    }
 
-  /* This routine never fails.  */
   return TRUE;
 }
 
-/* Used to count hash table entries.  */
+/* Return TRUE if a symbol exists at the given address, else return
+   FALSE.  */
+
 static bfd_boolean
-elf32_mn10300_count_hash_table_entries (struct bfd_hash_entry *gen_entry ATTRIBUTE_UNUSED,
-                                       PTR in_args)
+mn10300_elf_symbol_address_p (bfd *abfd,
+                             asection *sec,
+                             Elf_Internal_Sym *isym,
+                             bfd_vma addr)
 {
-  int *count = (int *)in_args;
+  Elf_Internal_Shdr *symtab_hdr;
+  unsigned int sec_shndx;
+  Elf_Internal_Sym *isymend;
+  struct elf_link_hash_entry **sym_hashes;
+  struct elf_link_hash_entry **end_hashes;
+  unsigned int symcount;
 
-  (*count) ++;
-  return TRUE;
-}
+  sec_shndx = _bfd_elf_section_from_bfd_section (abfd, sec);
 
-/* Used to enumerate hash table entries into a linear array.  */
-static bfd_boolean
-elf32_mn10300_list_hash_table_entries (struct bfd_hash_entry *gen_entry,
-                                      PTR in_args)
-{
-  struct bfd_hash_entry ***ptr = (struct bfd_hash_entry ***) in_args;
+  /* Examine all the symbols.  */
+  symtab_hdr = &elf_tdata (abfd)->symtab_hdr;
+  for (isymend = isym + symtab_hdr->sh_info; isym < isymend; isym++)
+    if (isym->st_shndx == sec_shndx
+       && isym->st_value == addr)
+      return TRUE;
 
-  **ptr = gen_entry;
-  (*ptr) ++;
-  return TRUE;
-}
+  symcount = (symtab_hdr->sh_size / sizeof (Elf32_External_Sym)
+             - symtab_hdr->sh_info);
+  sym_hashes = elf_sym_hashes (abfd);
+  end_hashes = sym_hashes + symcount;
+  for (; sym_hashes < end_hashes; sym_hashes++)
+    {
+      struct elf_link_hash_entry *sym_hash = *sym_hashes;
 
-/* Used to sort the array created by the above.  */
-static int
-sort_by_value (const void *va, const void *vb)
-{
-  struct elf32_mn10300_link_hash_entry *a
-    = *(struct elf32_mn10300_link_hash_entry **)va;
-  struct elf32_mn10300_link_hash_entry *b
-    = *(struct elf32_mn10300_link_hash_entry **)vb;
+      if ((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)
+       return TRUE;
+    }
 
-  return a->value - b->value;
+  return FALSE;
 }
 
-
 /* This function handles relaxing for the mn10300.
 
    There are quite a few relaxing opportunities available on the mn10300:
@@ -1692,11 +2648,10 @@ sort_by_value (const void *va, const void *vb)
        and somewhat more difficult to support.  */
 
 static bfd_boolean
-mn10300_elf_relax_section (abfd, sec, link_info, again)
-     bfd *abfd;
-     asection *sec;
-     struct bfd_link_info *link_info;
-     bfd_boolean *again;
+mn10300_elf_relax_section (bfd *abfd,
+                          asection *sec,
+                          struct bfd_link_info *link_info,
+                          bfd_boolean *again)
 {
   Elf_Internal_Shdr *symtab_hdr;
   Elf_Internal_Rela *internal_relocs = NULL;
@@ -1705,12 +2660,19 @@ mn10300_elf_relax_section (abfd, sec, link_info, again)
   Elf_Internal_Sym *isymbuf = NULL;
   struct elf32_mn10300_link_hash_table *hash_table;
   asection *section = sec;
+  bfd_vma align_gap_adjustment;
+
+  if (link_info->relocatable)
+    (*link_info->callbacks->einfo)
+      (_("%P%F: --relax and -r may not be used together\n"));
 
   /* Assume nothing changes.  */
   *again = FALSE;
 
   /* We need a pointer to the mn10300 specific hash table.  */
   hash_table = elf32_mn10300_hash_table (link_info);
+  if (hash_table == NULL)
+    return FALSE;
 
   /* Initialize fields in each hash table entry the first time through.  */
   if ((hash_table->flags & MN10300_HASH_ENTRIES_INITIALIZED) == 0)
@@ -1741,7 +2703,6 @@ mn10300_elf_relax_section (abfd, sec, link_info, again)
               section = section->next)
            {
              struct elf32_mn10300_link_hash_entry *hash;
-             Elf_Internal_Sym *sym;
              asection *sym_sec = NULL;
              const char *sym_name;
              char *new_name;
@@ -1770,12 +2731,10 @@ mn10300_elf_relax_section (abfd, sec, link_info, again)
              if ((section->flags & SEC_RELOC) != 0
                  && section->reloc_count != 0)
                {
-
                  /* Get a copy of the native relocations.  */
-                 internal_relocs = (_bfd_elf_link_read_relocs
-                                    (input_bfd, section, (PTR) NULL,
-                                     (Elf_Internal_Rela *) NULL,
-                                     link_info->keep_memory));
+                 internal_relocs = _bfd_elf_link_read_relocs (input_bfd, section,
+                                                              NULL, NULL,
+                                                              link_info->keep_memory);
                  if (internal_relocs == NULL)
                    goto error_return;
 
@@ -1797,7 +2756,6 @@ mn10300_elf_relax_section (abfd, sec, link_info, again)
                      /* We need the name and hash table entry of the target
                         symbol!  */
                      hash = NULL;
-                     sym = NULL;
                      sym_sec = NULL;
 
                      if (r_index < symtab_hdr->sh_info)
@@ -1834,7 +2792,7 @@ mn10300_elf_relax_section (abfd, sec, link_info, again)
                             local symbol in the global hash table.  */
                          amt = strlen (sym_name) + 10;
                          new_name = bfd_malloc (amt);
-                         if (new_name == 0)
+                         if (new_name == NULL)
                            goto error_return;
 
                          sprintf (new_name, "%s_%08x", sym_name, sym_sec->id);
@@ -1943,7 +2901,7 @@ mn10300_elf_relax_section (abfd, sec, link_info, again)
                             local symbol in the global hash table.  */
                          amt = strlen (sym_name) + 10;
                          new_name = bfd_malloc (amt);
-                         if (new_name == 0)
+                         if (new_name == NULL)
                            goto error_return;
 
                          sprintf (new_name, "%s_%08x", sym_name, sym_sec->id);
@@ -2033,26 +2991,28 @@ mn10300_elf_relax_section (abfd, sec, link_info, again)
                                          elf32_mn10300_count_hash_table_entries,
                                          &static_count);
 
-       entries = (struct elf32_mn10300_link_hash_entry **)
-         bfd_malloc (static_count * sizeof (struct elf32_mn10300_link_hash_entry *));
+       entries = bfd_malloc (static_count * sizeof (* ptr));
 
        ptr = entries;
        elf32_mn10300_link_hash_traverse (hash_table->static_hash_table,
                                          elf32_mn10300_list_hash_table_entries,
-                                         &ptr);
+                                         & ptr);
 
-       qsort (entries, static_count, sizeof(entries[0]), sort_by_value);
+       qsort (entries, static_count, sizeof (entries[0]), sort_by_value);
 
-       for (i=0; i<static_count-1; i++)
+       for (i = 0; i < static_count - 1; i++)
          if (entries[i]->value && entries[i]->value == entries[i+1]->value)
            {
              int v = entries[i]->flags;
              int j;
-             for (j=i+1; j<static_count && entries[j]->value == entries[i]->value; j++)
+
+             for (j = i + 1; j < static_count && entries[j]->value == entries[i]->value; j++)
                v |= entries[j]->flags;
-             for (j=i; j<static_count && entries[j]->value == entries[i]->value; j++)
+
+             for (j = i; j < static_count && entries[j]->value == entries[i]->value; j++)
                entries[j]->flags = v;
-             i = j-1;
+
+             i = j - 1;
            }
       }
 
@@ -2098,10 +3058,9 @@ mn10300_elf_relax_section (abfd, sec, link_info, again)
              if (section->reloc_count != 0)
                {
                  /* Get a copy of the native relocations.  */
-                 internal_relocs = (_bfd_elf_link_read_relocs
-                                    (input_bfd, section, (PTR) NULL,
-                                     (Elf_Internal_Rela *) NULL,
-                                     link_info->keep_memory));
+                 internal_relocs = _bfd_elf_link_read_relocs (input_bfd, section,
+                                                              NULL, NULL,
+                                                              link_info->keep_memory);
                  if (internal_relocs == NULL)
                    goto error_return;
                }
@@ -2154,15 +3113,15 @@ mn10300_elf_relax_section (abfd, sec, link_info, again)
                     local symbol in the global hash table.  */
                  amt = strlen (sym_name) + 10;
                  new_name = bfd_malloc (amt);
-                 if (new_name == 0)
+                 if (new_name == NULL)
                    goto error_return;
                  sprintf (new_name, "%s_%08x", sym_name, sym_sec->id);
                  sym_name = new_name;
 
-                 elftab = &hash_table->static_hash_table->root;
-                 sym_hash = ((struct elf32_mn10300_link_hash_entry *)
-                             elf_link_hash_lookup (elftab, sym_name,
-                                                   FALSE, FALSE, FALSE));
+                 elftab = & hash_table->static_hash_table->root;
+                 sym_hash = (struct elf32_mn10300_link_hash_entry *)
+                   elf_link_hash_lookup (elftab, sym_name,
+                                         FALSE, FALSE, FALSE);
 
                  free (new_name);
                  if (sym_hash == NULL)
@@ -2226,6 +3185,7 @@ mn10300_elf_relax_section (abfd, sec, link_info, again)
                    {
                      int bytes = 0;
                      bfd_vma symval;
+                     struct elf_link_hash_entry **hh;
 
                      /* Note that we've changed things.  */
                      elf_section_data (section)->relocs = internal_relocs;
@@ -2256,6 +3216,25 @@ mn10300_elf_relax_section (abfd, sec, link_info, again)
                                                           bytes))
                        goto error_return;
 
+                     /* There may be other C++ functions symbols with the same
+                        address.  If so then mark these as having had their
+                        prologue bytes deleted as well.  */
+                     for (hh = elf_sym_hashes (input_bfd); hh < end_hashes; hh++)
+                       {
+                         struct elf32_mn10300_link_hash_entry *h;
+
+                         h = (struct elf32_mn10300_link_hash_entry *) * hh;
+
+                         if (h != sym_hash
+                             && (h->root.root.type == bfd_link_hash_defined
+                                 || h->root.root.type == bfd_link_hash_defweak)
+                             && h->root.root.u.def.section == section
+                             && ! (h->flags & MN10300_CONVERT_CALL_TO_CALLS)
+                             && h->root.root.u.def.value == symval
+                             && h->root.type == STT_FUNC)
+                           h->flags |= MN10300_DELETED_PROLOGUE_BYTES;
+                       }
+
                      /* Something changed.  Not strictly necessary, but
                         may lead to more relaxing opportunities.  */
                      *again = TRUE;
@@ -2275,10 +3254,8 @@ mn10300_elf_relax_section (abfd, sec, link_info, again)
                  if (! link_info->keep_memory)
                    free (contents);
                  else
-                   {
-                     /* Cache the section contents for elf_link_input_bfd.  */
-                     elf_section_data (section)->this_hdr.contents = contents;
-                   }
+                   /* Cache the section contents for elf_link_input_bfd.  */
+                   elf_section_data (section)->this_hdr.contents = contents;
                }
              contents = NULL;
            }
@@ -2290,10 +3267,8 @@ mn10300_elf_relax_section (abfd, sec, link_info, again)
              if (! link_info->keep_memory)
                free (isymbuf);
              else
-               {
-                 /* Cache the symbols for elf_link_input_bfd.  */
-                 symtab_hdr->contents = (unsigned char *) isymbuf;
-               }
+               /* Cache the symbols for elf_link_input_bfd.  */
+               symtab_hdr->contents = (unsigned char *) isymbuf;
            }
          isymbuf = NULL;
        }
@@ -2318,17 +3293,45 @@ mn10300_elf_relax_section (abfd, sec, link_info, again)
   symtab_hdr = &elf_tdata (abfd)->symtab_hdr;
 
   /* Get a copy of the native relocations.  */
-  internal_relocs = (_bfd_elf_link_read_relocs
-                    (abfd, sec, (PTR) NULL, (Elf_Internal_Rela *) NULL,
-                     link_info->keep_memory));
+  internal_relocs = _bfd_elf_link_read_relocs (abfd, sec, NULL, NULL,
+                                              link_info->keep_memory);
   if (internal_relocs == NULL)
     goto error_return;
 
+  /* Scan for worst case alignment gap changes.  Note that this logic
+     is not ideal; what we should do is run this scan for every
+     opcode/address range and adjust accordingly, but that's
+     expensive.  Worst case is that for an alignment of N bytes, we
+     move by 2*N-N-1 bytes, assuming we have aligns of 1, 2, 4, 8, etc
+     all before it.  Plus, this still doesn't cover cross-section
+     jumps with section alignment.  */
+  irelend = internal_relocs + sec->reloc_count;
+  align_gap_adjustment = 0;
+  for (irel = internal_relocs; irel < irelend; irel++)
+    {
+      if (ELF32_R_TYPE (irel->r_info) == (int) R_MN10300_ALIGN)
+       {
+         bfd_vma adj = 1 << irel->r_addend;
+         bfd_vma aend = irel->r_offset;
+
+         aend = BFD_ALIGN (aend, 1 << irel->r_addend);
+         adj = 2 * adj - adj - 1;
+
+         /* Record the biggest adjustmnet.  Skip any alignment at the
+            end of our section.  */
+         if (align_gap_adjustment < adj
+             && aend < sec->output_section->vma + sec->output_offset + sec->size)
+           align_gap_adjustment = adj;
+       }
+    }
+
   /* Walk through them looking for relaxing opportunities.  */
   irelend = internal_relocs + sec->reloc_count;
   for (irel = internal_relocs; irel < irelend; irel++)
     {
       bfd_vma symval;
+      bfd_signed_vma jump_offset;
+      asection *sym_sec = NULL;
       struct elf32_mn10300_link_hash_entry *h = NULL;
 
       /* If this isn't something that can be relaxed, then ignore
@@ -2368,10 +3371,8 @@ mn10300_elf_relax_section (abfd, sec, link_info, again)
       if (ELF32_R_SYM (irel->r_info) < symtab_hdr->sh_info)
        {
          Elf_Internal_Sym *isym;
-         asection *sym_sec = NULL;
          const char *sym_name;
          char *new_name;
-         bfd_vma saved_addend;
 
          /* A local symbol.  */
          isym = isymbuf + ELF32_R_SYM (irel->r_info);
@@ -2389,24 +3390,42 @@ mn10300_elf_relax_section (abfd, sec, link_info, again)
                                                      isym->st_name);
 
          if ((sym_sec->flags & SEC_MERGE)
-             && ELF_ST_TYPE (isym->st_info) == STT_SECTION
              && sym_sec->sec_info_type == ELF_INFO_TYPE_MERGE)
            {
-             saved_addend = irel->r_addend;
-             symval = _bfd_elf_rela_local_sym (abfd, isym, &sym_sec, irel);
-             symval += irel->r_addend;
-             irel->r_addend = saved_addend;
+             symval = isym->st_value;
+
+             /* GAS may reduce relocations against symbols in SEC_MERGE
+                sections to a relocation against the section symbol when
+                the original addend was zero.  When the reloc is against
+                a section symbol we should include the addend in the
+                offset passed to _bfd_merged_section_offset, since the
+                location of interest is the original symbol.  On the
+                other hand, an access to "sym+addend" where "sym" is not
+                a section symbol should not include the addend;  Such an
+                access is presumed to be an offset from "sym";  The
+                location of interest is just "sym".  */
+             if (ELF_ST_TYPE (isym->st_info) == STT_SECTION)
+               symval += irel->r_addend;
+
+             symval = _bfd_merged_section_offset (abfd, & sym_sec,
+                                                  elf_section_data (sym_sec)->sec_info,
+                                                  symval);
+
+             if (ELF_ST_TYPE (isym->st_info) != STT_SECTION)
+               symval += irel->r_addend;
+
+             symval += sym_sec->output_section->vma
+               + sym_sec->output_offset - irel->r_addend;
            }
          else
-           {
-             symval = (isym->st_value
-                       + sym_sec->output_section->vma
-                       + sym_sec->output_offset);
-           }
+           symval = (isym->st_value
+                     + sym_sec->output_section->vma
+                     + sym_sec->output_offset);
+
          /* Tack on an ID so we can uniquely identify this
             local symbol in the global hash table.  */
          new_name = bfd_malloc ((bfd_size_type) strlen (sym_name) + 10);
-         if (new_name == 0)
+         if (new_name == NULL)
            goto error_return;
          sprintf (new_name, "%s_%08x", sym_name, sym_sec->id);
          sym_name = new_name;
@@ -2427,12 +3446,16 @@ mn10300_elf_relax_section (abfd, sec, link_info, again)
          BFD_ASSERT (h != NULL);
          if (h->root.root.type != bfd_link_hash_defined
              && h->root.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;
-           }
+           /* This appears to be a reference to an undefined
+              symbol.  Just ignore it--it will be caught by the
+              regular reloc processing.  */
+           continue;
+
+         /* Check for a reference to a discarded symbol and ignore it.  */
+         if (h->root.root.u.def.section->output_section == NULL)
+           continue;
+
+         sym_sec = h->root.root.u.def.section->output_section;
 
          symval = (h->root.root.u.def.value
                    + h->root.root.u.def.section->output_section->vma
@@ -2536,8 +3559,16 @@ mn10300_elf_relax_section (abfd, sec, link_info, again)
 
          /* See if the value will fit in 16 bits, note the high value is
             0x7fff + 2 as the target will be two bytes closer if we are
-            able to relax.  */
-         if ((long) value < 0x8001 && (long) value > -0x8000)
+            able to relax, if it's in the same section.  */
+         if (sec->output_section == sym_sec->output_section)
+           jump_offset = 0x8001;
+         else
+           jump_offset = 0x7fff;
+
+         /* Account for jumps across alignment boundaries using
+            align_gap_adjustment.  */
+         if ((bfd_signed_vma) value < jump_offset - (bfd_signed_vma) align_gap_adjustment
+             && ((bfd_signed_vma) value > -0x8000 + (bfd_signed_vma) align_gap_adjustment))
            {
              unsigned char code;
 
@@ -3142,7 +4173,7 @@ mn10300_elf_relax_section (abfd, sec, link_info, again)
                  case 0x93:
                    /* sp-based offsets are zero-extended.  */
                    if (code >= 0x90 && code <= 0x93
-                       && (long)value < 0)
+                       && (long) value < 0)
                      continue;
 
                    /* Note that we've changed the relocation contents, etc.  */
@@ -3197,9 +4228,9 @@ mn10300_elf_relax_section (abfd, sec, link_info, again)
                        && (value & 0x8000))
                      continue;
 
-                   /* mov imm16, an zero-extends the immediate.  */
-                   if (code == 0xdc
-                       && (long)value < 0)
+                   /* "mov imm16, an" zero-extends the immediate.  */
+                   if ((code & 0xfc) == 0xdc
+                       && (long) value < 0)
                      continue;
 
                    /* Note that we've changed the relocation contents, etc.  */
@@ -3280,12 +4311,12 @@ mn10300_elf_relax_section (abfd, sec, link_info, again)
                  case 0xe3:
                    /* cmp imm16, an zero-extends the immediate.  */
                    if (code == 0xdc
-                       && (long)value < 0)
+                       && (long) value < 0)
                      continue;
 
                    /* So do sp-based offsets.  */
                    if (code >= 0xb0 && code <= 0xb3
-                       && (long)value < 0)
+                       && (long) value < 0)
                      continue;
 
                    /* Note that we've changed the relocation contents, etc.  */
@@ -3404,242 +4435,16 @@ mn10300_elf_relax_section (abfd, sec, link_info, again)
   return FALSE;
 }
 
-/* Compute the stack size and movm arguments for the function
-   referred to by HASH at address ADDR in section with
-   contents CONTENTS, store the information in the hash table.  */
-static void
-compute_function_info (abfd, hash, addr, contents)
-     bfd *abfd;
-     struct elf32_mn10300_link_hash_entry *hash;
-     bfd_vma addr;
-     unsigned char *contents;
-{
-  unsigned char byte1, byte2;
-  /* We only care about a very small subset of the possible prologue
-     sequences here.  Basically we look for:
-
-     movm [d2,d3,a2,a3],sp (optional)
-     add <size>,sp (optional, and only for sizes which fit in an unsigned
-                   8 bit number)
-
-     If we find anything else, we quit.  */
-
-  /* Look for movm [regs],sp */
-  byte1 = bfd_get_8 (abfd, contents + addr);
-  byte2 = bfd_get_8 (abfd, contents + addr + 1);
-
-  if (byte1 == 0xcf)
-    {
-      hash->movm_args = byte2;
-      addr += 2;
-      byte1 = bfd_get_8 (abfd, contents + addr);
-      byte2 = bfd_get_8 (abfd, contents + addr + 1);
-    }
-
-  /* Now figure out how much stack space will be allocated by the movm
-     instruction.  We need this kept separate from the function's normal
-     stack space.  */
-  if (hash->movm_args)
-    {
-      /* Space for d2.  */
-      if (hash->movm_args & 0x80)
-       hash->movm_stack_size += 4;
-
-      /* Space for d3.  */
-      if (hash->movm_args & 0x40)
-       hash->movm_stack_size += 4;
-
-      /* Space for a2.  */
-      if (hash->movm_args & 0x20)
-       hash->movm_stack_size += 4;
-
-      /* Space for a3.  */
-      if (hash->movm_args & 0x10)
-       hash->movm_stack_size += 4;
-
-      /* "other" space.  d0, d1, a0, a1, mdr, lir, lar, 4 byte pad.  */
-      if (hash->movm_args & 0x08)
-       hash->movm_stack_size += 8 * 4;
-
-      if (bfd_get_mach (abfd) == bfd_mach_am33
-         || bfd_get_mach (abfd) == bfd_mach_am33_2)
-       {
-         /* "exother" space.  e0, e1, mdrq, mcrh, mcrl, mcvf */
-         if (hash->movm_args & 0x1)
-           hash->movm_stack_size += 6 * 4;
-
-         /* exreg1 space.  e4, e5, e6, e7 */
-         if (hash->movm_args & 0x2)
-           hash->movm_stack_size += 4 * 4;
-
-         /* exreg0 space.  e2, e3  */
-         if (hash->movm_args & 0x4)
-           hash->movm_stack_size += 2 * 4;
-       }
-    }
-
-  /* Now look for the two stack adjustment variants.  */
-  if (byte1 == 0xf8 && byte2 == 0xfe)
-    {
-      int temp = bfd_get_8 (abfd, contents + addr + 2);
-      temp = ((temp & 0xff) ^ (~0x7f)) + 0x80;
-
-      hash->stack_size = -temp;
-    }
-  else if (byte1 == 0xfa && byte2 == 0xfe)
-    {
-      int temp = bfd_get_16 (abfd, contents + addr + 2);
-      temp = ((temp & 0xffff) ^ (~0x7fff)) + 0x8000;
-      temp = -temp;
-
-      if (temp < 255)
-       hash->stack_size = temp;
-    }
-
-  /* If the total stack to be allocated by the call instruction is more
-     than 255 bytes, then we can't remove the stack adjustment by using
-     "call" (we might still be able to remove the "movm" instruction.  */
-  if (hash->stack_size + hash->movm_stack_size > 255)
-    hash->stack_size = 0;
-
-  return;
-}
-
-/* Delete some bytes from a section while relaxing.  */
-
-static bfd_boolean
-mn10300_elf_relax_delete_bytes (abfd, sec, addr, count)
-     bfd *abfd;
-     asection *sec;
-     bfd_vma addr;
-     int count;
-{
-  Elf_Internal_Shdr *symtab_hdr;
-  unsigned int sec_shndx;
-  bfd_byte *contents;
-  Elf_Internal_Rela *irel, *irelend;
-  Elf_Internal_Rela *irelalign;
-  bfd_vma toaddr;
-  Elf_Internal_Sym *isym, *isymend;
-  struct elf_link_hash_entry **sym_hashes;
-  struct elf_link_hash_entry **end_hashes;
-  unsigned int symcount;
-
-  sec_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->size;
-
-  irel = elf_section_data (sec)->relocs;
-  irelend = irel + sec->reloc_count;
-
-  /* Actually delete the bytes.  */
-  memmove (contents + addr, contents + addr + count,
-          (size_t) (toaddr - addr - count));
-  sec->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.  */
-  symtab_hdr = &elf_tdata (abfd)->symtab_hdr;
-  isym = (Elf_Internal_Sym *) symtab_hdr->contents;
-  for (isymend = isym + symtab_hdr->sh_info; isym < isymend; isym++)
-    {
-      if (isym->st_shndx == sec_shndx
-         && isym->st_value > addr
-         && isym->st_value < toaddr)
-       isym->st_value -= count;
-    }
-
-  /* Now adjust the global symbols defined in this section.  */
-  symcount = (symtab_hdr->sh_size / sizeof (Elf32_External_Sym)
-             - symtab_hdr->sh_info);
-  sym_hashes = elf_sym_hashes (abfd);
-  end_hashes = sym_hashes + symcount;
-  for (; sym_hashes < end_hashes; sym_hashes++)
-    {
-      struct elf_link_hash_entry *sym_hash = *sym_hashes;
-      if ((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;
-}
-
-/* Return TRUE if a symbol exists at the given address, else return
-   FALSE.  */
-static bfd_boolean
-mn10300_elf_symbol_address_p (abfd, sec, isym, addr)
-     bfd *abfd;
-     asection *sec;
-     Elf_Internal_Sym *isym;
-     bfd_vma addr;
-{
-  Elf_Internal_Shdr *symtab_hdr;
-  unsigned int sec_shndx;
-  Elf_Internal_Sym *isymend;
-  struct elf_link_hash_entry **sym_hashes;
-  struct elf_link_hash_entry **end_hashes;
-  unsigned int symcount;
-
-  sec_shndx = _bfd_elf_section_from_bfd_section (abfd, sec);
-
-  /* Examine all the symbols.  */
-  symtab_hdr = &elf_tdata (abfd)->symtab_hdr;
-  for (isymend = isym + symtab_hdr->sh_info; isym < isymend; isym++)
-    {
-      if (isym->st_shndx == sec_shndx
-         && isym->st_value == addr)
-       return TRUE;
-    }
-
-  symcount = (symtab_hdr->sh_size / sizeof (Elf32_External_Sym)
-             - symtab_hdr->sh_info);
-  sym_hashes = elf_sym_hashes (abfd);
-  end_hashes = sym_hashes + symcount;
-  for (; sym_hashes < end_hashes; sym_hashes++)
-    {
-      struct elf_link_hash_entry *sym_hash = *sym_hashes;
-      if ((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)
-       return TRUE;
-    }
-
-  return FALSE;
-}
-
 /* This is a version of bfd_generic_get_relocated_section_contents
    which uses mn10300_elf_relocate_section.  */
 
 static bfd_byte *
-mn10300_elf_get_relocated_section_contents (output_bfd, link_info, link_order,
-                                           data, relocatable, symbols)
-     bfd *output_bfd;
-     struct bfd_link_info *link_info;
-     struct bfd_link_order *link_order;
-     bfd_byte *data;
-     bfd_boolean relocatable;
-     asymbol **symbols;
+mn10300_elf_get_relocated_section_contents (bfd *output_bfd,
+                                           struct bfd_link_info *link_info,
+                                           struct bfd_link_order *link_order,
+                                           bfd_byte *data,
+                                           bfd_boolean relocatable,
+                                           asymbol **symbols)
 {
   Elf_Internal_Shdr *symtab_hdr;
   asection *input_section = link_order->u.indirect.section;
@@ -3669,9 +4474,8 @@ mn10300_elf_get_relocated_section_contents (output_bfd, link_info, link_order,
       Elf_Internal_Sym *isym, *isymend;
       bfd_size_type amt;
 
-      internal_relocs = (_bfd_elf_link_read_relocs
-                        (input_bfd, input_section, (PTR) NULL,
-                         (Elf_Internal_Rela *) NULL, FALSE));
+      internal_relocs = _bfd_elf_link_read_relocs (input_bfd, input_section,
+                                                  NULL, NULL, FALSE);
       if (internal_relocs == NULL)
        goto error_return;
 
@@ -3688,7 +4492,7 @@ mn10300_elf_get_relocated_section_contents (output_bfd, link_info, link_order,
 
       amt = symtab_hdr->sh_info;
       amt *= sizeof (asection *);
-      sections = (asection **) bfd_malloc (amt);
+      sections = bfd_malloc (amt);
       if (sections == NULL && amt != 0)
        goto error_return;
 
@@ -3710,8 +4514,8 @@ mn10300_elf_get_relocated_section_contents (output_bfd, link_info, link_order,
        }
 
       if (! mn10300_elf_relocate_section (output_bfd, link_info, input_bfd,
-                                    input_section, data, internal_relocs,
-                                    isymbuf, sections))
+                                         input_section, data, internal_relocs,
+                                         isymbuf, sections))
        goto error_return;
 
       if (sections != NULL)
@@ -3742,28 +4546,26 @@ mn10300_elf_get_relocated_section_contents (output_bfd, link_info, link_order,
 /* Create an entry in an MN10300 ELF linker hash table.  */
 
 static struct bfd_hash_entry *
-elf32_mn10300_link_hash_newfunc (entry, table, string)
-     struct bfd_hash_entry *entry;
-     struct bfd_hash_table *table;
-     const char *string;
+elf32_mn10300_link_hash_newfunc (struct bfd_hash_entry *entry,
+                                struct bfd_hash_table *table,
+                                const char *string)
 {
   struct elf32_mn10300_link_hash_entry *ret =
     (struct elf32_mn10300_link_hash_entry *) entry;
 
   /* Allocate the structure if it has not already been allocated by a
      subclass.  */
-  if (ret == (struct elf32_mn10300_link_hash_entry *) NULL)
-    ret = ((struct elf32_mn10300_link_hash_entry *)
-          bfd_hash_allocate (table,
-                             sizeof (struct elf32_mn10300_link_hash_entry)));
-  if (ret == (struct elf32_mn10300_link_hash_entry *) NULL)
+  if (ret == NULL)
+    ret = (struct elf32_mn10300_link_hash_entry *)
+          bfd_hash_allocate (table, sizeof (* ret));
+  if (ret == NULL)
     return (struct bfd_hash_entry *) ret;
 
   /* Call the allocation method of the superclass.  */
-  ret = ((struct elf32_mn10300_link_hash_entry *)
+  ret = (struct elf32_mn10300_link_hash_entry *)
         _bfd_elf_link_hash_newfunc ((struct bfd_hash_entry *) ret,
-                                    table, string));
-  if (ret != (struct elf32_mn10300_link_hash_entry *) NULL)
+                                    table, string);
+  if (ret != NULL)
     {
       ret->direct_calls = 0;
       ret->stack_size = 0;
@@ -3771,36 +4573,67 @@ elf32_mn10300_link_hash_newfunc (entry, table, string)
       ret->movm_stack_size = 0;
       ret->flags = 0;
       ret->value = 0;
+      ret->tls_type = GOT_UNKNOWN;
     }
 
   return (struct bfd_hash_entry *) ret;
 }
 
+static void
+_bfd_mn10300_copy_indirect_symbol (struct bfd_link_info *        info,
+                                  struct elf_link_hash_entry *  dir,
+                                  struct elf_link_hash_entry *  ind)
+{
+  struct elf32_mn10300_link_hash_entry * edir;
+  struct elf32_mn10300_link_hash_entry * eind;
+
+  edir = elf_mn10300_hash_entry (dir);
+  eind = elf_mn10300_hash_entry (ind);
+
+  if (ind->root.type == bfd_link_hash_indirect
+      && dir->got.refcount <= 0)
+    {
+      edir->tls_type = eind->tls_type;
+      eind->tls_type = GOT_UNKNOWN;
+    }
+  edir->direct_calls = eind->direct_calls;
+  edir->stack_size = eind->stack_size;
+  edir->movm_args = eind->movm_args;
+  edir->movm_stack_size = eind->movm_stack_size;
+  edir->flags = eind->flags;
+
+  _bfd_elf_link_hash_copy_indirect (info, dir, ind);
+}
+
 /* Create an mn10300 ELF linker hash table.  */
 
 static struct bfd_link_hash_table *
-elf32_mn10300_link_hash_table_create (abfd)
-     bfd *abfd;
+elf32_mn10300_link_hash_table_create (bfd *abfd)
 {
   struct elf32_mn10300_link_hash_table *ret;
-  bfd_size_type amt = sizeof (struct elf32_mn10300_link_hash_table);
+  bfd_size_type amt = sizeof (* ret);
 
-  ret = (struct elf32_mn10300_link_hash_table *) bfd_malloc (amt);
-  if (ret == (struct elf32_mn10300_link_hash_table *) NULL)
+  ret = bfd_malloc (amt);
+  if (ret == NULL)
     return NULL;
 
   if (!_bfd_elf_link_hash_table_init (&ret->root, abfd,
                                      elf32_mn10300_link_hash_newfunc,
-                                     sizeof (struct elf32_mn10300_link_hash_entry)))
+                                     sizeof (struct elf32_mn10300_link_hash_entry),
+                                     MN10300_ELF_DATA))
     {
       free (ret);
       return NULL;
     }
 
   ret->flags = 0;
+  ret->tls_ldm_got.refcount = 0;
+  ret->tls_ldm_got.offset = -1;
+  ret->tls_ldm_got.got_allocated = 0;
+  ret->tls_ldm_got.rel_emitted = 0;
+
   amt = sizeof (struct elf_link_hash_table);
-  ret->static_hash_table
-    = (struct elf32_mn10300_link_hash_table *) bfd_malloc (amt);
+  ret->static_hash_table = bfd_malloc (amt);
   if (ret->static_hash_table == NULL)
     {
       free (ret);
@@ -3809,20 +4642,20 @@ elf32_mn10300_link_hash_table_create (abfd)
 
   if (!_bfd_elf_link_hash_table_init (&ret->static_hash_table->root, abfd,
                                      elf32_mn10300_link_hash_newfunc,
-                                     sizeof (struct elf32_mn10300_link_hash_entry)))
+                                     sizeof (struct elf32_mn10300_link_hash_entry),
+                                     MN10300_ELF_DATA))
     {
       free (ret->static_hash_table);
       free (ret);
       return NULL;
     }
-  return &ret->root.root;
+  return & ret->root.root;
 }
 
 /* Free an mn10300 ELF linker hash table.  */
 
 static void
-elf32_mn10300_link_hash_table_free (hash)
-     struct bfd_link_hash_table *hash;
+elf32_mn10300_link_hash_table_free (struct bfd_link_hash_table *hash)
 {
   struct elf32_mn10300_link_hash_table *ret
     = (struct elf32_mn10300_link_hash_table *) hash;
@@ -3834,8 +4667,7 @@ elf32_mn10300_link_hash_table_free (hash)
 }
 
 static unsigned long
-elf_mn10300_mach (flags)
-     flagword flags;
+elf_mn10300_mach (flagword flags)
 {
   switch (flags & EF_MN10300_MACH)
     {
@@ -3855,10 +4687,9 @@ elf_mn10300_mach (flags)
    file.  This gets the MN10300 architecture right based on the machine
    number.  */
 
-void
-_bfd_mn10300_elf_final_write_processing (abfd, linker)
-     bfd *abfd;
-     bfd_boolean linker ATTRIBUTE_UNUSED;
+static void
+_bfd_mn10300_elf_final_write_processing (bfd *abfd,
+                                        bfd_boolean linker ATTRIBUTE_UNUSED)
 {
   unsigned long val;
 
@@ -3882,9 +4713,8 @@ _bfd_mn10300_elf_final_write_processing (abfd, linker)
   elf_elfheader (abfd)->e_flags |= val;
 }
 
-bfd_boolean
-_bfd_mn10300_elf_object_p (abfd)
-     bfd *abfd;
+static bfd_boolean
+_bfd_mn10300_elf_object_p (bfd *abfd)
 {
   bfd_default_set_arch_mach (abfd, bfd_arch_mn10300,
                             elf_mn10300_mach (elf_elfheader (abfd)->e_flags));
@@ -3894,10 +4724,8 @@ _bfd_mn10300_elf_object_p (abfd)
 /* Merge backend specific data from an object file to the output
    object file when linking.  */
 
-bfd_boolean
-_bfd_mn10300_elf_merge_private_bfd_data (ibfd, obfd)
-     bfd *ibfd;
-     bfd *obfd;
+static bfd_boolean
+_bfd_mn10300_elf_merge_private_bfd_data (bfd *ibfd, bfd *obfd)
 {
   if (bfd_get_flavour (ibfd) != bfd_target_elf_flavour
       || bfd_get_flavour (obfd) != bfd_target_elf_flavour)
@@ -3914,9 +4742,9 @@ _bfd_mn10300_elf_merge_private_bfd_data (ibfd, obfd)
   return TRUE;
 }
 
-#define PLT0_ENTRY_SIZE 15
-#define PLT_ENTRY_SIZE 20
-#define PIC_PLT_ENTRY_SIZE 24
+#define PLT0_ENTRY_SIZE     15
+#define PLT_ENTRY_SIZE      20
+#define PIC_PLT_ENTRY_SIZE  24
 
 static const bfd_byte elf_mn10300_plt0_entry[PLT0_ENTRY_SIZE] =
 {
@@ -3960,7 +4788,7 @@ static const bfd_byte elf_mn10300_pic_plt_entry[PIC_PLT_ENTRY_SIZE] =
 /* Return offset of the GOT id in PLT0 entry.  */
 #define elf_mn10300_plt0_gotid_offset(info) 9
 
-/* Return offset of the temporary in PLT entry */
+/* Return offset of the temporary in PLT entry */
 #define elf_mn10300_plt_temp_offset(info) 8
 
 /* Return offset of the symbol in PLT entry.  */
@@ -3977,9 +4805,7 @@ static const bfd_byte elf_mn10300_pic_plt_entry[PIC_PLT_ENTRY_SIZE] =
 /* Create dynamic sections when linking against a dynamic object.  */
 
 static bfd_boolean
-_bfd_mn10300_elf_create_dynamic_sections (abfd, info)
-     bfd *abfd;
-     struct bfd_link_info *info;
+_bfd_mn10300_elf_create_dynamic_sections (bfd *abfd, struct bfd_link_info *info)
 {
   flagword   flags;
   asection * s;
@@ -4003,7 +4829,6 @@ _bfd_mn10300_elf_create_dynamic_sections (abfd, info)
 
   /* We need to create .plt, .rel[a].plt, .got, .got.plt, .dynbss, and
      .rel[a].bss sections.  */
-
   flags = (SEC_ALLOC | SEC_LOAD | SEC_HAS_CONTENTS | SEC_IN_MEMORY
           | SEC_LINKER_CREATED);
 
@@ -4032,7 +4857,7 @@ _bfd_mn10300_elf_create_dynamic_sections (abfd, info)
          continue;
 
        secname = bfd_get_section_name (abfd, sec);
-       relname = (char *) bfd_malloc (strlen (secname) + 6);
+       relname = bfd_malloc (strlen (secname) + 6);
        strcpy (relname, ".rela");
        strcat (relname, secname);
 
@@ -4090,9 +4915,8 @@ _bfd_mn10300_elf_create_dynamic_sections (abfd, info)
    understand.  */
 
 static bfd_boolean
-_bfd_mn10300_elf_adjust_dynamic_symbol (info, h)
-     struct bfd_link_info * info;
-     struct elf_link_hash_entry * h;
+_bfd_mn10300_elf_adjust_dynamic_symbol (struct bfd_link_info * info,
+                                       struct elf_link_hash_entry * h)
 {
   bfd * dynobj;
   asection * s;
@@ -4160,13 +4984,11 @@ _bfd_mn10300_elf_adjust_dynamic_symbol (info, h)
 
       /* We also need to make an entry in the .got.plt section, which
         will be placed in the .got section by the linker script.  */
-
       s = bfd_get_section_by_name (dynobj, ".got.plt");
       BFD_ASSERT (s != NULL);
       s->size += 4;
 
       /* We also need to make an entry in the .rela.plt section.  */
-
       s = bfd_get_section_by_name (dynobj, ".rela.plt");
       BFD_ASSERT (s != NULL);
       s->size += sizeof (Elf32_External_Rela);
@@ -4241,10 +5063,10 @@ _bfd_mn10300_elf_adjust_dynamic_symbol (info, h)
 /* Set the sizes of the dynamic sections.  */
 
 static bfd_boolean
-_bfd_mn10300_elf_size_dynamic_sections (output_bfd, info)
-     bfd * output_bfd;
-     struct bfd_link_info * info;
+_bfd_mn10300_elf_size_dynamic_sections (bfd * output_bfd,
+                                       struct bfd_link_info * info)
 {
+  struct elf32_mn10300_link_hash_table *htab = elf32_mn10300_hash_table (info);
   bfd * dynobj;
   asection * s;
   bfd_boolean plt;
@@ -4277,6 +5099,13 @@ _bfd_mn10300_elf_size_dynamic_sections (output_bfd, info)
        s->size = 0;
     }
 
+  if (htab->tls_ldm_got.refcount > 0)
+    {
+      s = bfd_get_section_by_name (dynobj, ".rela.got");
+      BFD_ASSERT (s != NULL);
+      s->size += sizeof (Elf32_External_Rela);
+    }
+
   /* The check_relocs and adjust_dynamic_symbol entry points have
      determined the sizes of the various dynamic sections.  Allocate
      memory for them.  */
@@ -4294,7 +5123,7 @@ _bfd_mn10300_elf_size_dynamic_sections (output_bfd, info)
         of the dynobj section names depend upon the input files.  */
       name = bfd_get_section_name (dynobj, s);
 
-      if (strcmp (name, ".plt") == 0)
+      if (streq (name, ".plt"))
        {
          /* Remember whether there is a PLT.  */
          plt = s->size != 0;
@@ -4307,7 +5136,7 @@ _bfd_mn10300_elf_size_dynamic_sections (output_bfd, info)
 
              /* Remember whether there are any reloc sections other
                 than .rela.plt.  */
-             if (strcmp (name, ".rela.plt") != 0)
+             if (! streq (name, ".rela.plt"))
                {
                  const char * outname;
 
@@ -4333,7 +5162,7 @@ _bfd_mn10300_elf_size_dynamic_sections (output_bfd, info)
            }
        }
       else if (! CONST_STRNEQ (name, ".got")
-              && strcmp (name, ".dynbss") != 0)
+              && ! streq (name, ".dynbss"))
        /* It's not one of our sections, so don't allocate space.  */
        continue;
 
@@ -4360,7 +5189,7 @@ _bfd_mn10300_elf_size_dynamic_sections (output_bfd, info)
         section's contents are written out.  This should not happen,
         but this way if it does, we get a R_MN10300_NONE reloc
         instead of garbage.  */
-      s->contents = (bfd_byte *) bfd_zalloc (dynobj, s->size);
+      s->contents = bfd_zalloc (dynobj, s->size);
       if (s->contents == NULL)
        return FALSE;
     }
@@ -4410,11 +5239,10 @@ _bfd_mn10300_elf_size_dynamic_sections (output_bfd, info)
    dynamic sections here.  */
 
 static bfd_boolean
-_bfd_mn10300_elf_finish_dynamic_symbol (output_bfd, info, h, sym)
-     bfd * output_bfd;
-     struct bfd_link_info * info;
-     struct elf_link_hash_entry * h;
-     Elf_Internal_Sym * sym;
+_bfd_mn10300_elf_finish_dynamic_symbol (bfd * output_bfd,
+                                       struct bfd_link_info * info,
+                                       struct elf_link_hash_entry * h,
+                                       Elf_Internal_Sym * sym)
 {
   bfd * dynobj;
 
@@ -4513,40 +5341,72 @@ _bfd_mn10300_elf_finish_dynamic_symbol (output_bfd, info, h, sym)
       Elf_Internal_Rela rel;
 
       /* This symbol has an entry in the global offset table.  Set it up.  */
-
       sgot = bfd_get_section_by_name (dynobj, ".got");
       srel = bfd_get_section_by_name (dynobj, ".rela.got");
       BFD_ASSERT (sgot != NULL && srel != NULL);
 
       rel.r_offset = (sgot->output_section->vma
                      + sgot->output_offset
-                     + (h->got.offset &1));
+                     + (h->got.offset & ~1));
 
-      /* If this is a -Bsymbolic link, and the symbol is defined
-        locally, we just want to emit a RELATIVE reloc.  Likewise if
-        the symbol was forced to be local because of a version file.
-        The entry in the global offset table will already have been
-        initialized in the relocate_section function.  */
-      if (info->shared
-         && (info->symbolic || h->dynindx == -1)
-         && h->def_regular)
-       {
-         rel.r_info = ELF32_R_INFO (0, R_MN10300_RELATIVE);
-         rel.r_addend = (h->root.u.def.value
-                         + h->root.u.def.section->output_section->vma
-                         + h->root.u.def.section->output_offset);
-       }
-      else
+      switch (elf_mn10300_hash_entry (h)->tls_type)
        {
+       case GOT_TLS_GD:
          bfd_put_32 (output_bfd, (bfd_vma) 0, sgot->contents + h->got.offset);
-         rel.r_info = ELF32_R_INFO (h->dynindx, R_MN10300_GLOB_DAT);
+         bfd_put_32 (output_bfd, (bfd_vma) 0, sgot->contents + h->got.offset + 4);
+         rel.r_info = ELF32_R_INFO (h->dynindx, R_MN10300_TLS_DTPMOD);
+         rel.r_addend = 0;
+         bfd_elf32_swap_reloca_out (output_bfd, & rel,
+                                    (bfd_byte *) ((Elf32_External_Rela *) srel->contents
+                                                  + srel->reloc_count));
+         ++ srel->reloc_count;
+         rel.r_info = ELF32_R_INFO (h->dynindx, R_MN10300_TLS_DTPOFF);
+         rel.r_offset += 4;
          rel.r_addend = 0;
+         break;
+
+       case GOT_TLS_IE:
+         /* We originally stored the addend in the GOT, but at this
+            point, we want to move it to the reloc instead as that's
+            where the dynamic linker wants it.  */
+         rel.r_addend = bfd_get_32 (output_bfd, sgot->contents + h->got.offset);
+         bfd_put_32 (output_bfd, (bfd_vma) 0, sgot->contents + h->got.offset);
+         if (h->dynindx == -1)
+           rel.r_info = ELF32_R_INFO (0, R_MN10300_TLS_TPOFF);
+         else
+           rel.r_info = ELF32_R_INFO (h->dynindx, R_MN10300_TLS_TPOFF);
+         break;
+
+       default:
+         /* If this is a -Bsymbolic link, and the symbol is defined
+            locally, we just want to emit a RELATIVE reloc.  Likewise if
+            the symbol was forced to be local because of a version file.
+            The entry in the global offset table will already have been
+            initialized in the relocate_section function.  */
+         if (info->shared
+             && (info->symbolic || h->dynindx == -1)
+             && h->def_regular)
+           {
+             rel.r_info = ELF32_R_INFO (0, R_MN10300_RELATIVE);
+             rel.r_addend = (h->root.u.def.value
+                             + h->root.u.def.section->output_section->vma
+                             + h->root.u.def.section->output_offset);
+           }
+         else
+           {
+             bfd_put_32 (output_bfd, (bfd_vma) 0, sgot->contents + h->got.offset);
+             rel.r_info = ELF32_R_INFO (h->dynindx, R_MN10300_GLOB_DAT);
+             rel.r_addend = 0;
+           }
        }
 
-      bfd_elf32_swap_reloca_out (output_bfd, &rel,
-                                (bfd_byte *) ((Elf32_External_Rela *) srel->contents
-                                              + srel->reloc_count));
-      ++ srel->reloc_count;
+      if (ELF32_R_TYPE (rel.r_info) != R_MN10300_NONE)
+       {
+         bfd_elf32_swap_reloca_out (output_bfd, &rel,
+                                    (bfd_byte *) ((Elf32_External_Rela *) srel->contents
+                                                  + srel->reloc_count));
+         ++ srel->reloc_count;
+       }
     }
 
   if (h->needs_copy)
@@ -4568,14 +5428,14 @@ _bfd_mn10300_elf_finish_dynamic_symbol (output_bfd, info, h, sym)
                      + h->root.u.def.section->output_offset);
       rel.r_info = ELF32_R_INFO (h->dynindx, R_MN10300_COPY);
       rel.r_addend = 0;
-      bfd_elf32_swap_reloca_out (output_bfd, &rel,
+      bfd_elf32_swap_reloca_out (output_bfd, & rel,
                                 (bfd_byte *) ((Elf32_External_Rela *) s->contents
                                               + s->reloc_count));
       ++ s->reloc_count;
     }
 
   /* Mark _DYNAMIC and _GLOBAL_OFFSET_TABLE_ as absolute.  */
-  if (strcmp (h->root.root.string, "_DYNAMIC") == 0
+  if (streq (h->root.root.string, "_DYNAMIC")
       || h == elf_hash_table (info)->hgot)
     sym->st_shndx = SHN_ABS;
 
@@ -4585,9 +5445,8 @@ _bfd_mn10300_elf_finish_dynamic_symbol (output_bfd, info, h, sym)
 /* Finish up the dynamic sections.  */
 
 static bfd_boolean
-_bfd_mn10300_elf_finish_dynamic_sections (output_bfd, info)
-     bfd * output_bfd;
-     struct bfd_link_info * info;
+_bfd_mn10300_elf_finish_dynamic_sections (bfd * output_bfd,
+                                         struct bfd_link_info * info)
 {
   bfd *      dynobj;
   asection * sgot;
@@ -4684,6 +5543,14 @@ _bfd_mn10300_elf_finish_dynamic_sections (output_bfd, info)
          /* UnixWare sets the entsize of .plt to 4, although that doesn't
             really seem like the right value.  */
          elf_section_data (splt->output_section)->this_hdr.sh_entsize = 4;
+
+         /* UnixWare sets the entsize of .plt to 4, but this is incorrect
+            as it means that the size of the PLT0 section (15 bytes) is not
+            a multiple of the sh_entsize.  Some ELF tools flag this as an
+            error.  We could pad PLT0 to 16 bytes, but that would introduce
+            compatibilty issues with previous toolchains, so instead we
+            just set the entry size to 1.  */
+         elf_section_data (splt->output_section)->this_hdr.sh_entsize = 1;
        }
     }
 
@@ -4713,21 +5580,29 @@ _bfd_mn10300_elf_reloc_type_class (const Elf_Internal_Rela *rela)
 {
   switch ((int) ELF32_R_TYPE (rela->r_info))
     {
-    case R_MN10300_RELATIVE:
-      return reloc_class_relative;
-    case R_MN10300_JMP_SLOT:
-      return reloc_class_plt;
-    case R_MN10300_COPY:
-      return reloc_class_copy;
-    default:
-      return reloc_class_normal;
+    case R_MN10300_RELATIVE:   return reloc_class_relative;
+    case R_MN10300_JMP_SLOT:   return reloc_class_plt;
+    case R_MN10300_COPY:       return reloc_class_copy;
+    default:                   return reloc_class_normal;
     }
 }
 
+/* Allocate space for an MN10300 extension to the bfd elf data structure.  */
+
+static bfd_boolean
+mn10300_elf_mkobject (bfd *abfd)
+{
+  return bfd_elf_allocate_object (abfd, sizeof (struct elf_mn10300_obj_tdata),
+                                 MN10300_ELF_DATA);
+}
+
+#define bfd_elf32_mkobject     mn10300_elf_mkobject
+
 #ifndef ELF_ARCH
 #define TARGET_LITTLE_SYM      bfd_elf32_mn10300_vec
 #define TARGET_LITTLE_NAME     "elf32-mn10300"
 #define ELF_ARCH               bfd_arch_mn10300
+#define ELF_TARGET_ID          MN10300_ELF_DATA
 #define ELF_MACHINE_CODE       EM_MN10300
 #define ELF_MACHINE_ALT1       EM_CYGNUS_MN10300
 #define ELF_MAXPAGESIZE                0x1000
@@ -4773,7 +5648,8 @@ _bfd_mn10300_elf_reloc_type_class (const Elf_Internal_Rela *rela)
   _bfd_mn10300_elf_finish_dynamic_symbol
 #define elf_backend_finish_dynamic_sections \
   _bfd_mn10300_elf_finish_dynamic_sections
-
+#define elf_backend_copy_indirect_symbol \
+  _bfd_mn10300_copy_indirect_symbol
 #define elf_backend_reloc_type_class \
   _bfd_mn10300_elf_reloc_type_class
 
This page took 0.060382 seconds and 4 git commands to generate.