* mn10300.h (elf_mn10300_reloc_type): Add R_MN10300_TLS_GD,
authorNick Clifton <nickc@redhat.com>
Wed, 7 Mar 2012 17:52:00 +0000 (17:52 +0000)
committerNick Clifton <nickc@redhat.com>
Wed, 7 Mar 2012 17:52:00 +0000 (17:52 +0000)
R_MN10300_TLS_LD, R_MN10300_TLS_LDO, R_MN10300_TLS_GOTIE,
R_MN10300_TLS_IE, R_MN10300_TLS_LE, R_MN10300_TLS_DPTMOD,
R_MN10300_TLS_DTPOFF and R_MN10300_TLS_TPOFF.

* elf-m10300.c (elf32_mn10300_link_hash_entry): Add tls_type
field.
(elf32_mn10300_link_hash_table): Add tls_ldm_got entry;
(elf_mn10300_tdata): Define.
(elf_mn10300_local_got_tls_type): Define.
(elf_mn10300_howto_table): Add entries for R_MN10300_TLS_GD,
R_MN10300_TLS_LD, R_MN10300_TLS_LDO, R_MN10300_TLS_GOTIE,
R_MN10300_TLS_IE, R_MN10300_TLS_LE, R_MN10300_TLS_DPTMOD,
R_MN10300_TLS_DTPOFF, R_MN10300_TLS_TPOFF relocs.
(mn10300_reloc_map): Likewise.
(elf_mn10300_tls_transition): New function.
(dtpoff, tpoff, mn10300_do_tls_transition): New functions.
(mn10300_elf_check_relocs): Add TLS support.
(mn10300_elf_final_link_relocate): Likewise.
(mn10300_elf_relocate_section): Likewise.
(mn10300_elf_relax_section): Likewise.
(elf32_mn10300_link_hash_newfunc): Initialise new field.
(_bfd_mn10300_copy_indirect_symbol): New function.
(elf32_mn10300_link_hash_table_create): Initialise new fields.
(_bfd_mn10300_elf_size_dynamic_sections): Add TLS support.
(_bfd_mn10300_elf_finish_dynamic_symbol): Likewise.
(_bfd_mn10300_elf_reloc_type_class): Allocate an
elf_mn10300_obj_tdata structure.
(elf_backend_copy_indirect_symbol): Define.
* reloc.c (BFD_MN10300_TLS_GD, BFD_MN10300_TLS_LD,
BFD_MN10300_TLS_LDO, BFD_MN10300_TLS_GOTIE, BFD_MN10300_TLS_IE,
BFD_MN10300_TLS_LE, BFD_MN10300_TLS_DPTMOD,
BFD_MN10300_TLS_DTPOFF, BFD_MN10300_TLS_TPOFF): New relocations.
(BFD_RELOC_MN10300_32_PCREL, BFD_RELOC_MN10300_16_PCREL): Move to
alongside other MN10300 relocations.
* bfd-in2.h: Regenerate.
* libbfd.h: Regenerate.

* config/tc-mn10300.c (other_registers): Add SSP and USP.
(md_assemble): Add support for TLS relocs.
(mn10300_parse_name): Likewise.

* readelf.c (is_16bit_abs_reloc): Add detection of R_MN10300_16.

bfd/ChangeLog
bfd/bfd-in2.h
bfd/elf-m10300.c
bfd/libbfd.h
bfd/reloc.c
binutils/ChangeLog
binutils/readelf.c
gas/ChangeLog
gas/config/tc-mn10300.c
include/elf/ChangeLog
include/elf/mn10300.h

index 4a951bb..ce08017 100644 (file)
@@ -1,3 +1,38 @@
+2012-03-07  Nick Clifton  <nickc@redhat.com>
+
+       * elf-m10300.c (elf32_mn10300_link_hash_entry): Add tls_type
+       field.
+       (elf32_mn10300_link_hash_table): Add tls_ldm_got entry;
+       (elf_mn10300_tdata): Define.
+       (elf_mn10300_local_got_tls_type): Define.
+       (elf_mn10300_howto_table): Add entries for R_MN10300_TLS_GD,
+       R_MN10300_TLS_LD, R_MN10300_TLS_LDO, R_MN10300_TLS_GOTIE,
+       R_MN10300_TLS_IE, R_MN10300_TLS_LE, R_MN10300_TLS_DPTMOD,
+       R_MN10300_TLS_DTPOFF, R_MN10300_TLS_TPOFF relocs.
+       (mn10300_reloc_map): Likewise.
+       (elf_mn10300_tls_transition): New function.
+       (dtpoff, tpoff, mn10300_do_tls_transition): New functions.
+       (mn10300_elf_check_relocs): Add TLS support.
+       (mn10300_elf_final_link_relocate): Likewise.
+       (mn10300_elf_relocate_section): Likewise.
+       (mn10300_elf_relax_section): Likewise.
+       (elf32_mn10300_link_hash_newfunc): Initialise new field.
+       (_bfd_mn10300_copy_indirect_symbol): New function.
+       (elf32_mn10300_link_hash_table_create): Initialise new fields.
+       (_bfd_mn10300_elf_size_dynamic_sections): Add TLS support.
+       (_bfd_mn10300_elf_finish_dynamic_symbol): Likewise.
+       (_bfd_mn10300_elf_reloc_type_class): Allocate an
+       elf_mn10300_obj_tdata structure.
+       (elf_backend_copy_indirect_symbol): Define.
+       * reloc.c (BFD_MN10300_TLS_GD, BFD_MN10300_TLS_LD,
+       BFD_MN10300_TLS_LDO, BFD_MN10300_TLS_GOTIE, BFD_MN10300_TLS_IE,
+       BFD_MN10300_TLS_LE, BFD_MN10300_TLS_DPTMOD,
+       BFD_MN10300_TLS_DTPOFF, BFD_MN10300_TLS_TPOFF): New relocations.
+       (BFD_RELOC_MN10300_32_PCREL, BFD_RELOC_MN10300_16_PCREL): Move to
+       alongside other MN10300 relocations.
+       * bfd-in2.h: Regenerate.
+       * libbfd.h: Regenerate.
+
 2012-03-06  Jakub Jelinek  <jakub@redhat.com>
 
        * elf64-x86-64.c (elf_x86_64_relocate_section): For R_X86_64_RELATIVE
 2012-03-06  Jakub Jelinek  <jakub@redhat.com>
 
        * elf64-x86-64.c (elf_x86_64_relocate_section): For R_X86_64_RELATIVE
