aboutsummaryrefslogtreecommitdiff
path: root/bfd
diff options
context:
space:
mode:
authorKaz Kojima <kkojima@rr.iij4u.or.jp>2002-10-11 14:32:03 +0000
committerKaz Kojima <kkojima@rr.iij4u.or.jp>2002-10-11 14:32:03 +0000
commit3376eaf57788bb1487e6d96bd74c647612dd91c9 (patch)
treeed21040f9814662bc28babc6ad4addfe505602a9 /bfd
parent5dc976556d5fa7518147ddb609b3c274df56ab79 (diff)
downloadgdb-3376eaf57788bb1487e6d96bd74c647612dd91c9.zip
gdb-3376eaf57788bb1487e6d96bd74c647612dd91c9.tar.gz
gdb-3376eaf57788bb1487e6d96bd74c647612dd91c9.tar.bz2
* elf32-sh.c (sh_elf_optimized_tls_reloc, sh_elf_mkobject,
sh_elf_object_p, dtpoff_base): New functions. (sh_elf_howto_table): Add TLS relocs. (sh_reloc_map): Likewise. (sh_elf_info_to_howto): Support TLS relocs. (elf_sh_link_hash_entry): Add tls_type and tls_tpoff32. (sh_elf_hash_entry, sh_elf_tdata, sh_elf_local_got_tls_type): New macros. (sh_elf_obj_tdata): New. (elf_sh_link_hash_table): Add tls_ldm_got. (sh_elf_link_hash_table_create): Clear refcount of tls_ldm_got. (allocate_dynrelocs): Support TLS relocs. (sh_elf_size_dynamic_sections): Likewise. (sh_elf_relocate_section): Support TLS relocs. Don't try to find .rela.got section when found already. Return false after printing error about unresolvable relocation. (sh_elf_gc_sweep_hook): Support TLS relocs. (sh_elf_check_relocs): Likewise. (sh_elf_finish_dynamic_symbol): Likewise. (bfd_elf32_mkobject, elf_backend_object_p): Define for TLS case. * reloc.c: Add SH TLS relocs. * libbfd.h: Regenerate.
Diffstat (limited to 'bfd')
-rw-r--r--bfd/elf32-sh.c961
-rw-r--r--bfd/libbfd.h8
-rw-r--r--bfd/reloc.c16
3 files changed, 959 insertions, 26 deletions
diff --git a/bfd/elf32-sh.c b/bfd/elf32-sh.c
index 5fe0f58..53d2841 100644
--- a/bfd/elf32-sh.c
+++ b/bfd/elf32-sh.c
@@ -59,6 +59,12 @@ static bfd_byte *sh_elf_get_relocated_section_contents
static void sh_elf_copy_indirect_symbol
PARAMS ((struct elf_backend_data *, struct elf_link_hash_entry *,
struct elf_link_hash_entry *));
+static int sh_elf_optimized_tls_reloc
+ PARAMS ((struct bfd_link_info *, int, int));
+static boolean sh_elf_mkobject
+ PARAMS((bfd *));
+static boolean sh_elf_object_p
+ PARAMS((bfd *));
static boolean sh_elf_check_relocs
PARAMS ((bfd *, struct bfd_link_info *, asection *,
const Elf_Internal_Rela *));
@@ -82,6 +88,8 @@ static boolean create_got_section
PARAMS((bfd *, struct bfd_link_info *));
static boolean sh_elf_create_dynamic_sections
PARAMS ((bfd *, struct bfd_link_info *));
+static bfd_vma dtpoff_base
+ PARAMS ((struct bfd_link_info *));
static asection * sh_elf_gc_mark_hook
PARAMS ((asection *, struct bfd_link_info *, Elf_Internal_Rela *,
struct elf_link_hash_entry *, Elf_Internal_Sym *));
@@ -713,14 +721,119 @@ static reloc_howto_type sh_elf_howto_table[] =
EMPTY_HOWTO (141),
EMPTY_HOWTO (142),
EMPTY_HOWTO (143),
- EMPTY_HOWTO (144),
- EMPTY_HOWTO (145),
- EMPTY_HOWTO (146),
- EMPTY_HOWTO (147),
- EMPTY_HOWTO (148),
- EMPTY_HOWTO (149),
- EMPTY_HOWTO (150),
- EMPTY_HOWTO (151),
+
+ HOWTO (R_SH_TLS_GD_32, /* 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_SH_TLS_GD_32", /* name */
+ true, /* partial_inplace */
+ 0xffffffff, /* src_mask */
+ 0xffffffff, /* dst_mask */
+ false), /* pcrel_offset */
+
+ HOWTO (R_SH_TLS_LD_32, /* 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_SH_TLS_LD_32", /* name */
+ true, /* partial_inplace */
+ 0xffffffff, /* src_mask */
+ 0xffffffff, /* dst_mask */
+ false), /* pcrel_offset */
+
+ HOWTO (R_SH_TLS_LDO_32, /* 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_SH_TLS_LDO_32", /* name */
+ true, /* partial_inplace */
+ 0xffffffff, /* src_mask */
+ 0xffffffff, /* dst_mask */
+ false), /* pcrel_offset */
+
+ HOWTO (R_SH_TLS_IE_32, /* 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_SH_TLS_IE_32", /* name */
+ true, /* partial_inplace */
+ 0xffffffff, /* src_mask */
+ 0xffffffff, /* dst_mask */
+ false), /* pcrel_offset */
+
+ HOWTO (R_SH_TLS_LE_32, /* 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_SH_TLS_LE_32", /* name */
+ true, /* partial_inplace */
+ 0xffffffff, /* src_mask */
+ 0xffffffff, /* dst_mask */
+ false), /* pcrel_offset */
+
+ HOWTO (R_SH_TLS_DTPMOD32, /* 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_SH_TLS_DTPMOD32", /* name */
+ true, /* partial_inplace */
+ 0xffffffff, /* src_mask */
+ 0xffffffff, /* dst_mask */
+ false), /* pcrel_offset */
+
+ HOWTO (R_SH_TLS_DTPOFF32, /* 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_SH_TLS_DTPOFF32", /* name */
+ true, /* partial_inplace */
+ 0xffffffff, /* src_mask */
+ 0xffffffff, /* dst_mask */
+ false), /* pcrel_offset */
+
+ HOWTO (R_SH_TLS_TPOFF32, /* 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_SH_TLS_TPOFF32", /* name */
+ true, /* partial_inplace */
+ 0xffffffff, /* src_mask */
+ 0xffffffff, /* dst_mask */
+ false), /* pcrel_offset */
+
EMPTY_HOWTO (152),
EMPTY_HOWTO (153),
EMPTY_HOWTO (154),
@@ -1776,6 +1889,14 @@ static const struct elf_reloc_map sh_reloc_map[] =
{ BFD_RELOC_VTABLE_ENTRY, R_SH_GNU_VTENTRY },
{ BFD_RELOC_SH_LOOP_START, R_SH_LOOP_START },
{ BFD_RELOC_SH_LOOP_END, R_SH_LOOP_END },
+ { BFD_RELOC_SH_TLS_GD_32, R_SH_TLS_GD_32 },
+ { BFD_RELOC_SH_TLS_LD_32, R_SH_TLS_LD_32 },
+ { BFD_RELOC_SH_TLS_LDO_32, R_SH_TLS_LDO_32 },
+ { BFD_RELOC_SH_TLS_IE_32, R_SH_TLS_IE_32 },
+ { BFD_RELOC_SH_TLS_LE_32, R_SH_TLS_LE_32 },
+ { BFD_RELOC_SH_TLS_DTPMOD32, R_SH_TLS_DTPMOD32 },
+ { BFD_RELOC_SH_TLS_DTPOFF32, R_SH_TLS_DTPOFF32 },
+ { BFD_RELOC_SH_TLS_TPOFF32, R_SH_TLS_TPOFF32 },
{ BFD_RELOC_32_GOT_PCREL, R_SH_GOT32 },
{ BFD_RELOC_32_PLT_PCREL, R_SH_PLT32 },
{ BFD_RELOC_SH_COPY, R_SH_COPY },
@@ -1874,6 +1995,7 @@ sh_elf_info_to_howto (abfd, cache_ptr, dst)
BFD_ASSERT (r < R_SH_FIRST_INVALID_RELOC_2 || r > R_SH_LAST_INVALID_RELOC_2);
BFD_ASSERT (r < R_SH_FIRST_INVALID_RELOC_3 || r > R_SH_LAST_INVALID_RELOC_3);
BFD_ASSERT (r < R_SH_FIRST_INVALID_RELOC_4 || r > R_SH_LAST_INVALID_RELOC_4);
+ BFD_ASSERT (r < R_SH_FIRST_INVALID_RELOC_5 || r > R_SH_LAST_INVALID_RELOC_5);
cache_ptr->howto = &sh_elf_howto_table[r];
}
@@ -3390,8 +3512,45 @@ struct elf_sh_link_hash_entry
struct elf_sh_dyn_relocs *dyn_relocs;
bfd_signed_vma gotplt_refcount;
+
+ enum {
+ GOT_UNKNOWN = 0, GOT_NORMAL, GOT_TLS_GD, GOT_TLS_IE
+ } tls_type;
+
+ /* If true, R_SH_TLS_TPOFF32 relocation is generated. */
+ boolean tls_tpoff32;
+};
+
+#define sh_elf_hash_entry(ent) ((struct elf_sh_link_hash_entry *)(ent))
+
+struct sh_elf_obj_tdata
+{
+ struct elf_obj_tdata root;
+
+ /* tls_type for each local got entry. */
+ char *local_got_tls_type;
};
+#define sh_elf_tdata(abfd) \
+ ((struct sh_elf_obj_tdata *) (abfd)->tdata.any)
+
+#define sh_elf_local_got_tls_type(abfd) \
+ (sh_elf_tdata (abfd)->local_got_tls_type)
+
+/* Override the generic function because we need to store sh_elf_obj_tdata
+ as the specific tdata. */
+
+static boolean
+sh_elf_mkobject (abfd)
+ bfd *abfd;
+{
+ bfd_size_type amt = sizeof (struct sh_elf_obj_tdata);
+ abfd->tdata.any = bfd_zalloc (abfd, amt);
+ if (abfd->tdata.any == NULL)
+ return false;
+ return true;
+}
+
/* sh ELF linker hash table. */
struct elf_sh_link_hash_table
@@ -3409,6 +3568,13 @@ struct elf_sh_link_hash_table
/* Small local sym to section mapping cache. */
struct sym_sec_cache sym_sec;
+
+ /* A counter or offset to track a TLS got entry. */
+ union
+ {
+ bfd_signed_vma refcount;
+ bfd_vma offset;
+ } tls_ldm_got;
};
/* Traverse an sh ELF linker hash table. */
@@ -3458,6 +3624,8 @@ sh_elf_link_hash_newfunc (entry, table, string)
#ifdef INCLUDE_SHMEDIA
ret->datalabel_got_offset = (bfd_vma) -1;
#endif
+ ret->tls_type = GOT_UNKNOWN;
+ ret->tls_tpoff32 = false;
}
return (struct bfd_hash_entry *) ret;
@@ -3491,6 +3659,7 @@ sh_elf_link_hash_table_create (abfd)
ret->sdynbss = NULL;
ret->srelbss = NULL;
ret->sym_sec.abfd = NULL;
+ ret->tls_ldm_got.refcount = 0;
return &ret->root.root;
}
@@ -3946,6 +4115,7 @@ allocate_dynrelocs (h, inf)
{
asection *s;
boolean dyn;
+ int tls_type = sh_elf_hash_entry (h)->tls_type;
/* Make sure this symbol is output as a dynamic symbol.
Undefined weak syms won't yet be marked as dynamic. */
@@ -3972,8 +4142,18 @@ allocate_dynrelocs (h, inf)
h->got.offset = s->_raw_size;
#endif
s->_raw_size += 4;
+ /* R_SH_TLS_GD needs 2 consecutive GOT slots. */
+ if (tls_type == GOT_TLS_GD)
+ s->_raw_size += 4;
dyn = htab->root.dynamic_sections_created;
- if (WILL_CALL_FINISH_DYNAMIC_SYMBOL (dyn, info, h))
+ /* R_SH_TLS_IE_32 needs one dynamic relocation,
+ R_SH_TLS_GD needs one if local symbol and two if global. */
+ if ((tls_type == GOT_TLS_GD && h->dynindx == -1)
+ || tls_type == GOT_TLS_IE)
+ htab->srelgot->_raw_size += sizeof (Elf32_External_Rela);
+ else if (tls_type == GOT_TLS_GD)
+ htab->srelgot->_raw_size += 2 * sizeof (Elf32_External_Rela);
+ else if (WILL_CALL_FINISH_DYNAMIC_SYMBOL (dyn, info, h))
htab->srelgot->_raw_size += sizeof (Elf32_External_Rela);
}
else
@@ -4009,6 +4189,9 @@ allocate_dynrelocs (h, inf)
}
else
{
+ if (sh_elf_hash_entry (h)->tls_tpoff32)
+ goto keep;
+
/* For the non-shared case, discard space for relocs against
symbols which turn out to need copy relocs or are not
dynamic. */
@@ -4116,6 +4299,7 @@ sh_elf_size_dynamic_sections (output_bfd, info)
{
bfd_signed_vma *local_got;
bfd_signed_vma *end_local_got;
+ char *local_tls_type;
bfd_size_type locsymcount;
Elf_Internal_Shdr *symtab_hdr;
asection *srel;
@@ -4161,6 +4345,7 @@ sh_elf_size_dynamic_sections (output_bfd, info)
locsymcount *= 2;
#endif
end_local_got = local_got + locsymcount;
+ local_tls_type = sh_elf_local_got_tls_type (ibfd);
s = htab->sgot;
srel = htab->srelgot;
for (; local_got < end_local_got; ++local_got)
@@ -4169,14 +4354,28 @@ sh_elf_size_dynamic_sections (output_bfd, info)
{
*local_got = s->_raw_size;
s->_raw_size += 4;
+ if (*local_tls_type == GOT_TLS_GD)
+ s->_raw_size += 4;
if (info->shared)
srel->_raw_size += sizeof (Elf32_External_Rela);
}
else
*local_got = (bfd_vma) -1;
+ ++local_tls_type;
}
}
+ if (htab->tls_ldm_got.refcount > 0)
+ {
+ /* Allocate 2 got entries and 1 dynamic reloc for R_SH_TLS_LD_32
+ relocs. */
+ htab->tls_ldm_got.offset = htab->sgot->_raw_size;
+ htab->sgot->_raw_size += 8;
+ htab->srelgot->_raw_size += sizeof (Elf32_External_Rela);
+ }
+ else
+ htab->tls_ldm_got.offset = -1;
+
/* Allocate global sym .plt and .got entries, and space for global
sym dynamic relocs. */
elf_link_hash_traverse (&htab->root, allocate_dynrelocs, (PTR) info);
@@ -4312,6 +4511,7 @@ sh_elf_relocate_section (output_bfd, info, input_bfd, input_section,
asection *sgotplt;
asection *splt;
asection *sreloc;
+ asection *srelgot;
htab = sh_elf_hash_table (info);
symtab_hdr = &elf_tdata (input_bfd)->symtab_hdr;
@@ -4323,6 +4523,7 @@ sh_elf_relocate_section (output_bfd, info, input_bfd, input_section,
sgotplt = htab->sgotplt;
splt = htab->splt;
sreloc = NULL;
+ srelgot = NULL;
rel = relocs;
relend = relocs + input_section->reloc_count;
@@ -4338,6 +4539,8 @@ sh_elf_relocate_section (output_bfd, info, input_bfd, input_section,
bfd_vma addend = (bfd_vma) 0;
bfd_reloc_status_type r;
int seen_stt_datalabel = 0;
+ bfd_vma off;
+ int tls_type;
r_symndx = ELF32_R_SYM (rel->r_info);
@@ -4359,6 +4562,8 @@ sh_elf_relocate_section (output_bfd, info, input_bfd, input_section,
&& r_type <= (int) R_SH_LAST_INVALID_RELOC_3)
|| ( r_type >= (int) R_SH_FIRST_INVALID_RELOC_4
&& r_type <= (int) R_SH_LAST_INVALID_RELOC_4)
+ || ( r_type >= (int) R_SH_FIRST_INVALID_RELOC_5
+ && r_type <= (int) R_SH_LAST_INVALID_RELOC_5)
|| (r_type >= (int) R_SH_FIRST_INVALID_RELOC_2
&& r_type <= (int) R_SH_LAST_INVALID_RELOC_2))
{
@@ -4529,15 +4734,18 @@ sh_elf_relocate_section (output_bfd, info, input_bfd, input_section,
with them here. */
|| ((input_section->flags & SEC_DEBUGGING) != 0
&& (h->elf_link_hash_flags
- & ELF_LINK_HASH_DEF_DYNAMIC) != 0))))
+ & ELF_LINK_HASH_DEF_DYNAMIC) != 0)))
+ || (sec->output_section == NULL
+ && (sh_elf_hash_entry (h)->tls_type == GOT_TLS_IE
+ || sh_elf_hash_entry (h)->tls_type == GOT_TLS_GD)))
relocation = 0;
else if (sec->output_section == NULL)
{
(*_bfd_error_handler)
- (_("%s: warning: unresolvable relocation against symbol `%s' from %s section"),
+ (_("%s: unresolvable relocation against symbol `%s' from %s section"),
bfd_archive_filename (input_bfd), h->root.root.string,
bfd_get_section_name (input_bfd, input_section));
- relocation = 0;
+ return false;
}
else
relocation = ((h->root.u.def.value
@@ -4782,7 +4990,6 @@ sh_elf_relocate_section (output_bfd, info, input_bfd, input_section,
if (h != NULL)
{
- bfd_vma off;
boolean dyn;
off = h->got.offset;
@@ -4840,8 +5047,6 @@ sh_elf_relocate_section (output_bfd, info, input_bfd, input_section,
}
else
{
- bfd_vma off;
-
#ifdef INCLUDE_SHMEDIA
if (rel->r_addend)
{
@@ -4875,11 +5080,14 @@ sh_elf_relocate_section (output_bfd, info, input_bfd, input_section,
if (info->shared)
{
- asection *srelgot;
Elf_Internal_Rela outrel;
- srelgot = bfd_get_section_by_name (dynobj, ".rela.got");
- BFD_ASSERT (srelgot != NULL);
+ if (srelgot == NULL)
+ {
+ srelgot = bfd_get_section_by_name (dynobj,
+ ".rela.got");
+ BFD_ASSERT (srelgot != NULL);
+ }
outrel.r_offset = (sgot->output_section->vma
+ sgot->output_offset
@@ -5013,6 +5221,450 @@ sh_elf_relocate_section (output_bfd, info, input_bfd, input_section,
rel->r_offset, sec, start, end);
break;
}
+
+ case R_SH_TLS_GD_32:
+ case R_SH_TLS_IE_32:
+ r_type = sh_elf_optimized_tls_reloc (info, r_type, h == NULL);
+ tls_type = GOT_UNKNOWN;
+ if (h == NULL && local_got_offsets)
+ tls_type = sh_elf_local_got_tls_type (input_bfd) [r_symndx];
+ else if (h != NULL)
+ {
+ tls_type = sh_elf_hash_entry (h)->tls_type;
+ if (! info->shared
+ && (h->dynindx == -1
+ || (h->elf_link_hash_flags & ELF_LINK_HASH_DEF_REGULAR))
+ && (tls_type == GOT_TLS_IE
+ || sh_elf_hash_entry (h)->tls_tpoff32))
+ r_type = R_SH_TLS_LE_32;
+ }
+
+ if (r_type == R_SH_TLS_GD_32 && tls_type == GOT_TLS_IE)
+ r_type = R_SH_TLS_IE_32;
+
+ if (r_type == R_SH_TLS_LE_32)
+ {
+ bfd_vma offset;
+ unsigned short insn;
+ int indx;
+ Elf_Internal_Rela outrel;
+
+ if (ELF32_R_TYPE (rel->r_info) == R_SH_TLS_GD_32)
+ {
+ /* GD->LE transition:
+ mov.l 1f,r4; mova 2f,r0; mov.l 2f,r1; add r0,r1;
+ jsr @r1; add r12,r4; bra 3f; nop; .align 2;
+ 1: .long x$TLSGD; 2: .long __tls_get_addr@PLT; 3:
+ We change it into:
+ mov.l 1f,r4; stc gbr,r0; add r4,r0; nop;
+ nop; nop; ...
+ 1: .long x@TPOFF; 2: .long __tls_get_addr@PLT; 3:. */
+
+ offset = rel->r_offset;
+ BFD_ASSERT (offset >= 16);
+ /* Size of GD instructions is 16 or 18. */
+ offset -= 16;
+ insn = bfd_get_16 (input_bfd, contents + offset + 0);
+ if ((insn & 0xff00) == 0xc700)
+ {
+ BFD_ASSERT (offset >= 2);
+ offset -= 2;
+ insn = bfd_get_16 (input_bfd, contents + offset + 0);
+ }
+
+ BFD_ASSERT ((insn & 0xff00) == 0xd400);
+ insn = bfd_get_16 (input_bfd, contents + offset + 2);
+ BFD_ASSERT ((insn & 0xff00) == 0xc700);
+ insn = bfd_get_16 (input_bfd, contents + offset + 4);
+ BFD_ASSERT ((insn & 0xff00) == 0xd100);
+ insn = bfd_get_16 (input_bfd, contents + offset + 6);
+ BFD_ASSERT (insn == 0x310c);
+ insn = bfd_get_16 (input_bfd, contents + offset + 8);
+ BFD_ASSERT (insn == 0x410b);
+ insn = bfd_get_16 (input_bfd, contents + offset + 10);
+ BFD_ASSERT (insn == 0x34cc);
+
+ bfd_put_16 (output_bfd, 0x0012, contents + offset + 2);
+ bfd_put_16 (output_bfd, 0x304c, contents + offset + 4);
+ bfd_put_16 (output_bfd, 0x0009, contents + offset + 6);
+ bfd_put_16 (output_bfd, 0x0009, contents + offset + 8);
+ bfd_put_16 (output_bfd, 0x0009, contents + offset + 10);
+ }
+ else
+ {
+ int index;
+
+ /* IE->LE transition:
+ mov.l 1f,r0; stc gbr,rN; mov.l @(r0,r12),rM;
+ bra 2f; add ...; .align 2; 1: x@GOTTPOFF; 2:
+ We change it into:
+ mov.l .Ln,rM; stc gbr,rN; nop; ...;
+ 1: x@TPOFF; 2:. */
+
+ offset = rel->r_offset;
+ BFD_ASSERT (offset >= 16);
+ /* Size of IE instructions is 10 or 12. */
+ offset -= 10;
+ insn = bfd_get_16 (input_bfd, contents + offset + 0);
+ if ((insn & 0xf0ff) == 0x0012)
+ {
+ BFD_ASSERT (offset >= 2);
+ offset -= 2;
+ insn = bfd_get_16 (input_bfd, contents + offset + 0);
+ }
+
+ BFD_ASSERT ((insn & 0xff00) == 0xd000);
+ index = insn & 0x00ff;
+ insn = bfd_get_16 (input_bfd, contents + offset + 2);
+ BFD_ASSERT ((insn & 0xf0ff) == 0x0012);
+ insn = bfd_get_16 (input_bfd, contents + offset + 4);
+ BFD_ASSERT ((insn & 0xf0ff) == 0x00ce);
+ insn = 0xd000 | (insn & 0x0f00) | index;
+ bfd_put_16 (output_bfd, insn, contents + offset + 0);
+ bfd_put_16 (output_bfd, 0x0009, contents + offset + 4);
+ }
+
+ if (sreloc == NULL)
+ {
+ const char *name;
+
+ name = (bfd_elf_string_from_elf_section
+ (input_bfd,
+ elf_elfheader (input_bfd)->e_shstrndx,
+ elf_section_data (input_section)->rel_hdr.sh_name));
+ if (name == NULL)
+ return false;
+
+ BFD_ASSERT (strncmp (name, ".rela", 5) == 0
+ && strcmp (bfd_get_section_name (input_bfd,
+ input_section),
+ name + 5) == 0);
+
+ sreloc = bfd_get_section_by_name (dynobj, name);
+ BFD_ASSERT (sreloc != NULL);
+ }
+
+ indx = (h && h->dynindx != -1) ? h->dynindx : 0;
+ outrel.r_offset = (input_section->output_section->vma
+ + input_section->output_offset
+ + rel->r_offset);
+ outrel.r_info = ELF32_R_INFO (indx, R_SH_TLS_TPOFF32);
+ if (indx == 0)
+ outrel.r_addend = relocation - dtpoff_base (info);
+ else
+ outrel.r_addend = 0;
+ bfd_elf32_swap_reloca_out (output_bfd, &outrel,
+ (((Elf32_External_Rela *)
+ sreloc->contents)
+ + sreloc->reloc_count));
+ ++sreloc->reloc_count;
+
+ continue;
+ }
+
+ sgot = htab->sgot;
+ if (sgot == NULL)
+ abort ();
+
+ if (h != NULL)
+ off = h->got.offset;
+ else
+ {
+ if (local_got_offsets == NULL)
+ abort ();
+
+ off = local_got_offsets[r_symndx];
+ }
+
+ if ((off & 1) != 0)
+ off &= ~1;
+ else
+ {
+ Elf_Internal_Rela outrel;
+ Elf32_External_Rela *loc;
+ int dr_type, indx;
+
+ if (srelgot == NULL)
+ {
+ srelgot = bfd_get_section_by_name (dynobj, ".rela.got");
+ BFD_ASSERT (srelgot != NULL);
+ }
+
+ outrel.r_offset = (sgot->output_section->vma
+ + sgot->output_offset + off);
+
+ indx = (h && h->dynindx != -1) ? h->dynindx : 0;
+ dr_type = (r_type == R_SH_TLS_GD_32 ? R_SH_TLS_DTPMOD32 :
+ R_SH_TLS_TPOFF32);
+ if (dr_type == R_SH_TLS_TPOFF32 && indx == 0)
+ outrel.r_addend = relocation - dtpoff_base (info);
+ else
+ outrel.r_addend = 0;
+ outrel.r_info = ELF32_R_INFO (indx, dr_type);
+ loc = (Elf32_External_Rela *) srelgot->contents;
+ loc += srelgot->reloc_count++;
+ bfd_elf32_swap_reloca_out (output_bfd, &outrel, loc);
+
+ if (r_type == R_SH_TLS_GD_32)
+ {
+ if (indx == 0)
+ {
+ bfd_put_32 (output_bfd,
+ relocation - dtpoff_base (info),
+ sgot->contents + off + 4);
+ }
+ else
+ {
+ outrel.r_info = ELF32_R_INFO (indx,
+ R_SH_TLS_DTPOFF32);
+ outrel.r_offset += 4;
+ outrel.r_addend = 0;
+ srelgot->reloc_count++;
+ loc++;
+ bfd_elf32_swap_reloca_out (output_bfd, &outrel,
+ loc);
+ }
+ }
+
+ if (h != NULL)
+ h->got.offset |= 1;
+ else
+ local_got_offsets[r_symndx] |= 1;
+ }
+
+ if (off >= (bfd_vma) -2)
+ abort ();
+
+ if (r_type == (int) ELF32_R_TYPE (rel->r_info))
+ relocation = sgot->output_offset + off;
+ else
+ {
+ bfd_vma offset;
+ unsigned short insn;
+
+ /* GD->IE transition:
+ mov.l 1f,r4; mova 2f,r0; mov.l 2f,r1; add r0,r1;
+ jsr @r1; add r12,r4; bra 3f; nop; .align 2;
+ 1: .long x$TLSGD; 2: .long __tls_get_addr@PLT; 3:
+ We change it into:
+ mov.l 1f,r0; stc gbr,r4; mov.l @(r0,r12),r0; add r4,r0;
+ nop; nop; bra 3f; nop; .align 2;
+ 1: .long x@TPOFF; 2:...; 3:. */
+
+ offset = rel->r_offset;
+ BFD_ASSERT (offset >= 16);
+ /* Size of GD instructions is 16 or 18. */
+ offset -= 16;
+ insn = bfd_get_16 (input_bfd, contents + offset + 0);
+ if ((insn & 0xff00) == 0xc700)
+ {
+ BFD_ASSERT (offset >= 2);
+ offset -= 2;
+ insn = bfd_get_16 (input_bfd, contents + offset + 0);
+ }
+
+ BFD_ASSERT ((insn & 0xff00) == 0xd400);
+
+ /* Replace mov.l 1f,R4 with mov.l 1f,r0. */
+ bfd_put_16 (output_bfd, insn & 0xf0ff, contents + offset);
+
+ insn = bfd_get_16 (input_bfd, contents + offset + 2);
+ BFD_ASSERT ((insn & 0xff00) == 0xc700);
+ insn = bfd_get_16 (input_bfd, contents + offset + 4);
+ BFD_ASSERT ((insn & 0xff00) == 0xd100);
+ insn = bfd_get_16 (input_bfd, contents + offset + 6);
+ BFD_ASSERT (insn == 0x310c);
+ insn = bfd_get_16 (input_bfd, contents + offset + 8);
+ BFD_ASSERT (insn == 0x410b);
+ insn = bfd_get_16 (input_bfd, contents + offset + 10);
+ BFD_ASSERT (insn == 0x34cc);
+
+ bfd_put_16 (output_bfd, 0x0412, contents + offset + 2);
+ bfd_put_16 (output_bfd, 0x00ce, contents + offset + 4);
+ bfd_put_16 (output_bfd, 0x304c, contents + offset + 6);
+ bfd_put_16 (output_bfd, 0x0009, contents + offset + 8);
+ bfd_put_16 (output_bfd, 0x0009, contents + offset + 10);
+
+ bfd_put_32 (output_bfd, sgot->output_offset + off,
+ contents + rel->r_offset);
+
+ continue;
+ }
+
+ addend = rel->r_addend;
+
+ goto final_link_relocate;
+
+ case R_SH_TLS_LD_32:
+ if (! info->shared)
+ {
+ bfd_vma offset;
+ unsigned short insn;
+
+ /* LD->LE transition:
+ mov.l 1f,r4; mova 2f,r0; mov.l 2f,r1; add r0,r1;
+ jsr @r1; add r12,r4; bra 3f; nop; .align 2;
+ 1: .long x$TLSLD; 2: .long __tls_get_addr@PLT; 3:
+ We change it into:
+ stc gbr,r0; nop; nop; nop;
+ nop; nop; bra 3f; ...; 3:. */
+
+ offset = rel->r_offset;
+ BFD_ASSERT (offset >= 16);
+ /* Size of LD instructions is 16 or 18. */
+ offset -= 16;
+ insn = bfd_get_16 (input_bfd, contents + offset + 0);
+ if ((insn & 0xff00) == 0xc700)
+ {
+ BFD_ASSERT (offset >= 2);
+ offset -= 2;
+ insn = bfd_get_16 (input_bfd, contents + offset + 0);
+ }
+
+ BFD_ASSERT ((insn & 0xff00) == 0xd400);
+ insn = bfd_get_16 (input_bfd, contents + offset + 2);
+ BFD_ASSERT ((insn & 0xff00) == 0xc700);
+ insn = bfd_get_16 (input_bfd, contents + offset + 4);
+ BFD_ASSERT ((insn & 0xff00) == 0xd100);
+ insn = bfd_get_16 (input_bfd, contents + offset + 6);
+ BFD_ASSERT (insn == 0x310c);
+ insn = bfd_get_16 (input_bfd, contents + offset + 8);
+ BFD_ASSERT (insn == 0x410b);
+ insn = bfd_get_16 (input_bfd, contents + offset + 10);
+ BFD_ASSERT (insn == 0x34cc);
+
+ bfd_put_16 (output_bfd, 0x0012, contents + offset + 0);
+ bfd_put_16 (output_bfd, 0x0009, contents + offset + 2);
+ bfd_put_16 (output_bfd, 0x0009, contents + offset + 4);
+ bfd_put_16 (output_bfd, 0x0009, contents + offset + 6);
+ bfd_put_16 (output_bfd, 0x0009, contents + offset + 8);
+ bfd_put_16 (output_bfd, 0x0009, contents + offset + 10);
+
+ continue;
+ }
+
+ sgot = htab->sgot;
+ if (sgot == NULL)
+ abort ();
+
+ off = htab->tls_ldm_got.offset;
+ if (off & 1)
+ off &= ~1;
+ else
+ {
+ Elf_Internal_Rela outrel;
+ Elf32_External_Rela *loc;
+
+ srelgot = htab->srelgot;
+ if (srelgot == NULL)
+ abort ();
+
+ outrel.r_offset = (sgot->output_section->vma
+ + sgot->output_offset + off);
+ outrel.r_addend = 0;
+ outrel.r_info = ELF32_R_INFO (0, R_SH_TLS_DTPMOD32);
+ loc = (Elf32_External_Rela *) srelgot->contents;
+ loc += srelgot->reloc_count++;
+ bfd_elf32_swap_reloca_out (output_bfd, &outrel, loc);
+ htab->tls_ldm_got.offset |= 1;
+ }
+
+ relocation = sgot->output_offset + off;
+ addend = rel->r_addend;
+
+ goto final_link_relocate;
+
+ case R_SH_TLS_LDO_32:
+ if (! info->shared)
+ {
+ int indx;
+ Elf_Internal_Rela outrel;
+
+ if (sreloc == NULL)
+ {
+ const char *name;
+
+ name = (bfd_elf_string_from_elf_section
+ (input_bfd,
+ elf_elfheader (input_bfd)->e_shstrndx,
+ elf_section_data (input_section)->rel_hdr.sh_name));
+ if (name == NULL)
+ return false;
+
+ BFD_ASSERT (strncmp (name, ".rela", 5) == 0
+ && strcmp (bfd_get_section_name (input_bfd,
+ input_section),
+ name + 5) == 0);
+
+ sreloc = bfd_get_section_by_name (dynobj, name);
+ BFD_ASSERT (sreloc != NULL);
+ }
+
+ indx = (h && h->dynindx != -1) ? h->dynindx : 0;
+ outrel.r_offset = (input_section->output_section->vma
+ + input_section->output_offset
+ + rel->r_offset);
+ outrel.r_info = ELF32_R_INFO (indx, R_SH_TLS_TPOFF32);
+ if (indx == 0)
+ outrel.r_addend = relocation - dtpoff_base (info);
+ else
+ outrel.r_addend = 0;
+ bfd_elf32_swap_reloca_out (output_bfd, &outrel,
+ (((Elf32_External_Rela *)
+ sreloc->contents)
+ + sreloc->reloc_count));
+ ++sreloc->reloc_count;
+
+ continue;
+ }
+ else
+ relocation -= dtpoff_base (info);
+
+ addend = rel->r_addend;
+ goto final_link_relocate;
+
+ case R_SH_TLS_LE_32:
+ {
+ int indx;
+ Elf_Internal_Rela outrel;
+
+ if (sreloc == NULL)
+ {
+ const char *name;
+
+ name = (bfd_elf_string_from_elf_section
+ (input_bfd,
+ elf_elfheader (input_bfd)->e_shstrndx,
+ elf_section_data (input_section)->rel_hdr.sh_name));
+ if (name == NULL)
+ return false;
+
+ BFD_ASSERT (strncmp (name, ".rela", 5) == 0
+ && strcmp (bfd_get_section_name (input_bfd,
+ input_section),
+ name + 5) == 0);
+
+ sreloc = bfd_get_section_by_name (dynobj, name);
+ BFD_ASSERT (sreloc != NULL);
+ }
+
+ indx = (h && h->dynindx != -1) ? h->dynindx : 0;
+ outrel.r_offset = (input_section->output_section->vma
+ + input_section->output_offset
+ + rel->r_offset);
+ outrel.r_info = ELF32_R_INFO (indx, R_SH_TLS_TPOFF32);
+ if (indx == 0)
+ outrel.r_addend = relocation - dtpoff_base (info);
+ else
+ outrel.r_addend = 0;
+ bfd_elf32_swap_reloca_out (output_bfd, &outrel,
+ (((Elf32_External_Rela *)
+ sreloc->contents)
+ + sreloc->reloc_count));
+ ++sreloc->reloc_count;
+
+ continue;
+ }
}
relocation_done:
@@ -5160,6 +5812,20 @@ sh_elf_get_relocated_section_contents (output_bfd, link_info, link_order,
return NULL;
}
+/* Return the base VMA address which should be subtracted from real addresses
+ when resolving @dtpoff relocation.
+ This is PT_TLS segment p_vaddr. */
+
+static bfd_vma
+dtpoff_base (info)
+ struct bfd_link_info *info;
+{
+ /* If tls_segment is NULL, we should have signalled an error already. */
+ if (elf_hash_table (info)->tls_segment == NULL)
+ return 0;
+ return elf_hash_table (info)->tls_segment->start;
+}
+
static asection *
sh_elf_gc_mark_hook (sec, info, rel, h, sym)
asection *sec;
@@ -5227,8 +5893,15 @@ sh_elf_gc_sweep_hook (abfd, info, sec, relocs)
relend = relocs + sec->reloc_count;
for (rel = relocs; rel < relend; rel++)
- switch (ELF32_R_TYPE (rel->r_info))
+ switch (sh_elf_optimized_tls_reloc (info, ELF32_R_TYPE (rel->r_info),
+ ELF32_R_SYM (rel->r_info)
+ >= symtab_hdr->sh_info))
{
+ case R_SH_TLS_LD_32:
+ if (sh_elf_hash_table (info)->tls_ldm_got.refcount > 0)
+ sh_elf_hash_table (info)->tls_ldm_got.refcount -= 1;
+ break;
+
case R_SH_GOT32:
case R_SH_GOTOFF:
case R_SH_GOTPC:
@@ -5248,6 +5921,8 @@ sh_elf_gc_sweep_hook (abfd, info, sec, relocs)
case R_SH_GOTPC_MEDHI16:
case R_SH_GOTPC_HI16:
#endif
+ case R_SH_TLS_GD_32:
+ case R_SH_TLS_IE_32:
r_symndx = ELF32_R_SYM (rel->r_info);
if (r_symndx >= symtab_hdr->sh_info)
{
@@ -5391,9 +6066,39 @@ sh_elf_copy_indirect_symbol (bed, dir, ind)
edir->gotplt_refcount = eind->gotplt_refcount;
eind->gotplt_refcount = 0;
+ if (ind->root.type == bfd_link_hash_indirect
+ && dir->got.refcount <= 0)
+ {
+ edir->tls_type = eind->tls_type;
+ eind->tls_type = GOT_UNKNOWN;
+ }
+
_bfd_elf_link_hash_copy_indirect (bed, dir, ind);
}
+static int
+sh_elf_optimized_tls_reloc (info, r_type, is_local)
+ struct bfd_link_info *info;
+ int r_type;
+ int is_local;
+{
+ if (info->shared)
+ return r_type;
+
+ switch (r_type)
+ {
+ case R_SH_TLS_GD_32:
+ case R_SH_TLS_IE_32:
+ if (is_local)
+ return R_SH_TLS_LE_32;
+ return R_SH_TLS_IE_32;
+ case R_SH_TLS_LD_32:
+ return R_SH_TLS_LE_32;
+ }
+
+ 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. */
@@ -5415,6 +6120,8 @@ sh_elf_check_relocs (abfd, info, sec, relocs)
asection *sgot;
asection *srelgot;
asection *sreloc;
+ unsigned int r_type;
+ int tls_type, old_tls_type;
sgot = NULL;
srelgot = NULL;
@@ -5440,15 +6147,27 @@ sh_elf_check_relocs (abfd, info, sec, relocs)
unsigned long r_symndx;
r_symndx = ELF32_R_SYM (rel->r_info);
+ r_type = ELF32_R_TYPE (rel->r_info);
+
if (r_symndx < symtab_hdr->sh_info)
h = NULL;
else
h = sym_hashes[r_symndx - symtab_hdr->sh_info];
+ r_type = sh_elf_optimized_tls_reloc (info, r_type, h == NULL);
+ if (! info->shared
+ && r_type == R_SH_TLS_IE_32
+ && h != NULL
+ && h->root.type != bfd_link_hash_undefined
+ && h->root.type != bfd_link_hash_undefweak
+ && (h->dynindx == -1
+ || (h->elf_link_hash_flags & ELF_LINK_HASH_DEF_REGULAR)))
+ r_type = R_SH_TLS_LE_32;
+
/* Some relocs require a global offset table. */
if (htab->sgot == NULL)
{
- switch (ELF32_R_TYPE (rel->r_info))
+ switch (r_type)
{
case R_SH_GOTPLT32:
case R_SH_GOT32:
@@ -5476,6 +6195,9 @@ sh_elf_check_relocs (abfd, info, sec, relocs)
case R_SH_GOTPC_MEDHI16:
case R_SH_GOTPC_HI16:
#endif
+ case R_SH_TLS_GD_32:
+ case R_SH_TLS_LD_32:
+ case R_SH_TLS_IE_32:
if (dynobj == NULL)
htab->root.dynobj = dynobj = abfd;
if (! create_got_section (dynobj, info))
@@ -5487,7 +6209,7 @@ sh_elf_check_relocs (abfd, info, sec, relocs)
}
}
- switch (ELF32_R_TYPE (rel->r_info))
+ switch (r_type)
{
/* This relocation describes the C++ object vtable hierarchy.
Reconstruct it for later use during GC. */
@@ -5504,6 +6226,12 @@ sh_elf_check_relocs (abfd, info, sec, relocs)
break;
force_got:
+ case R_SH_TLS_IE_32:
+ if (info->shared)
+ info->flags |= DF_STATIC_TLS;
+
+ /* FALLTHROUGH */
+ case R_SH_TLS_GD_32:
case R_SH_GOT32:
#ifdef INCLUDE_SHMEDIA
case R_SH_GOT_LOW16:
@@ -5513,8 +6241,24 @@ sh_elf_check_relocs (abfd, info, sec, relocs)
case R_SH_GOT10BY4:
case R_SH_GOT10BY8:
#endif
+ switch (r_type)
+ {
+ default:
+ tls_type = GOT_NORMAL;
+ break;
+ case R_SH_TLS_GD_32:
+ tls_type = GOT_TLS_GD;
+ break;
+ case R_SH_TLS_IE_32:
+ tls_type = GOT_TLS_IE;
+ break;
+ }
+
if (h != NULL)
- h->got.refcount += 1;
+ {
+ h->got.refcount += 1;
+ old_tls_type = sh_elf_hash_entry (h)->tls_type;
+ }
else
{
bfd_signed_vma *local_got_refcounts;
@@ -5533,14 +6277,54 @@ sh_elf_check_relocs (abfd, info, sec, relocs)
codelabel local GOT offsets. */
size *= 2;
#endif
+ size += symtab_hdr->sh_info;
local_got_refcounts = ((bfd_signed_vma *)
bfd_zalloc (abfd, size));
if (local_got_refcounts == NULL)
return false;
elf_local_got_refcounts (abfd) = local_got_refcounts;
+#ifdef INCLUDE_SHMEDIA
+ /* Take care of both the datalabel and codelabel local
+ GOT offsets. */
+ sh_elf_local_got_tls_type (abfd)
+ = (char *) (local_got_refcounts + 2 * symtab_hdr->sh_info);
+#else
+ sh_elf_local_got_tls_type (abfd)
+ = (char *) (local_got_refcounts + symtab_hdr->sh_info);
+#endif
}
local_got_refcounts[r_symndx] += 1;
+ old_tls_type = sh_elf_local_got_tls_type (abfd) [r_symndx];
+ }
+
+ /* If a TLS symbol is accessed using IE at least once,
+ there is no point to use dynamic model for it. */
+ if (old_tls_type != tls_type && old_tls_type != GOT_UNKNOWN
+ && (old_tls_type != GOT_TLS_GD || tls_type != GOT_TLS_IE))
+ {
+ if (old_tls_type == GOT_TLS_IE && tls_type == GOT_TLS_GD)
+ tls_type = GOT_TLS_IE;
+ else
+ {
+ (*_bfd_error_handler)
+ (_("%s: `%s' accessed both as normal and thread local symbol"),
+ bfd_archive_filename (abfd), h->root.root.string);
+ return false;
+ }
+ }
+
+ if (old_tls_type != tls_type)
+ {
+ if (h != NULL)
+ sh_elf_hash_entry (h)->tls_type = tls_type;
+ else
+ sh_elf_local_got_tls_type (abfd) [r_symndx] = tls_type;
}
+
+ break;
+
+ case R_SH_TLS_LD_32:
+ sh_elf_hash_table(info)->tls_ldm_got.refcount += 1;
break;
case R_SH_GOTPLT32:
@@ -5623,7 +6407,7 @@ sh_elf_check_relocs (abfd, info, sec, relocs)
symbol. */
if ((info->shared
&& (sec->flags & SEC_ALLOC) != 0
- && (ELF32_R_TYPE (rel->r_info) != R_SH_REL32
+ && (r_type != R_SH_REL32
|| (h != NULL
&& (! info->symbolic
|| h->root.type == bfd_link_hash_defweak
@@ -5713,11 +6497,110 @@ sh_elf_check_relocs (abfd, info, sec, relocs)
}
p->count += 1;
- if (ELF32_R_TYPE (rel->r_info) == R_SH_REL32)
+ if (r_type == R_SH_REL32)
p->pc_count += 1;
}
break;
+
+ case R_SH_TLS_LE_32:
+ if (info->shared)
+ {
+ (*_bfd_error_handler) (_("%s: TLS local exec code cannot be linked into shared objects"),
+ bfd_archive_filename (abfd));
+ return false;
+ }
+
+ if (ELF32_R_TYPE (rel->r_info) == R_SH_TLS_LD_32)
+ break;
+
+ /* FALLTHROUGH */
+ case R_SH_TLS_LDO_32:
+ /* We make a R_SH_TLS_TPOFF32 relocation. Count it as a
+ copy relocation. */
+ if (! info->shared)
+ {
+ struct elf_sh_dyn_relocs *p;
+ struct elf_sh_dyn_relocs **head;
+
+ if (dynobj == NULL)
+ htab->root.dynobj = dynobj = abfd;
+
+ if (sreloc == NULL)
+ {
+ const char *name;
+
+ name = (bfd_elf_string_from_elf_section
+ (abfd,
+ elf_elfheader (abfd)->e_shstrndx,
+ elf_section_data (sec)->rel_hdr.sh_name));
+ if (name == NULL)
+ return false;
+
+ BFD_ASSERT (strncmp (name, ".rela", 5) == 0
+ && strcmp (bfd_get_section_name (abfd, sec),
+ name + 5) == 0);
+
+ sreloc = bfd_get_section_by_name (dynobj, name);
+ if (sreloc == NULL)
+ {
+ flagword flags;
+
+ sreloc = bfd_make_section (dynobj, name);
+ flags = (SEC_HAS_CONTENTS | SEC_READONLY
+ | SEC_IN_MEMORY | SEC_LINKER_CREATED);
+ if ((sec->flags & SEC_ALLOC) != 0)
+ flags |= SEC_ALLOC | SEC_LOAD;
+ if (sreloc == NULL
+ || ! bfd_set_section_flags (dynobj, sreloc, flags)
+ || ! bfd_set_section_alignment (dynobj, sreloc, 2))
+ return false;
+ }
+ elf_section_data (sec)->sreloc = sreloc;
+ if (sec->flags & SEC_READONLY)
+ info->flags |= DF_TEXTREL;
+ }
+
+ /* If this is a global symbol, we count the number of
+ relocations we need for this symbol. */
+ if (h != NULL)
+ head = &((struct elf_sh_link_hash_entry *) h)->dyn_relocs;
+ else
+ {
+ asection *s;
+
+ /* Track dynamic relocs needed for local syms too. */
+ s = bfd_section_from_r_symndx (abfd, &htab->sym_sec,
+ sec, r_symndx);
+ if (s == NULL)
+ return false;
+
+ head = ((struct elf_sh_dyn_relocs **)
+ &elf_section_data (s)->local_dynrel);
+ }
+
+ p = *head;
+ if (p == NULL || p->sec != sec)
+ {
+ bfd_size_type amt = sizeof (*p);
+ p = ((struct elf_sh_dyn_relocs *) bfd_alloc (dynobj, amt));
+ if (p == NULL)
+ return false;
+ p->next = *head;
+ *head = p;
+ p->sec = sec;
+ p->count = 0;
+ p->pc_count = 0;
+ }
+
+ p->count += 1;
+ if (h)
+ sh_elf_hash_entry (h)->tls_tpoff32 = true;
+ }
+ break;
+
+ default:
+ break;
}
}
@@ -5838,6 +6721,29 @@ sh_elf_merge_private_data (ibfd, obfd)
}
#endif /* not sh_elf_merge_private_data */
+/* Override the generic function because we need to store sh_elf_obj_tdata
+ as the specific tdata. We set also the machine architecture from flags
+ here. */
+
+static boolean
+sh_elf_object_p (abfd)
+ bfd *abfd;
+{
+ struct sh_elf_obj_tdata *new_tdata;
+ bfd_size_type amt = sizeof (struct sh_elf_obj_tdata);
+
+ if (sh_elf_set_mach_from_flags (abfd) == false)
+ return false;
+
+ /* Allocate our special target data. */
+ new_tdata = bfd_zalloc (abfd, amt);
+ if (new_tdata == NULL)
+ return false;
+ new_tdata->root = *abfd->tdata.elf_obj_data;
+ abfd->tdata.any = new_tdata;
+ return true;
+}
+
/* Finish up dynamic symbol handling. We set the contents of various
dynamic sections here. */
@@ -5994,7 +6900,9 @@ sh_elf_finish_dynamic_symbol (output_bfd, info, h, sym)
}
}
- if (h->got.offset != (bfd_vma) -1)
+ if (h->got.offset != (bfd_vma) -1
+ && sh_elf_hash_entry (h)->tls_type != GOT_TLS_GD
+ && sh_elf_hash_entry (h)->tls_type != GOT_TLS_IE)
{
asection *sgot;
asection *srel;
@@ -6283,7 +7191,8 @@ sh_elf_reloc_type_class (rela)
#define elf_backend_relocate_section sh_elf_relocate_section
#define bfd_elf32_bfd_get_relocated_section_contents \
sh_elf_get_relocated_section_contents
-#define elf_backend_object_p sh_elf_set_mach_from_flags
+#define bfd_elf32_mkobject sh_elf_mkobject
+#define elf_backend_object_p sh_elf_object_p
#define bfd_elf32_bfd_set_private_bfd_flags \
sh_elf_set_private_flags
#define bfd_elf32_bfd_copy_private_bfd_data \
diff --git a/bfd/libbfd.h b/bfd/libbfd.h
index 96e55d7..ef001f3 100644
--- a/bfd/libbfd.h
+++ b/bfd/libbfd.h
@@ -1005,6 +1005,14 @@ static const char *const bfd_reloc_code_real_names[] = { "@@uninitialized@@",
"BFD_RELOC_SH_IMM_HI16",
"BFD_RELOC_SH_IMM_HI16_PCREL",
"BFD_RELOC_SH_PT_16",
+ "BFD_RELOC_SH_TLS_GD_32",
+ "BFD_RELOC_SH_TLS_LD_32",
+ "BFD_RELOC_SH_TLS_LDO_32",
+ "BFD_RELOC_SH_TLS_IE_32",
+ "BFD_RELOC_SH_TLS_LE_32",
+ "BFD_RELOC_SH_TLS_DTPMOD32",
+ "BFD_RELOC_SH_TLS_DTPOFF32",
+ "BFD_RELOC_SH_TLS_TPOFF32",
"BFD_RELOC_THUMB_PCREL_BRANCH9",
"BFD_RELOC_THUMB_PCREL_BRANCH12",
"BFD_RELOC_THUMB_PCREL_BRANCH23",
diff --git a/bfd/reloc.c b/bfd/reloc.c
index 71f1740..23e4934 100644
--- a/bfd/reloc.c
+++ b/bfd/reloc.c
@@ -2575,6 +2575,22 @@ ENUMX
BFD_RELOC_SH_IMM_HI16_PCREL
ENUMX
BFD_RELOC_SH_PT_16
+ENUMX
+ BFD_RELOC_SH_TLS_GD_32
+ENUMX
+ BFD_RELOC_SH_TLS_LD_32
+ENUMX
+ BFD_RELOC_SH_TLS_LDO_32
+ENUMX
+ BFD_RELOC_SH_TLS_IE_32
+ENUMX
+ BFD_RELOC_SH_TLS_LE_32
+ENUMX
+ BFD_RELOC_SH_TLS_DTPMOD32
+ENUMX
+ BFD_RELOC_SH_TLS_DTPOFF32
+ENUMX
+ BFD_RELOC_SH_TLS_TPOFF32
ENUMDOC
Hitachi SH relocs. Not all of these appear in object files.