This is the mail archive of the binutils@sourceware.org mailing list for the binutils project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

[patch] am33 TLS support


First stab at adding TLS support for the am33 (mn10300) chip.  The GAS
testsuite is in the patch; the LD testsuite is appended as a uuencoded
tar.gz file.  Comments?

[include]
	* elf/mn104300.h: Add TLS relocations.
	
[bfd]
	* reloc.c: Add MN10300 TLS relocations.
	* libbfd.h: Regenerate.
	* bfd-in2.h: Regenerate.
	* elf-m10300.c (elf32_mn10300_link_hash_entry): Add tls_type.
	(elf_mn10300_obj_tdata): New.
	(elf_mn10300_mkobject): New.
	(elf32_mn10300_link_hash_table): Add tls_ldm_got.
	(elf_mn10300_howto_table): Add TLS relocs.
	(mn10300_reloc_map): Add TLS relocs.
	(elf_mn10300_tls_transition): New.
	(mn10300_elf_check_relocs): Add TLS support.
	(dtpoff): New.
	(tpoff): New.
	(mn10300_do_tls_transition): New.
	(mn10300_elf_final_link_relocate): Add TLS support.
	(mn10300_elf_relocate_section): Add TLS support.
	(elf32_mn10300_link_hash_newfunc): Initialize tls_type.
	(_bfd_mn10300_copy_indirect_symbol): New.
	(elf32_mn10300_link_hash_table_create): Initialize TLS fields.
	(_bfd_mn10300_elf_size_dynamic_sections): Add TLS support.
	(_bfd_mn10300_elf_finish_dynamic_symbol): Add TLS support.
	(_bfd_mn10300_elf_finish_dynamic_sections): Add TLS support.

[gas]
	* config/tc-mn10300.c (md_assemble): Add TLS support.
	(md_parse_name): Add TLS support.

[gas/testsuite]

	* gas/mn10300/basic.exp: Add TLS tests.
	* gas/mn10300/tls.s: New.
	* gas/mn10300/tls.d: New.
	* gas/mn10300/tls2.s: New.
	* gas/mn10300/tls2.d: New.

[ld/testsuite]
	* ld-am33: New directory.

Index: bfd/bfd-in2.h
===================================================================
RCS file: /cvs/src/src/bfd/bfd-in2.h,v
retrieving revision 1.390
diff -p -U3 -r1.390  bfd/bfd-in2.h
--- bfd/bfd-in2.h	11 May 2006 15:17:34 -0000	1.390
+++ bfd/bfd-in2.h	11 May 2006 22:21:48 -0000
@@ -2656,6 +2656,17 @@ in the instruction.  */
 /* Adjust by program base.  */
   BFD_RELOC_MN10300_RELATIVE,
 
+/* 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,
+
 
 /* i386/elf relocations  */
   BFD_RELOC_386_GOT32,
Index: bfd/elf-m10300.c
===================================================================
RCS file: /cvs/src/src/bfd/elf-m10300.c,v
retrieving revision 1.73
diff -p -U3 -r1.73  bfd/elf-m10300.c
--- bfd/elf-m10300.c	16 Mar 2006 12:20:15 -0000	1.73
+++ bfd/elf-m10300.c	11 May 2006 22:21:51 -0000
@@ -85,8 +85,42 @@ struct elf32_mn10300_link_hash_entry {
    prologue deleted.  */
 #define MN10300_DELETED_PROLOGUE_BYTES 0x2
   unsigned char flags;
+
+#define GOT_UNKNOWN	0
+#define GOT_NORMAL	1
+#define GOT_TLS_GD	2
+#define GOT_TLS_LD	3
+#define GOT_TLS_IE	4
+  unsigned char tls_type;
+};
+
+#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)
+
+static bfd_boolean
+elf_mn10300_mkobject (bfd *abfd)
+{
+  bfd_size_type amt = sizeof (struct elf_mn10300_obj_tdata);
+  abfd->tdata.any = bfd_zalloc (abfd, amt);
+  if (abfd->tdata.any == NULL)
+    return FALSE;
+  return TRUE;
+}
+
+
 /* 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.  */
@@ -102,6 +136,13 @@ 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;
 };
 
 /* For MN10300 linker hash table.  */
@@ -498,6 +539,132 @@ static reloc_howto_type elf_mn10300_howt
 	 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 */
+
 };
 
 struct mn10300_reloc_map {
@@ -530,6 +697,15 @@ static const struct mn10300_reloc_map mn
   { 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 },
 };
 
 /* Create the GOT section.  */
@@ -652,6 +828,46 @@ mn10300_info_to_howto (abfd, cache_ptr, 
   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, int counting)