index 9c77fed..bb43860 100644 (file)
@@ -2963,6 +2963,25 @@ be honoured at the offset's location, regardless of linker
 relaxation.  */
   BFD_RELOC_MN10300_ALIGN,
 
 relaxation.  */
   BFD_RELOC_MN10300_ALIGN,
 
+/* Various TLS-related relocations.  */
+  BFD_RELOC_MN10300_TLS_GD,
+  BFD_RELOC_MN10300_TLS_LD,
+  BFD_RELOC_MN10300_TLS_LDO,
+  BFD_RELOC_MN10300_TLS_GOTIE,
+  BFD_RELOC_MN10300_TLS_IE,
+  BFD_RELOC_MN10300_TLS_LE,
+  BFD_RELOC_MN10300_TLS_DTPMOD,
+  BFD_RELOC_MN10300_TLS_DTPOFF,
+  BFD_RELOC_MN10300_TLS_TPOFF,
+
+/* This is a 32bit pcrel reloc for the mn10300, offset by two bytes in the
+instruction.  */
+  BFD_RELOC_MN10300_32_PCREL,
+
+/* This is a 16bit pcrel reloc for the mn10300, offset by two bytes in the
+instruction.  */
+  BFD_RELOC_MN10300_16_PCREL,
+
 
 /* i386/elf relocations  */
   BFD_RELOC_386_GOT32,
 
 /* i386/elf relocations  */
   BFD_RELOC_386_GOT32,
@@ -3798,14 +3817,6 @@ instructions.  */
 /* start data in text.  */
   BFD_RELOC_V850_DATA,
 
 /* start data in text.  */
   BFD_RELOC_V850_DATA,
 
-/* This is a 32bit pcrel reloc for the mn10300, offset by two bytes in the
-instruction.  */
-  BFD_RELOC_MN10300_32_PCREL,
-
-/* This is a 16bit pcrel reloc for the mn10300, offset by two bytes in the
-instruction.  */
-  BFD_RELOC_MN10300_16_PCREL,
-
 /* This is a 8bit DP reloc for the tms320c30, where the most
 significant 8 bits of a 24 bit word are placed into the least
 significant 8 bits of the opcode.  */
 /* This is a 8bit DP reloc for the tms320c30, where the most
 significant 8 bits of a 24 bit word are placed into the least
 significant 8 bits of the opcode.  */
index fa33b4a..d5e183d 100644 (file)
@@ -69,6 +69,14 @@ struct elf32_mn10300_link_hash_entry
 
   /* Calculated value.  */
   bfd_vma value;
 
   /* 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 derive a hash table from the main elf linker hash table so
@@ -87,8 +95,31 @@ struct elf32_mn10300_link_hash_table
   /* Random linker state flags.  */
 #define MN10300_HASH_ENTRIES_INITIALIZED 0x1
   char flags;
   /* 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
 #ifndef streq
 #define streq(a, b) (strcmp ((a),(b)) == 0)
 #endif
@@ -448,15 +479,131 @@ static reloc_howto_type elf_mn10300_howto_table[] =
         0xffffffff,            /* dst_mask */
         FALSE),                /* pcrel_offset */
 
         0xffffffff,            /* dst_mask */
         FALSE),                /* pcrel_offset */
 
