This is the mail archive of the
binutils@sourceware.org
mailing list for the binutils project.
[patch] am33 TLS support
- From: DJ Delorie <dj at redhat dot com>
- To: binutils at sourceware dot org
- Date: Thu, 11 May 2006 19:17:47 -0400
- Subject: [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
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
C(8444D@AA1122"&%%%)((8444D@AA13RQN2_0OA*R`!0````
`
end