+{
+  int local_p = _bfd_elf_symbol_refs_local_p (h, info, 1);
+
+  if (r_type == R_MN10300_TLS_GD
+      && h && 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 && !elf_hash_table (info)->dynamic_sections_created)
+    local_p = 1;
+
+  /* For the main program, these are the transitions we do.  */
+  switch (r_type)
+    {
+    case R_MN10300_TLS_GD:
+      if (local_p)
+	return R_MN10300_TLS_LE;
+      return 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:
+      if (local_p)
+	return R_MN10300_TLS_LE;
+      return r_type;
+    }
+
+  return r_type;
+}
+
 /* 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.  */
@@ -663,6 +879,7 @@ mn10300_elf_check_relocs (abfd, info, se
      asection *sec;
      const Elf_Internal_Rela *relocs;
 {
+  struct elf32_mn10300_link_hash_table *htab;
   Elf_Internal_Shdr *symtab_hdr;
   struct elf_link_hash_entry **sym_hashes, **sym_hashes_end;
   const Elf_Internal_Rela *rel;
@@ -680,6 +897,7 @@ mn10300_elf_check_relocs (abfd, info, se
   if (info->relocatable)
     return TRUE;
 
+  htab = elf32_mn10300_hash_table (info);
   symtab_hdr = &elf_tdata (abfd)->symtab_hdr;
   sym_hashes = elf_sym_hashes (abfd);
   sym_hashes_end = sym_hashes + symtab_hdr->sh_size/sizeof (Elf32_External_Sym);
@@ -693,6 +911,8 @@ mn10300_elf_check_relocs (abfd, info, se
     {
       struct elf_link_hash_entry *h;
       unsigned long r_symndx;
+      int tls_type = GOT_NORMAL;
+      unsigned int r_type;
 
       r_symndx = ELF32_R_SYM (rel->r_info);
       if (r_symndx < symtab_hdr->sh_info)
@@ -705,10 +925,13 @@ mn10300_elf_check_relocs (abfd, info, se
 	    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, 1);
+
       /* 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:
@@ -718,6 +941,10 @@ mn10300_elf_check_relocs (abfd, info, se
 	    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;
@@ -728,7 +955,7 @@ mn10300_elf_check_relocs (abfd, info, se
 	    }
 	}
 
-      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.  */
@@ -743,10 +970,65 @@ mn10300_elf_check_relocs (abfd, info, se
 	  if (!bfd_elf_gc_record_vtentry (abfd, sec, h, rel->r_addend))
 	    return FALSE;
 	  break;
+
+
+	case R_MN10300_PLT32:
+	case R_MN10300_PLT16:
+	  /* This symbol requires a procedure linkage table entry.  We
+	     actually build the entry in adjust_dynamic_symbol,
+	     because this might be a case of linking PIC code which is
+	     never referenced by a dynamic object, in which case we
+	     don't need to generate a procedure linkage table entry
+	     after all.  */
+
+	  /* If this is a local symbol, we resolve it directly without
+	     creating a procedure linkage table entry.  */
+	  if (h == NULL)
+	    continue;
+
+	  if (ELF_ST_VISIBILITY (h->other) == STV_INTERNAL
+	      || ELF_ST_VISIBILITY (h->other) == STV_HIDDEN)
+	    break;
+
+	  h->needs_plt = 1;
+
+	  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_GD:
+		tls_type = GOT_TLS_GD;
+		break;
+	      case R_MN10300_TLS_IE:
+	      case R_MN10300_TLS_GOTIE:
+		tls_type = GOT_TLS_IE;
+		break;
+	      default:
+		tls_type = GOT_NORMAL;
+		break;
+	      }
+	  }
 
 	  if (sgot == NULL)
 	    {
@@ -774,22 +1056,48 @@ mn10300_elf_check_relocs (abfd, info, se
 		}
 	    }
 
-	  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;
+		goto need_shared_relocs;
 
 	      h->got.offset = sgot->size;
-
 	      /* Make sure this symbol is output as a dynamic symbol.  */
-	      if (h->dynindx == -1)
+	      if (h->dynindx == -1
+		  && ELF_ST_VISIBILITY (h->other != STV_HIDDEN)
+		  && ELF_ST_VISIBILITY (h->other != STV_INTERNAL))
 		{
 		  if (! bfd_elf_link_record_dynamic_symbol (info, h))
 		    return FALSE;
 		}
 
 	      srelgot->size += sizeof (Elf32_External_Rela);
+	      if (r_type == R_MN10300_TLS_GD)
+		srelgot->size += sizeof (Elf32_External_Rela);
 	    }
 	  else
 	    {
@@ -800,12 +1108,14 @@ mn10300_elf_check_relocs (abfd, info, se
 		  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_vma *) bfd_alloc (abfd, size);
 
 		  if (local_got_offsets == NULL)
 		    return FALSE;
 		  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;
@@ -813,42 +1123,28 @@ mn10300_elf_check_relocs (abfd, info, se
 
 	      if (local_got_offsets[r_symndx] != (bfd_vma) -1)
 		/* We have already allocated space in the .got.  */
-		break;
+		goto need_shared_relocs;
 
 	      local_got_offsets[r_symndx] = sgot->size;
+	      elf_mn10300_local_got_tls_type (abfd) [r_symndx] = tls_type;
 
 	      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)
+		    srelgot->size += sizeof (Elf32_External_Rela);
+		}
 	    }
 
 	  sgot->size += 4;
+	  if (r_type == R_MN10300_TLS_GD
+	      || r_type == R_MN10300_TLS_LD)
+	    sgot->size += 4;
 
-	  break;
-
-	case R_MN10300_PLT32:
-	case R_MN10300_PLT16:
-	  /* This symbol requires a procedure linkage table entry.  We
-	     actually build the entry in adjust_dynamic_symbol,
-	     because this might be a case of linking PIC code which is
-	     never referenced by a dynamic object, in which case we
-	     don't need to generate a procedure linkage table entry
-	     after all.  */
-
-	  /* If this is a local symbol, we resolve it directly without
-	     creating a procedure linkage table entry.  */
-	  if (h == NULL)
-	    continue;
-
-	  if (ELF_ST_VISIBILITY (h->other) == STV_INTERNAL
-	      || ELF_ST_VISIBILITY (h->other) == STV_HIDDEN)
-	    break;
-
-	  h->needs_plt = 1;
-
-	  break;
+	  goto need_shared_relocs;
 
 	case R_MN10300_24:
 	case R_MN10300_16:
@@ -864,6 +1160,7 @@ mn10300_elf_check_relocs (abfd, info, se
 	  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
@@ -955,6 +1252,185 @@ mn10300_elf_gc_mark_hook (sec, info, rel
   return NULL;
 }
 
+/* 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;
+}
+
+
 /* Perform a relocation as part of a final link.  */
 static bfd_reloc_status_type
 mn10300_elf_final_link_relocate (howto, input_bfd, output_bfd,
@@ -974,6 +1450,7 @@ mn10300_elf_final_link_relocate (howto, 
      asection *sym_sec ATTRIBUTE_UNUSED;
      int is_local ATTRIBUTE_UNUSED;
 {
+  struct elf32_mn10300_link_hash_table *htab;
   unsigned long r_type = howto->type;
   bfd_byte *hit_data = contents + offset;
   bfd *      dynobj;
@@ -982,6 +1459,7 @@ mn10300_elf_final_link_relocate (howto, 
   asection * splt;
   asection * sreloc;
 
+  htab = elf32_mn10300_hash_table (info);
   dynobj = elf_hash_table (info)->dynobj;
   local_got_offsets = elf_local_got_offsets (input_bfd);
 
@@ -1269,14 +1747,63 @@ mn10300_elf_final_link_relocate (howto, 
       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:
+      {
+	asection *sgot = bfd_get_section_by_name (dynobj, ".got");
+
+	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;
+
+	    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_GOT32:
     case R_MN10300_GOT24:
     case R_MN10300_GOT16:
+    case R_MN10300_TLS_IE:
       {
-	asection * sgot;
-
 	sgot = bfd_get_section_by_name (dynobj, ".got");
 
+	switch (r_type)
+	  {
+	  case R_MN10300_TLS_GD:
+	    value = dtpoff (info, value);
+	    break;
+	  }
+
 	  if (h != NULL)
 	    {
 	      bfd_vma off;
@@ -1295,8 +1822,11 @@ mn10300_elf_final_link_relocate (howto, 
 		   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);
+		{
+		  BFD_ASSERT (r_type != R_MN10300_TLS_GD);
+		  bfd_put_32 (output_bfd, value,
+			      sgot->contents + off);
+		}
 
 	      value = sgot->output_offset + off;
 	    }
@@ -1304,11 +1834,14 @@ mn10300_elf_final_link_relocate (howto, 
 	    {
 	      bfd_vma off;
 
-	      off = elf_local_got_offsets (input_bfd)[symndx];
+	      if (h)
+		off = h->got.offset;
+	      else
+		off = elf_local_got_offsets (input_bfd)[symndx];
 
-	      bfd_put_32 (output_bfd, value, sgot->contents + off);
+	      bfd_put_32 (output_bfd, value, sgot->contents + (off & ~1));
 
-	      if (info->shared)
+	      if (info->shared && ! (off & 1))
 		{
 		  asection * srelgot;
 		  Elf_Internal_Rela outrel;
@@ -1316,24 +1849,59 @@ mn10300_elf_final_link_relocate (howto, 
 		  srelgot = bfd_get_section_by_name (dynobj, ".rela.got");
 		  BFD_ASSERT (srelgot != NULL);
 
+		  outrel.r_addend = value;
+		  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_offset = (sgot->output_section->vma
 				     + sgot->output_offset
 				     + off);
-		  outrel.r_info = ELF32_R_INFO (0, R_MN10300_RELATIVE);
-		  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_TLS_IE)
+	{
+	  value += sgot->output_section->vma;
+	  bfd_put_32 (input_bfd, value, hit_data);
+	  return bfd_reloc_ok;
+	}
+      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;
+	}
       if (r_type == R_MN10300_GOT32)
 	{
 	  bfd_put_32 (input_bfd, value, hit_data);
@@ -1379,7 +1947,7 @@ mn10300_elf_relocate_section (output_bfd
 {
   Elf_Internal_Shdr *symtab_hdr;
   struct elf_link_hash_entry **sym_hashes;
-  Elf_Internal_Rela *rel, *relend;
+  Elf_Internal_Rela *rel, *relend, *trel;
 
   if (info->relocatable)
     return TRUE;
@@ -1391,14 +1959,17 @@ mn10300_elf_relocate_section (output_bfd
   relend = relocs + input_section->reloc_count;
   for (; rel < relend; rel++)
     {
-      int r_type;
+      int r_type, tls_r_type;
       reloc_howto_type *howto;
       unsigned long r_symndx;
       Elf_Internal_Sym *sym;
       asection *sec;
       struct elf32_mn10300_link_hash_entry *h;
-      bfd_vma relocation;
+      bfd_vma relocation = 0;
       bfd_reloc_status_type r;
+      bfd_boolean unresolved_reloc = 0;
+      bfd_boolean warned;
+      struct elf_link_hash_entry *hh;
 
       r_symndx = ELF32_R_SYM (rel->r_info);
       r_type = ELF32_R_TYPE (rel->r_info);
@@ -1409,28 +1980,44 @@ mn10300_elf_relocate_section (output_bfd
 	  || r_type == R_MN10300_GNU_VTENTRY)
 	continue;
 
-      h = NULL;
       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 = (struct elf32_mn10300_link_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)
+	{
+	  int 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
@@ -1442,7 +2029,11 @@ mn10300_elf_relocate_section (output_bfd
 		      && h->root.plt.offset != (bfd_vma) -1)
 		  || ((   r_type == R_MN10300_GOT32
 		       || r_type == R_MN10300_GOT24
-		       || r_type == R_MN10300_GOT16)
+		       || r_type == R_MN10300_GOT16
+		       || r_type == R_MN10300_TLS_GD
+		       || r_type == R_MN10300_TLS_LD
+		       || r_type == R_MN10300_TLS_GOTIE
+		       || r_type == R_MN10300_TLS_IE)
 		      && elf_hash_table (info)->dynamic_sections_created
 		      && !SYMBOL_REFERENCES_LOCAL (info, hh))
 		  || (r_type == R_MN10300_32
@@ -3677,10 +4268,35 @@ elf32_mn10300_link_hash_newfunc (entry, 
       ret->movm_args = 0;
       ret->movm_stack_size = 0;
       ret->flags = 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, *eind;
+
+  edir = (struct elf32_mn10300_link_hash_entry *) dir;
+  eind = (struct elf32_mn10300_link_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.  */
 
@@ -3704,6 +4320,12 @@ elf32_mn10300_link_hash_table_create (ab
     }
 
   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);
@@ -4173,12 +4795,14 @@ _bfd_mn10300_elf_size_dynamic_sections (
      bfd * output_bfd;
      struct bfd_link_info * info;
 {
+  struct elf32_mn10300_link_hash_table *htab;
   bfd * dynobj;
   asection * s;
   bfd_boolean plt;
   bfd_boolean relocs;
   bfd_boolean reltext;
 
+  htab = elf32_mn10300_hash_table (info);
   dynobj = elf_hash_table (info)->dynobj;
   BFD_ASSERT (dynobj != NULL);
 
@@ -4205,6 +4829,13 @@ _bfd_mn10300_elf_size_dynamic_sections (
 	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.  */
@@ -4344,8 +4975,10 @@ _bfd_mn10300_elf_finish_dynamic_symbol (
      struct elf_link_hash_entry * h;
      Elf_Internal_Sym * sym;
 {
+  struct elf32_mn10300_link_hash_table *htab;
   bfd * dynobj;
 
+  htab = elf32_mn10300_hash_table (info);
   dynobj = elf_hash_table (info)->dynobj;
 
   if (h->plt.offset != (bfd_vma) -1)
@@ -4450,31 +5083,65 @@ _bfd_mn10300_elf_finish_dynamic_symbol (
 		      + 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);
-	  rel.r_info = ELF32_R_INFO (h->dynindx, R_MN10300_GLOB_DAT);
 	  rel.r_addend = 0;
+	  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;
+	  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;
+	    }
+	  break;
 	}
 
-      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)
@@ -4608,10 +5275,6 @@ _bfd_mn10300_elf_finish_dynamic_sections
 			  sgot->output_section->vma + sgot->output_offset + 8,
 			  splt->contents + elf_mn10300_plt0_linker_offset (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;
 	}
     }
 
@@ -4675,6 +5338,7 @@ _bfd_mn10300_elf_reloc_type_class (const
 				elf32_mn10300_link_hash_table_create
 #define bfd_elf32_bfd_link_hash_table_free \
 				elf32_mn10300_link_hash_table_free
+#define bfd_elf32_mkobject		elf_mn10300_mkobject
 
 #ifndef elf_symbol_leading_char
 #define elf_symbol_leading_char '_'
@@ -4699,6 +5363,8 @@ _bfd_mn10300_elf_reloc_type_class (const
   _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
Index: bfd/libbfd.h
===================================================================
RCS file: /cvs/src/src/bfd/libbfd.h,v
retrieving revision 1.181
diff -p -U3 -r1.181  bfd/libbfd.h
--- bfd/libbfd.h	11 May 2006 15:17:34 -0000	1.181
+++ bfd/libbfd.h	11 May 2006 22:21:51 -0000
@@ -1025,6 +1025,15 @@ static const char *const bfd_reloc_code_
   "BFD_RELOC_MN10300_GLOB_DAT",
   "BFD_RELOC_MN10300_JMP_SLOT",
   "BFD_RELOC_MN10300_RELATIVE",
+  "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_386_GOT32",
   "BFD_RELOC_386_PLT32",
Index: bfd/reloc.c
===================================================================
RCS file: /cvs/src/src/bfd/reloc.c,v
retrieving revision 1.153
diff -p -U3 -r1.153  bfd/reloc.c
--- bfd/reloc.c	11 May 2006 15:17:34 -0000	1.153
+++ bfd/reloc.c	11 May 2006 22:21:52 -0000
@@ -2264,6 +2264,26 @@ ENUM
   BFD_RELOC_MN10300_RELATIVE
 ENUMDOC
   Adjust by program base.
+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.
 COMMENT
 
 ENUM
Index: gas/config/tc-mn10300.c
===================================================================
RCS file: /cvs/src/src/gas/config/tc-mn10300.c,v
retrieving revision 1.56
diff -p -U3 -r1.56  gas/config/tc-mn10300.c
--- gas/config/tc-mn10300.c	3 May 2006 14:26:41 -0000	1.56
+++ gas/config/tc-mn10300.c	11 May 2006 22:21:53 -0000
@@ -2207,7 +2207,13 @@ 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_MN10300_GOT32)
+	      && fixups[i].reloc != BFD_RELOC_MN10300_GOT32
+	      && 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)
 	    {
 	      reloc_howto_type *reloc_howto;
 	      int size;
@@ -2811,9 +2817,40 @@ mn10300_parse_name (name, exprP, mode, n
     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;
 
+  /* The linker needs these, else it complains about linking TLS
+     symbols to non-TLS references.  */
+  switch (reloc_type)
+    {
+    case BFD_RELOC_MN10300_TLS_GD:
+    case BFD_RELOC_MN10300_TLS_LD:
+    case BFD_RELOC_MN10300_TLS_LDO:
+    case BFD_RELOC_MN10300_TLS_GOTIE:
+    case BFD_RELOC_MN10300_TLS_IE:
+    case BFD_RELOC_MN10300_TLS_LE:
+    case BFD_RELOC_MN10300_TLS_DTPMOD:
+    case BFD_RELOC_MN10300_TLS_DTPOFF:
+    case BFD_RELOC_MN10300_TLS_TPOFF:
+      S_SET_THREAD_LOCAL (exprP->X_add_symbol);
+      break;
+    default:
+      break;
+    }
+
   *input_line_pointer = *nextcharP;
   input_line_pointer = next_end;
   *nextcharP = *input_line_pointer;
Index: gas/testsuite/gas/mn10300/basic.exp
===================================================================
RCS file: /cvs/src/src/gas/testsuite/gas/mn10300/basic.exp,v
retrieving revision 1.11
diff -p -U3 -r1.11  gas/testsuite/gas/mn10300/basic.exp
--- gas/testsuite/gas/mn10300/basic.exp	5 May 2005 09:13:16 -0000	1.11
+++ gas/testsuite/gas/mn10300/basic.exp	11 May 2006 22:21:53 -0000
@@ -1819,3 +1819,8 @@ if [istarget mn10300*-*-*] then {
     run_dump_test "am33-2"
     run_dump_test "relax"
 }
+
+if [istarget am33*-*-*linux*] then {
+    run_dump_test "tls"
+    run_dump_test "tls2"
+}
Index: gas/testsuite/gas/mn10300/tls.d
===================================================================
RCS file: gas/testsuite/gas/mn10300/tls.d
diff -N  gas/testsuite/gas/mn10300/tls.d
--- gas/testsuite/gas/mn10300/tls.d	1 Jan 1970 00:00:00 -0000
+++ gas/testsuite/gas/mn10300/tls.d	11 May 2006 22:21:53 -0000
@@ -0,0 +1,26 @@
+# name: tls - am33 tls relocations
+# objdump: -dr
+
+dump.o:     file format elf32-am33lin
+
+Disassembly of section .text:
+
+00000000 <.text>:
+   0:	fc dc 00 00 	mov	0,a0
+   4:	00 00 
+			2: R_MN10300_TLS_GD	a
+   6:	fc dc 00 00 	mov	0,a0
+   a:	00 00 
+			8: R_MN10300_TLS_LD	b
+   c:	fc 20 00 00 	mov	\(0,a0\),a0
+  10:	00 00 
+			e: R_MN10300_TLS_LDO	c
+  12:	fc 22 00 00 	mov	\(0,a2\),a0
+  16:	00 00 
+			14: R_MN10300_TLS_GOTIE	d
+  18:	fc dc 00 00 	mov	0,a0
+  1c:	00 00 
+			1a: R_MN10300_TLS_IE	e
+  1e:	fc dc 00 00 	mov	0,a0
+  22:	00 00 
+			20: R_MN10300_TLS_LE	f
Index: gas/testsuite/gas/mn10300/tls.s
===================================================================
RCS file: gas/testsuite/gas/mn10300/tls.s
diff -N  gas/testsuite/gas/mn10300/tls.s
--- gas/testsuite/gas/mn10300/tls.s	1 Jan 1970 00:00:00 -0000
+++ gas/testsuite/gas/mn10300/tls.s	11 May 2006 22:21:53 -0000
@@ -0,0 +1,8 @@
+	.text
+
+	mov	+a@tlsgd,a0
+	mov	+b@tlsldm,a0
+	mov	(c@dtpoff,a0),a0
+	mov	(d@gotntpoff,a2),a0
+	mov	+e@indntpoff,a0
+	mov	+f@tpoff,a0
Index: gas/testsuite/gas/mn10300/tls2.d
===================================================================
RCS file: gas/testsuite/gas/mn10300/tls2.d
diff -N  gas/testsuite/gas/mn10300/tls2.d
--- gas/testsuite/gas/mn10300/tls2.d	1 Jan 1970 00:00:00 -0000
+++ gas/testsuite/gas/mn10300/tls2.d	11 May 2006 22:21:53 -0000
@@ -0,0 +1,27 @@
+# name: tls2 - am33 tls symbol types
+# readelf: -sr
+
+Relocation section '.rela.text' at offset 0x2e4 contains 6 entries:
+ Offset     Info    Type            Sym.Value  Sym. Name \+ Addend
+00000002  00000618 R_MN10300_TLS_GD  00000000   a \+ 0
+00000008  00000719 R_MN10300_TLS_LD  00000000   b \+ 0
+0000000e  0000081a R_MN10300_TLS_LDO 00000000   c \+ 0
+00000014  0000091b R_MN10300_TLS_GOT 00000000   d \+ 0
+0000001a  00000a1c R_MN10300_TLS_IE  00000000   e \+ 0
+00000020  00000b1d R_MN10300_TLS_LE  00000000   f \+ 0
+
+Symbol table '.symtab' contains 13 entries:
+   Num:    Value  Size Type    Bind   Vis      Ndx Name
+     0: 00000000     0 NOTYPE  LOCAL  DEFAULT  UND 
+     1: 00000000     0 SECTION LOCAL  DEFAULT    1 
+     2: 00000000     0 SECTION LOCAL  DEFAULT    3 
+     3: 00000000     0 SECTION LOCAL  DEFAULT    4 
+     4: 00000000     0 SECTION LOCAL  DEFAULT    5 
+     5: 00000004     4 TLS     LOCAL  DEFAULT    5 z
+     6: 00000000     0 TLS     GLOBAL DEFAULT  UND a
+     7: 00000000     0 TLS     GLOBAL DEFAULT  UND b
+     8: 00000000     0 TLS     GLOBAL DEFAULT  UND c
+     9: 00000000     0 TLS     GLOBAL DEFAULT  UND d
+    10: 00000000     0 TLS     GLOBAL DEFAULT  UND e
+    11: 00000000     0 TLS     GLOBAL DEFAULT  UND f
+    12: 00000000     4 TLS     GLOBAL DEFAULT    5 y
Index: gas/testsuite/gas/mn10300/tls2.s
===================================================================
RCS file: gas/testsuite/gas/mn10300/tls2.s
diff -N  gas/testsuite/gas/mn10300/tls2.s
--- gas/testsuite/gas/mn10300/tls2.s	1 Jan 1970 00:00:00 -0000
+++ gas/testsuite/gas/mn10300/tls2.s	11 May 2006 22:21:53 -0000
@@ -0,0 +1,19 @@
+	.text
+
+	mov	+a@tlsgd,a0
+	mov	+b@tlsldm,a0
+	mov	(c@dtpoff,a0),a0
+	mov	(d@gotntpoff,a2),a0
+	mov	+e@indntpoff,a0
+	mov	+f@tpoff,a0
+
+	.section	.tdata,"awT",@progbits
+	.global	y
+        .type   y, @object
+	.size	y, 4
+y:
+	.long	5
+	.size	z, 4
+        .type   z, @object
+z:
+	.long	6
Index: include/elf/mn10300.h
===================================================================
RCS file: /cvs/src/src/include/elf/mn10300.h,v
retrieving revision 1.10
diff -p -U3 -r1.10  include/elf/mn10300.h
--- include/elf/mn10300.h	10 May 2005 10:21:10 -0000	1.10
+++ include/elf/mn10300.h	11 May 2006 22:21:53 -0000
@@ -50,6 +50,16 @@ START_RELOC_NUMBERS (elf_mn10300_reloc_t
   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)
 END_RELOC_NUMBERS (R_MN10300_MAX)
 
 /* Machine variant if we know it.  This field was invented at Cygnus,

begin 644 ld-testsuite-am33.tar.gz
M'XL(`)^R8T0"`^U:;7/B.!+.5_M7]&7N0Y(SC.07()FKJS`)F:4J"2D@MY7:
M;%'"DH/W#*9LDP%2\]^OY1=,2`(S-QDNN^/."[;TJ-62_*A;;CS^/A)A%$[<
M2+SW>(D-#>/]SNL*(42O6I;\)%0WXT^2?2:R0XEID*I!J8XX:AJFO@/6SA9D
M$D8L`-CA?ZS'W;&A"-</,AY(]ODG$>^Y]9?_RF(Z?KWU)Q73?&G]=9.8*^MO
M572Z`Z18_Q\N[Z`Q'0L[@M`.W'$$CA]`^AA`_&"H[P#@Q!_/`O=N$,'>R3[H
MA!AP%@@!'=^)/K-`P)D_&7$6N?Y(?8<MN@,W!,?U!,A/B0Q3Y`>8^1.PV0@"
MP=TP"MS^)$)8!&S$WV/G0Y^[S@QU8!'J%`%$`X&F!,,0?">^^71Y#9_$2`3,
M@ZM)WW-M.'=M,0H%L!#&LB0<"`Y]J48V>,G6#R!<K`_@7@0AWH.>=9'JT\`/
M4,<>BZ39`?ACV6P?;9V!QZ*\93D?]CCP[P(VE"//!\C!'<6*!_X81S-`A3B^
MSZ[G05_`)!3.Q--0`V+AUV;WE]9U%^J7-_!KO=VN7W9O/B`V&OA8*^Y%HLD=
MCCT7%>.8`C:*9F@Z*KAHM$]^P1;UC\WS9O<&[8>S9O>RT>G`6:L-=;BJM[O-
MD^OS>ANNKMM7K4ZC#-`1TBB![=?,K1.O#DX@%Q%SO3`9\PTN9XB6>1P&[%[@
MLMK"O4>[&-CXU&Q>,]3!/']T%X\0L?D4?@#7@9$?:?`YP.T)(O_I:F+K?#TU
M:([LL@;6(70%3H^`*X_9`DK0D?L;&`;1X*,?1A)Z40>B4TI+%#<>#:X[=3D@
M%;M\^-O>;Z[<%NY$!+N2"@<E_/'<T61ZL/O[/GR!!Q59@6.-)L%(_:*J(2(E
ML!=S)JU^P+^X.7PZU<Y/H7O>T7"NT&J^JRJ[I>022L[8M64!_CW`[ATO15Y8
MHN5P=W&CRYLOLOK![__!)\,QE/@<TEH^+W.LA*7*=E;7CJOP-U55#OW=V+@O
M3TPL-1N)B6(J,GMRFUR1FX37+UN$E:E!::^N*$^?[[/9*)V_V"?J\;(^D^L7
M^DPJE_J,"_(^<7F"R:CG\1ZNX'_2%?I[OEKJSD\LS_K_9`+#G>WX?V)4JHG_
MMTC%,*K2_UN&7OC_;8A2CL0T4I7RG>?WF:<XOJ_V\-^1JBI#_U[9^\?T^,Z/
M1M'8=QR-Z?L:HZK".%>$%5\FH-G7@.;K02-_C)V60XQ&<"]'PW!39]HN^]S=
MU8ZE2^B[2%:E/'`Y1Q\XRXV6EZ$[%\I,`U.='>&M]"B*E97/9?E\45[YJ2F_
MF?^++7Y+_"=&PG^SBH&_'L?_EE'P?XO\3RB*7,<0X8YKP$E"348T>6DSSU-Z
M/:SL84S4PYI`^^UWC63M9K*=QX??TO!KZ9YR?)IQ>2JY/%UPV2RX_"/XGX:@
MV^%_E:;G?ZI7"$7^5TC!_[?A_Q]M"<^Q/2V;/R[['E\.J92C&9Z5`="I'V.\
MCZJ^RLVO-I_GS8L(X%O\OSQ1;8/_M$J-+/Y'QT\D__%<7O!_&Z*6#](C^E',
MFOBEG>,'0Q:!\!Q#CY\(/#BKZJD;LC`4P[X7O]5)N0WQ!H+;!:G)<1^:\$^Y
M?_SK2(6TX$AQ;-`)$!L(@7B[N-VCNL;(+9X!2(:K'2E8C;]9`<.&AU"M@5Z3
MEL5A1:`OM>"Q9F%"TD[Q`R6..I)J1E<4,N-(J1!82&P))]KMGK0D`TES+:C5
MED'+O;+*^E[9:J\VX@700]#U'!_H:76?9/B\2=^(NZ`$'!,<9\G04CIM&;"*
M0$="LH+##=;W^VNM[SLKUMMTK?6V]=1ZN[:POK9B?6W9>-M>,=X61XK=7UH?
M=")*5N=\W5/$C94!<&O#4\1K:V>$VZL*Q88I%F2M0F&N*!25M5,LV-,I%ORY
MF7KU^$_?4ORGZ^8B_K-DGA#COTJQ__^?SW_/!WO??&I;#<>F3Z*YXD#W1L]_
MKQ4`;N*_9:3O?ZLZD2]^D?\&K1;\WU[\ER2&OCL"C!>8+T6`>!,[0]M>]MOH
MM:4[I'PIY*.<94AJ+I`Z29%B"9DZV.>1R^Z52M?Z3$1!176-5:*_K(&OZ<M9
MBC"I8[R:3WXK_&]OY_Q'S&HEY[]53<Y_9L'_M\?_F\OZ1?,$VHWSUDF]VVQ=
MXN5)JWW:45MG9YU&%YMW;ZX:\$C^73^_;H":K3:T>Q>7E!B$]"Y;ES'V]J#^
ML7-[\(H0JM?L)4CWO-,[[5Y=M$Z?P,P78-,,4'L*P,%*@/H7B%1>SO^^VNO?
MS?Z_8J7O?RBEI)+D?RH%_]_"^]\]>7/\J=5-,K9DZVGAO#]WQ!/4BYUM0LS7
M('[2[/,:_F\M_TNS[W]:5`8#,?_-(O[?$O^_-P%K%>?UOV;^9WO^WZHL\C^F
ME7[_H^#_F_#_W_Z5D.Q]/^PQLO^_?T$D5S,[YFEPD.N;?X>^^6-]/_?7SM;X
M_ZWE?W737)S_*[3(_V[Y_)]^7?H'YW_UIYD[?7/^UP;.`?]G><22*8/U%"!6
M$HB,9+D^ZS#/]5EY"V8L5.:)U3BGND"L9E39X2:=]D)GGNZ4F4ZZE.%]G*35
M-ZCL6QM&'J=Y'ZGL;U(I-HW<UE?3L>8&G79UP\CM_JI*OD$E)W_*EZB%%%)(
C(8444D@AA1122"&%%%)((8444D@AA13RQN2_0OA*R`!0````
`
end


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]