-  EMPTY_HOWTO (24),
-  EMPTY_HOWTO (25),
-  EMPTY_HOWTO (26),
-  EMPTY_HOWTO (27),
-  EMPTY_HOWTO (28),
-  EMPTY_HOWTO (29),
-  EMPTY_HOWTO (30),
-  EMPTY_HOWTO (31),
-  EMPTY_HOWTO (32),
+  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 */
   
   HOWTO (R_MN10300_SYM_DIFF,   /* type */
         0,                     /* rightshift */
@@ -519,6 +666,15 @@ 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_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 }
 };
   { BFD_RELOC_MN10300_SYM_DIFF, R_MN10300_SYM_DIFF },
   { BFD_RELOC_MN10300_ALIGN, R_MN10300_ALIGN }
 };
@@ -650,6 +806,223 @@ mn10300_info_to_howto (bfd *abfd ATTRIBUTE_UNUSED,
   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.
    Since we don't do .gots or .plts, we just need to consider the
    virtual table relocs for gc.  */
 /* Look through the relocs for a section during the first phase.
    Since we don't do .gots or .plts, we just need to consider the
    virtual table relocs for gc.  */
@@ -660,6 +1033,7 @@ mn10300_elf_check_relocs (bfd *abfd,
                          asection *sec,
                          const Elf_Internal_Rela *relocs)
 {
                          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;
   bfd_boolean sym_diff_reloc_seen;
   Elf_Internal_Shdr *symtab_hdr;
   Elf_Internal_Sym * isymbuf = NULL;
@@ -694,6 +1068,7 @@ mn10300_elf_check_relocs (bfd *abfd,
       struct elf_link_hash_entry *h;
       unsigned long r_symndx;
       unsigned int r_type;
       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)
 
       r_symndx = ELF32_R_SYM (rel->r_info);
       if (r_symndx < symtab_hdr->sh_info)
@@ -707,6 +1082,7 @@ mn10300_elf_check_relocs (bfd *abfd,
        }
 
       r_type = ELF32_R_TYPE (rel->r_info);
        }
 
       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)
 
       /* Some relocs require a global offset table.  */
       if (dynobj == NULL)
@@ -721,6 +1097,10 @@ mn10300_elf_check_relocs (bfd *abfd,
            case R_MN10300_GOTOFF16:
            case R_MN10300_GOTPC32:
            case R_MN10300_GOTPC16:
            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))
                goto fail;
              elf_hash_table (info)->dynobj = dynobj = abfd;
              if (! _bfd_mn10300_elf_create_got_section (dynobj, info))
                goto fail;
@@ -749,11 +1129,35 @@ mn10300_elf_check_relocs (bfd *abfd,
            goto fail;
          break;
 
            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:
        case R_MN10300_GOT32:
        case R_MN10300_GOT24:
        case R_MN10300_GOT16:
+       create_got:
          /* This symbol requires a global offset table entry.  */
 
          /* 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");
          if (sgot == NULL)
            {
              sgot = bfd_get_section_by_name (dynobj, ".got");
@@ -780,22 +1184,48 @@ mn10300_elf_check_relocs (bfd *abfd,
                }
            }
 
                }
            }
 
-         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;
 
              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))
                    goto fail;
                }
 
              srelgot->size += sizeof (Elf32_External_Rela);
                {
                  if (! bfd_elf_link_record_dynamic_symbol (info, h))
                    goto fail;
                }
 
              srelgot->size += sizeof (Elf32_External_Rela);
+             if (r_type == R_MN10300_TLS_GD)
+               srelgot->size += sizeof (Elf32_External_Rela);
            }
          else
            {
            }
          else
            {
@@ -806,13 +1236,15 @@ mn10300_elf_check_relocs (bfd *abfd,
                  size_t       size;
                  unsigned int i;
 
                  size_t       size;
                  unsigned int i;
 
-                 size = symtab_hdr->sh_info * sizeof (bfd_vma);
+                 size = symtab_hdr->sh_info * (sizeof (bfd_vma) + sizeof (char));
                  local_got_offsets = bfd_alloc (abfd, size);
 
                  if (local_got_offsets == NULL)
                    goto fail;
 
                  elf_local_got_offsets (abfd) = local_got_offsets;
                  local_got_offsets = bfd_alloc (abfd, size);
 
                  if (local_got_offsets == NULL)
                    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;
 
                  for (i = 0; i < symtab_hdr->sh_info; i++)
                    local_got_offsets[i] = (bfd_vma) -1;
@@ -825,14 +1257,26 @@ mn10300_elf_check_relocs (bfd *abfd,
              local_got_offsets[r_symndx] = sgot->size;
 
              if (info->shared)
              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;
            }
 
          sgot->size += 4;
-         break;
+         if (r_type == R_MN10300_TLS_GD
+             || r_type == R_MN10300_TLS_LD)
+           sgot->size += 4;
+
+         goto need_shared_relocs;
 
        case R_MN10300_PLT32:
        case R_MN10300_PLT16:
 
        case R_MN10300_PLT32:
        case R_MN10300_PLT16:
@@ -873,6 +1317,7 @@ mn10300_elf_check_relocs (bfd *abfd,
          if (h != NULL)
            h->non_got_ref = 1;
 
          if (h != NULL)
            h->non_got_ref = 1;
 
+       need_shared_relocs:
          /* If we are creating a shared library, then we
             need to copy the reloc into the shared library.  */
          if (info->shared
          /* If we are creating a shared library, then we
             need to copy the reloc into the shared library.  */
          if (info->shared
@@ -981,6 +1426,7 @@ mn10300_elf_final_link_relocate (reloc_howto_type *howto,
                                 asection *sym_sec ATTRIBUTE_UNUSED,
                                 int is_local ATTRIBUTE_UNUSED)
 {
                                 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;
   static asection *  sym_diff_section;
   static bfd_vma     sym_diff_value;
   bfd_boolean is_sym_diff_reloc;
@@ -1012,6 +1458,17 @@ mn10300_elf_final_link_relocate (reloc_howto_type *howto,
          && h != NULL
          && ! SYMBOL_REFERENCES_LOCAL (info, h))
        return bfd_reloc_dangerous;
          && 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;
     }
 
   is_sym_diff_reloc = FALSE;
@@ -1208,6 +1665,9 @@ mn10300_elf_final_link_relocate (reloc_howto_type *howto,
       return bfd_reloc_ok;
 
     case R_MN10300_GOTPC32:
       return bfd_reloc_ok;
 
     case R_MN10300_GOTPC32:
+      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;
       /* Use global offset table as symbol value.  */
       value = bfd_get_section_by_name (dynobj,
                                       ".got")->output_section->vma;
@@ -1220,6 +1680,9 @@ mn10300_elf_final_link_relocate (reloc_howto_type *howto,
       return bfd_reloc_ok;
 
     case R_MN10300_GOTPC16:
       return bfd_reloc_ok;
 
     case R_MN10300_GOTPC16:
+      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;
       /* Use global offset table as symbol value.  */
       value = bfd_get_section_by_name (dynobj,
                                       ".got")->output_section->vma;
@@ -1235,6 +1698,9 @@ mn10300_elf_final_link_relocate (reloc_howto_type *howto,
       return bfd_reloc_ok;
 
     case R_MN10300_GOTOFF32:
       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;
       value -= bfd_get_section_by_name (dynobj,
                                        ".got")->output_section->vma;
       value += addend;
@@ -1243,6 +1709,9 @@ mn10300_elf_final_link_relocate (reloc_howto_type *howto,
       return bfd_reloc_ok;
 
     case R_MN10300_GOTOFF24:
       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;
       value -= bfd_get_section_by_name (dynobj,
                                        ".got")->output_section->vma;
       value += addend;
@@ -1256,6 +1725,9 @@ mn10300_elf_final_link_relocate (reloc_howto_type *howto,
       return bfd_reloc_ok;
 
     case R_MN10300_GOTOFF16:
       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;
       value -= bfd_get_section_by_name (dynobj,
                                        ".got")->output_section->vma;
       value += addend;
@@ -1272,6 +1744,9 @@ mn10300_elf_final_link_relocate (reloc_howto_type *howto,
          && ELF_ST_VISIBILITY (h->other) != STV_HIDDEN
          && h->plt.offset != (bfd_vma) -1)
        {
          && ELF_ST_VISIBILITY (h->other) != STV_HIDDEN
          && h->plt.offset != (bfd_vma) -1)
        {
+         if (dynobj == NULL)
+           return bfd_reloc_dangerous;
+
          splt = bfd_get_section_by_name (dynobj, ".plt");
 
          value = (splt->output_section->vma
          splt = bfd_get_section_by_name (dynobj, ".plt");
 
          value = (splt->output_section->vma
@@ -1293,6 +1768,9 @@ mn10300_elf_final_link_relocate (reloc_howto_type *howto,
          && ELF_ST_VISIBILITY (h->other) != STV_HIDDEN
          && h->plt.offset != (bfd_vma) -1)
        {
          && ELF_ST_VISIBILITY (h->other) != STV_HIDDEN
          && h->plt.offset != (bfd_vma) -1)
        {
+         if (dynobj == NULL)
+           return bfd_reloc_dangerous;
+
          splt = bfd_get_section_by_name (dynobj, ".plt");
 
          value = (splt->output_section->vma
          splt = bfd_get_section_by_name (dynobj, ".plt");
 
          value = (splt->output_section->vma
@@ -1311,41 +1789,102 @@ mn10300_elf_final_link_relocate (reloc_howto_type *howto,
       bfd_put_16 (input_bfd, value, hit_data);
       return bfd_reloc_ok;
 
       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:
     case R_MN10300_GOT32:
     case R_MN10300_GOT24:
     case R_MN10300_GOT16:
-      {
-       sgot = bfd_get_section_by_name (dynobj, ".got");
+      if (dynobj == NULL)
+       return bfd_reloc_dangerous;
 
 
-         if (h != NULL)
-           {
-             bfd_vma off;
+      sgot = bfd_get_section_by_name (dynobj, ".got");
 
 
-             off = h->got.offset;
-             BFD_ASSERT (off != (bfd_vma) -1);
+      if (r_type == R_MN10300_TLS_GD)
+       value = dtpoff (info, value);
 
 
-             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;
-           }
-         else
-           {
-             bfd_vma off;
+      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;
 
 
-             off = elf_local_got_offsets (input_bfd)[symndx];
+         off = elf_local_got_offsets (input_bfd)[symndx];
 
 
+         if (off & 1)
+           bfd_put_32 (output_bfd, value, sgot->contents + (off & ~ 1));
+         else
+           {
              bfd_put_32 (output_bfd, value, sgot->contents + off);
 
              if (info->shared)
              bfd_put_32 (output_bfd, value, sgot->contents + off);
 
              if (info->shared)
@@ -1359,22 +1898,58 @@ mn10300_elf_final_link_relocate (reloc_howto_type *howto,
                  outrel.r_offset = (sgot->output_section->vma
                                     + sgot->output_offset
                                     + off);
                  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;
                  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;
 
 
       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;
        {
          bfd_put_32 (input_bfd, value, hit_data);
          return bfd_reloc_ok;
@@ -1419,6 +1994,7 @@ mn10300_elf_relocate_section (bfd *output_bfd,
   Elf_Internal_Shdr *symtab_hdr;
   struct elf_link_hash_entry **sym_hashes;
   Elf_Internal_Rela *rel, *relend;
   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);
 
   symtab_hdr = &elf_tdata (input_bfd)->symtab_hdr;
   sym_hashes = elf_sym_hashes (input_bfd);
@@ -1435,7 +2011,12 @@ mn10300_elf_relocate_section (bfd *output_bfd,
       struct elf32_mn10300_link_hash_entry *h;
       bfd_vma relocation;
       bfd_reloc_status_type r;
       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;
       r_symndx = ELF32_R_SYM (rel->r_info);
       r_type = ELF32_R_TYPE (rel->r_info);
       howto = elf_mn10300_howto_table + r_type;
@@ -1449,24 +2030,42 @@ mn10300_elf_relocate_section (bfd *output_bfd,
       sym = NULL;
       sec = NULL;
       if (r_symndx < symtab_hdr->sh_info)
       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
        {
       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);
          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
          if ((h->root.root.type == bfd_link_hash_defined
              || h->root.root.type == bfd_link_hash_defweak)
              && (   r_type == R_MN10300_GOTPC32
@@ -1478,6 +2077,10 @@ mn10300_elf_relocate_section (bfd *output_bfd,
                      && h->root.plt.offset != (bfd_vma) -1)
                  || ((   r_type == R_MN10300_GOT32
                       || r_type == R_MN10300_GOT24
                      && 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_GOT16)
                      && elf_hash_table (info)->dynamic_sections_created
                      && !SYMBOL_REFERENCES_LOCAL (info, hh))
@@ -1571,6 +2174,9 @@ mn10300_elf_relocate_section (bfd *output_bfd,
              if (r_type == R_MN10300_PCREL32)
                msg = _("error: inappropriate relocation type for shared"
                        " library (did you forget -fpic?)");
              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");
              else
                msg = _("internal error: suspicious relocation type used"
                        " in shared library");
@@ -1581,11 +2187,9 @@ mn10300_elf_relocate_section (bfd *output_bfd,
              /* Fall through.  */
 
            common_error:
              /* Fall through.  */
 
            common_error:
-             if (!((*info->callbacks->warning)
-                   (info, msg, name, input_bfd, input_section,
-                    rel->r_offset)))
-               return FALSE;
-             break;
+             _bfd_error_handler (msg, input_bfd, name);
+             bfd_set_error (bfd_error_bad_value);
+             return FALSE;
            }
        }
     }
            }
        }
     }
@@ -2581,6 +3185,7 @@ mn10300_elf_relax_section (bfd *abfd,
                    {
                      int bytes = 0;
                      bfd_vma symval;
                    {
                      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;
 
                      /* Note that we've changed things.  */
                      elf_section_data (section)->relocs = internal_relocs;
@@ -2611,6 +3216,25 @@ mn10300_elf_relax_section (bfd *abfd,
                                                           bytes))
                        goto error_return;
 
                                                           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;
                      /* Something changed.  Not strictly necessary, but
                         may lead to more relaxing opportunities.  */
                      *again = TRUE;
@@ -3949,11 +4573,38 @@ elf32_mn10300_link_hash_newfunc (struct bfd_hash_entry *entry,
       ret->movm_stack_size = 0;
       ret->flags = 0;
       ret->value = 0;
       ret->movm_stack_size = 0;
       ret->flags = 0;
       ret->value = 0;
+      ret->tls_type = GOT_UNKNOWN;
     }
 
   return (struct bfd_hash_entry *) ret;
 }
 
     }
 
   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 *
 /* Create an mn10300 ELF linker hash table.  */
 
 static struct bfd_link_hash_table *
@@ -3976,6 +4627,11 @@ elf32_mn10300_link_hash_table_create (bfd *abfd)
     }
 
   ret->flags = 0;
     }
 
   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 = bfd_malloc (amt);
   if (ret->static_hash_table == NULL)
   amt = sizeof (struct elf_link_hash_table);
   ret->static_hash_table = bfd_malloc (amt);
   if (ret->static_hash_table == NULL)
@@ -4410,6 +5066,7 @@ static bfd_boolean
 _bfd_mn10300_elf_size_dynamic_sections (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;
   bfd * dynobj;
   asection * s;
   bfd_boolean plt;
@@ -4442,6 +5099,13 @@ _bfd_mn10300_elf_size_dynamic_sections (bfd * output_bfd,
        s->size = 0;
     }
 
        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.  */
   /* The check_relocs and adjust_dynamic_symbol entry points have
      determined the sizes of the various dynamic sections.  Allocate
      memory for them.  */
@@ -4685,31 +5349,64 @@ _bfd_mn10300_elf_finish_dynamic_symbol (bfd * output_bfd,
                      + sgot->output_offset
                      + (h->got.offset & ~1));
 
                      + sgot->output_offset
                      + (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);
          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;
          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)
     }
 
   if (h->needs_copy)
@@ -4846,6 +5543,14 @@ _bfd_mn10300_elf_finish_dynamic_sections (bfd * output_bfd,
          /* 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, 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;
        }
     }
 
        }
     }
 
@@ -4887,12 +5592,7 @@ _bfd_mn10300_elf_reloc_type_class (const Elf_Internal_Rela *rela)
 static bfd_boolean
 mn10300_elf_mkobject (bfd *abfd)
 {
 static bfd_boolean
 mn10300_elf_mkobject (bfd *abfd)
 {
-  /* We do not actually need any extra room in the bfd elf data structure.
-     But we do need the object_id of the structure to be set to
-     MN10300_ELF_DATA so that elflink.c:elf_link_add_object_symols() will call
-     our mn10300_elf_check_relocs function which will then allocate space in
-     the .got section for any GOT based relocs.  */
-  return bfd_elf_allocate_object (abfd, sizeof (struct elf_obj_tdata),
+  return bfd_elf_allocate_object (abfd, sizeof (struct elf_mn10300_obj_tdata),
                                  MN10300_ELF_DATA);
 }
 
                                  MN10300_ELF_DATA);
 }
 
@@ -4948,7 +5648,8 @@ mn10300_elf_mkobject (bfd *abfd)
   _bfd_mn10300_elf_finish_dynamic_symbol
 #define elf_backend_finish_dynamic_sections \
   _bfd_mn10300_elf_finish_dynamic_sections
   _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
 
 #define elf_backend_reloc_type_class \
   _bfd_mn10300_elf_reloc_type_class
 
index 78860ff..844d3a7 100644 (file)
@@ -1225,6 +1225,17 @@ static const char *const bfd_reloc_code_real_names[] = { "@@uninitialized@@",
   "BFD_RELOC_MN10300_RELATIVE",
   "BFD_RELOC_MN10300_SYM_DIFF",
   "BFD_RELOC_MN10300_ALIGN",
   "BFD_RELOC_MN10300_RELATIVE",
   "BFD_RELOC_MN10300_SYM_DIFF",
   "BFD_RELOC_MN10300_ALIGN",
+  "BFD_RELOC_MN10300_TLS_GD",
+  "BFD_RELOC_MN10300_TLS_LD",
+  "BFD_RELOC_MN10300_TLS_LDO",
+  "BFD_RELOC_MN10300_TLS_GOTIE",
+  "BFD_RELOC_MN10300_TLS_IE",
+  "BFD_RELOC_MN10300_TLS_LE",
+  "BFD_RELOC_MN10300_TLS_DTPMOD",
+  "BFD_RELOC_MN10300_TLS_DTPOFF",
+  "BFD_RELOC_MN10300_TLS_TPOFF",
+  "BFD_RELOC_MN10300_32_PCREL",
+  "BFD_RELOC_MN10300_16_PCREL",
 
   "BFD_RELOC_386_GOT32",
   "BFD_RELOC_386_PLT32",
 
   "BFD_RELOC_386_GOT32",
   "BFD_RELOC_386_PLT32",
@@ -1733,8 +1744,6 @@ static const char *const bfd_reloc_code_real_names[] = { "@@uninitialized@@",
   "BFD_RELOC_V850_32_GOTOFF",
   "BFD_RELOC_V850_CODE",
   "BFD_RELOC_V850_DATA",
   "BFD_RELOC_V850_32_GOTOFF",
   "BFD_RELOC_V850_CODE",
   "BFD_RELOC_V850_DATA",
-  "BFD_RELOC_MN10300_32_PCREL",
-  "BFD_RELOC_MN10300_16_PCREL",
   "BFD_RELOC_TIC30_LDP",
   "BFD_RELOC_TIC54X_PARTLS7",
   "BFD_RELOC_TIC54X_PARTMS9",
   "BFD_RELOC_TIC30_LDP",
   "BFD_RELOC_TIC54X_PARTLS7",
   "BFD_RELOC_TIC54X_PARTMS9",
index 4e1958c..fb3aab2 100644 (file)
@@ -2547,6 +2547,36 @@ ENUMDOC
   The addend of this reloc is an alignment power that must
   be honoured at the offset's location, regardless of linker
   relaxation.
   The addend of this reloc is an alignment power that must
   be honoured at the offset's location, regardless of linker
   relaxation.
+ENUM
+  BFD_RELOC_MN10300_TLS_GD
+ENUMX
+  BFD_RELOC_MN10300_TLS_LD
+ENUMX
+  BFD_RELOC_MN10300_TLS_LDO
+ENUMX
+  BFD_RELOC_MN10300_TLS_GOTIE
+ENUMX
+  BFD_RELOC_MN10300_TLS_IE
+ENUMX
+  BFD_RELOC_MN10300_TLS_LE
+ENUMX
+  BFD_RELOC_MN10300_TLS_DTPMOD
+ENUMX
+  BFD_RELOC_MN10300_TLS_DTPOFF
+ENUMX
+  BFD_RELOC_MN10300_TLS_TPOFF
+ENUMDOC
+  Various TLS-related relocations.
+ENUM
+  BFD_RELOC_MN10300_32_PCREL
+ENUMDOC
+  This is a 32bit pcrel reloc for the mn10300, offset by two bytes in the
+  instruction.
+ENUM
+  BFD_RELOC_MN10300_16_PCREL
+ENUMDOC
+  This is a 16bit pcrel reloc for the mn10300, offset by two bytes in the
+  instruction.
 COMMENT
 
 ENUM
 COMMENT
 
 ENUM
@@ -3921,16 +3951,6 @@ ENUM
   BFD_RELOC_V850_DATA
 ENUMDOC
   start data in text.
   BFD_RELOC_V850_DATA
 ENUMDOC
   start data in text.
-ENUM
-  BFD_RELOC_MN10300_32_PCREL
-ENUMDOC
-  This is a 32bit pcrel reloc for the mn10300, offset by two bytes in the
-  instruction.
-ENUM
-  BFD_RELOC_MN10300_16_PCREL
-ENUMDOC
-  This is a 16bit pcrel reloc for the mn10300, offset by two bytes in the
-  instruction.
 
 ENUM
   BFD_RELOC_TIC30_LDP
 
 ENUM
   BFD_RELOC_TIC30_LDP
index cf01c4a..425f926 100644 (file)
@@ -1,3 +1,7 @@
+2012-03-07  Nick Clifton  <nickc@redhat.com>
+
+       * readelf.c (is_16bit_abs_reloc): Add detection of R_MN10300_16.
+
 2012-02-29  Jeff Law  <law@redhat.com>
 
        * doc/binutils.texi (c++filt): Fix typos.
 2012-02-29  Jeff Law  <law@redhat.com>
 
        * doc/binutils.texi (c++filt): Fix typos.
index 560df7a..f42039e 100644 (file)
@@ -10084,6 +10084,9 @@ is_16bit_abs_reloc (unsigned int reloc_type)
     case EM_XC16X:
     case EM_C166:
       return reloc_type == 2; /* R_XC16C_ABS_16.  */
     case EM_XC16X:
     case EM_C166:
       return reloc_type == 2; /* R_XC16C_ABS_16.  */
+    case EM_CYGNUS_MN10300:
+    case EM_MN10300:
+      return reloc_type == 2; /* R_MN10300_16.  */
     default:
       return FALSE;
     }
     default:
       return FALSE;
     }
index be8e7c5..f60f94b 100644 (file)
@@ -1,3 +1,9 @@
+2012-03-07  Nick Clifton  <nickc@redhat.com>
+
+       * config/tc-mn10300.c (other_registers): Add SSP and USP.
+       (md_assemble): Add support for TLS relocs.
+       (mn10300_parse_name): Likewise.
+
 2012-02-27  Alan Modra  <amodra@gmail.com>
 
        * config/tc-crx.c (check_range): Correct uint32_t misconceptions.
 2012-02-27  Alan Modra  <amodra@gmail.com>
 
        * config/tc-crx.c (check_range): Correct uint32_t misconceptions.
index 0a4f26c..4029c64 100644 (file)
@@ -281,6 +281,8 @@ static const struct reg_name other_registers[] =
   { "pc", AM33 },
   { "psw", 0 },
   { "sp", 0 },
   { "pc", AM33 },
   { "psw", 0 },
   { "sp", 0 },
+  { "ssp", 0 },
+  { "usp", 0 },
 };
 
 #define OTHER_REG_NAME_CNT     ARRAY_SIZE (other_registers)
 };
 
 #define OTHER_REG_NAME_CNT     ARRAY_SIZE (other_registers)
@@ -2063,6 +2065,12 @@ keep_going:
              && fixups[i].reloc != BFD_RELOC_32_GOT_PCREL
              && fixups[i].reloc != BFD_RELOC_32_GOTOFF
              && fixups[i].reloc != BFD_RELOC_32_PLT_PCREL
              && fixups[i].reloc != BFD_RELOC_32_GOT_PCREL
              && fixups[i].reloc != BFD_RELOC_32_GOTOFF
              && fixups[i].reloc != BFD_RELOC_32_PLT_PCREL
+             && fixups[i].reloc != BFD_RELOC_MN10300_TLS_GD
+             && fixups[i].reloc != BFD_RELOC_MN10300_TLS_LD
+             && fixups[i].reloc != BFD_RELOC_MN10300_TLS_LDO
+             && fixups[i].reloc != BFD_RELOC_MN10300_TLS_GOTIE
+             && fixups[i].reloc != BFD_RELOC_MN10300_TLS_IE
+             && fixups[i].reloc != BFD_RELOC_MN10300_TLS_LE
              && fixups[i].reloc != BFD_RELOC_MN10300_GOT32)
            {
              reloc_howto_type *reloc_howto;
              && fixups[i].reloc != BFD_RELOC_MN10300_GOT32)
            {
              reloc_howto_type *reloc_howto;
@@ -2501,6 +2509,18 @@ mn10300_parse_name (char const *name,
     reloc_type = BFD_RELOC_MN10300_GOT32;
   else if ((next_end = mn10300_end_of_match (next + 1, "PLT")))
     reloc_type = BFD_RELOC_32_PLT_PCREL;
     reloc_type = BFD_RELOC_MN10300_GOT32;
   else if ((next_end = mn10300_end_of_match (next + 1, "PLT")))
     reloc_type = BFD_RELOC_32_PLT_PCREL;
+  else if ((next_end = mn10300_end_of_match (next + 1, "tlsgd")))
+    reloc_type = BFD_RELOC_MN10300_TLS_GD;
+  else if ((next_end = mn10300_end_of_match (next + 1, "tlsldm")))
+    reloc_type = BFD_RELOC_MN10300_TLS_LD;
+  else if ((next_end = mn10300_end_of_match (next + 1, "dtpoff")))
+    reloc_type = BFD_RELOC_MN10300_TLS_LDO;
+  else if ((next_end = mn10300_end_of_match (next + 1, "gotntpoff")))
+    reloc_type = BFD_RELOC_MN10300_TLS_GOTIE;
+  else if ((next_end = mn10300_end_of_match (next + 1, "indntpoff")))
+    reloc_type = BFD_RELOC_MN10300_TLS_IE;
+  else if ((next_end = mn10300_end_of_match (next + 1, "tpoff")))
+    reloc_type = BFD_RELOC_MN10300_TLS_LE;
   else
     goto no_suffix;
 
   else
     goto no_suffix;
 
index 1535dfb..2d8264e 100644 (file)
@@ -1,3 +1,10 @@
+2012-03-07  Nick Clifton  <nickc@redhat.com>
+
+       * mn10300.h (elf_mn10300_reloc_type): Add R_MN10300_TLS_GD,
+       R_MN10300_TLS_LD, R_MN10300_TLS_LDO, R_MN10300_TLS_GOTIE,
+       R_MN10300_TLS_IE, R_MN10300_TLS_LE, R_MN10300_TLS_DPTMOD,
+       R_MN10300_TLS_DTPOFF and R_MN10300_TLS_TPOFF.
+
 2012-02-25  Walter Lee  <walt@tilera.com>
 
        * tilegx.h (R_TILEGX_IMM16_X0_HW1_GOT): Delete.
 2012-02-25  Walter Lee  <walt@tilera.com>
 
        * tilegx.h (R_TILEGX_IMM16_X0_HW1_GOT): Delete.
index 444787b..529b389 100644 (file)
@@ -51,6 +51,15 @@ START_RELOC_NUMBERS (elf_mn10300_reloc_type)
   RELOC_NUMBER (R_MN10300_GLOB_DAT, 21)
   RELOC_NUMBER (R_MN10300_JMP_SLOT, 22)
   RELOC_NUMBER (R_MN10300_RELATIVE, 23)
   RELOC_NUMBER (R_MN10300_GLOB_DAT, 21)
   RELOC_NUMBER (R_MN10300_JMP_SLOT, 22)
   RELOC_NUMBER (R_MN10300_RELATIVE, 23)
+  RELOC_NUMBER (R_MN10300_TLS_GD, 24)
+  RELOC_NUMBER (R_MN10300_TLS_LD, 25)
+  RELOC_NUMBER (R_MN10300_TLS_LDO, 26)
+  RELOC_NUMBER (R_MN10300_TLS_GOTIE, 27)
+  RELOC_NUMBER (R_MN10300_TLS_IE, 28)
+  RELOC_NUMBER (R_MN10300_TLS_LE, 29)
+  RELOC_NUMBER (R_MN10300_TLS_DTPMOD, 30)
+  RELOC_NUMBER (R_MN10300_TLS_DTPOFF, 31)
+  RELOC_NUMBER (R_MN10300_TLS_TPOFF, 32)
   RELOC_NUMBER (R_MN10300_SYM_DIFF, 33)
   RELOC_NUMBER (R_MN10300_ALIGN, 34)
 END_RELOC_NUMBERS (R_MN10300_MAX)
   RELOC_NUMBER (R_MN10300_SYM_DIFF, 33)
   RELOC_NUMBER (R_MN10300_ALIGN, 34)
 END_RELOC_NUMBERS (R_MN10300_MAX)