Index: bfd/elf32-tilepro.c |
diff --git a/bfd/elf32-tilepro.c b/bfd/elf32-tilepro.c |
index 7b08aff04ed59ad5118bd00e90adb928cc978cad..fa883e19d69a2acb55de4b763d84081d69646aa6 100644 |
--- a/bfd/elf32-tilepro.c |
+++ b/bfd/elf32-tilepro.c |
@@ -1,5 +1,5 @@ |
/* TILEPro-specific support for 32-bit ELF. |
- Copyright 2011 Free Software Foundation, Inc. |
+ Copyright 2011, 2012 Free Software Foundation, Inc. |
This file is part of BFD, the Binary File Descriptor library. |
@@ -18,8 +18,8 @@ |
Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, |
MA 02110-1301, USA. */ |
-#include "bfd.h" |
#include "sysdep.h" |
+#include "bfd.h" |
#include "libbfd.h" |
#include "elf-bfd.h" |
#include "elf/tilepro.h" |
@@ -380,12 +380,26 @@ static reloc_howto_type tilepro_elf_howto_table [] = |
EMPTY_HOWTO (57), |
EMPTY_HOWTO (58), |
EMPTY_HOWTO (59), |
- EMPTY_HOWTO (60), |
- EMPTY_HOWTO (61), |
- EMPTY_HOWTO (62), |
- EMPTY_HOWTO (63), |
- EMPTY_HOWTO (64), |
- EMPTY_HOWTO (65), |
+ |
+ HOWTO (R_TILEPRO_TLS_GD_CALL, /* type */ |
+ TILEPRO_LOG2_BUNDLE_ALIGNMENT_IN_BYTES, /* rightshift */ |
+ 2, /* size (0 = byte, 1 = short, 2 = long) */ |
+ 29, /* bitsize */ |
+ TRUE, /* pc_relative */ |
+ 0, /* bitpos */ |
+ complain_overflow_signed,/* complain_on_overflow */ |
+ bfd_elf_generic_reloc, /* special_function */ |
+ "R_TILEPRO_TLS_GD_CALL", /* name */ |
+ FALSE, /* partial_inplace */ |
+ 0, /* src_mask */ |
+ -1, /* dst_mask */ |
+ TRUE), /* pcrel_offset */ |
+ |
+ TILEPRO_IMM_HOWTO(R_TILEPRO_IMM8_X0_TLS_GD_ADD, 0, 8), |
+ TILEPRO_IMM_HOWTO(R_TILEPRO_IMM8_X1_TLS_GD_ADD, 0, 8), |
+ TILEPRO_IMM_HOWTO(R_TILEPRO_IMM8_Y0_TLS_GD_ADD, 0, 8), |
+ TILEPRO_IMM_HOWTO(R_TILEPRO_IMM8_Y1_TLS_GD_ADD, 0, 8), |
+ TILEPRO_IMM_HOWTO(R_TILEPRO_TLS_IE_LOAD, 0, 8), |
/* Offsets into the GOT of TLS Descriptors. */ |
@@ -454,17 +468,12 @@ static reloc_howto_type tilepro_elf_howto_table [] = |
-1, /* dst_mask */ |
TRUE), /* pcrel_offset */ |
-#define TILEPRO_IMM16_HOWTO_TLS_IE(name, rshift) \ |
- HOWTO (name, rshift, 1, 16, FALSE, 0, \ |
- complain_overflow_dont, bfd_elf_generic_reloc, \ |
- #name, FALSE, 0, 0xffff, TRUE) |
- |
- TILEPRO_IMM16_HOWTO_TLS_IE (R_TILEPRO_IMM16_X0_TLS_IE_LO, 0), |
- TILEPRO_IMM16_HOWTO_TLS_IE (R_TILEPRO_IMM16_X1_TLS_IE_LO, 0), |
- TILEPRO_IMM16_HOWTO_TLS_IE (R_TILEPRO_IMM16_X0_TLS_IE_HI, 16), |
- TILEPRO_IMM16_HOWTO_TLS_IE (R_TILEPRO_IMM16_X1_TLS_IE_HI, 16), |
- TILEPRO_IMM16_HOWTO_TLS_IE (R_TILEPRO_IMM16_X0_TLS_IE_HA, 16), |
- TILEPRO_IMM16_HOWTO_TLS_IE (R_TILEPRO_IMM16_X1_TLS_IE_HA, 16), |
+ TILEPRO_IMM16_HOWTO (R_TILEPRO_IMM16_X0_TLS_IE_LO, 0), |
+ TILEPRO_IMM16_HOWTO (R_TILEPRO_IMM16_X1_TLS_IE_LO, 0), |
+ TILEPRO_IMM16_HOWTO (R_TILEPRO_IMM16_X0_TLS_IE_HI, 16), |
+ TILEPRO_IMM16_HOWTO (R_TILEPRO_IMM16_X1_TLS_IE_HI, 16), |
+ TILEPRO_IMM16_HOWTO (R_TILEPRO_IMM16_X0_TLS_IE_HA, 16), |
+ TILEPRO_IMM16_HOWTO (R_TILEPRO_IMM16_X1_TLS_IE_HA, 16), |
/* These are common with the Solaris TLS implementation. */ |
HOWTO(R_TILEPRO_TLS_DTPMOD32, 0, 0, 0, FALSE, 0, complain_overflow_dont, |
@@ -475,8 +484,42 @@ static reloc_howto_type tilepro_elf_howto_table [] = |
FALSE, 0, 0xFFFFFFFF, TRUE), |
HOWTO(R_TILEPRO_TLS_TPOFF32, 0, 0, 0, FALSE, 0, complain_overflow_dont, |
bfd_elf_generic_reloc, "R_TILEPRO_TLS_TPOFF32", |
- FALSE, 0, 0, TRUE) |
+ FALSE, 0, 0, TRUE), |
+ HOWTO (R_TILEPRO_IMM16_X0_TLS_LE,/* type */ |
+ 0, /* rightshift */ |
+ 1, /* size (0 = byte, 1 = short, 2 = long) */ |
+ 16, /* bitsize */ |
+ FALSE, /* pc_relative */ |
+ 0, /* bitpos */ |
+ complain_overflow_signed, /* complain_on_overflow */ |
+ bfd_elf_generic_reloc, /* special_function */ |
+ "R_TILEPRO_IMM16_X0_TLS_LE",/* name */ |
+ FALSE, /* partial_inplace */ |
+ 0, /* src_mask */ |
+ -1, /* dst_mask */ |
+ TRUE), /* pcrel_offset */ |
+ |
+ HOWTO (R_TILEPRO_IMM16_X1_TLS_LE,/* type */ |
+ 0, /* rightshift */ |
+ 1, /* size (0 = byte, 1 = short, 2 = long) */ |
+ 16, /* bitsize */ |
+ FALSE, /* pc_relative */ |
+ 0, /* bitpos */ |
+ complain_overflow_signed, /* complain_on_overflow */ |
+ bfd_elf_generic_reloc, /* special_function */ |
+ "R_TILEPRO_IMM16_X1_TLS_LE",/* name */ |
+ FALSE, /* partial_inplace */ |
+ 0, /* src_mask */ |
+ -1, /* dst_mask */ |
+ TRUE), /* pcrel_offset */ |
+ |
+ TILEPRO_IMM16_HOWTO (R_TILEPRO_IMM16_X0_TLS_LE_LO, 0), |
+ TILEPRO_IMM16_HOWTO (R_TILEPRO_IMM16_X1_TLS_LE_LO, 0), |
+ TILEPRO_IMM16_HOWTO (R_TILEPRO_IMM16_X0_TLS_LE_HI, 16), |
+ TILEPRO_IMM16_HOWTO (R_TILEPRO_IMM16_X1_TLS_LE_HI, 16), |
+ TILEPRO_IMM16_HOWTO (R_TILEPRO_IMM16_X0_TLS_LE_HA, 16), |
+ TILEPRO_IMM16_HOWTO (R_TILEPRO_IMM16_X1_TLS_LE_HA, 16), |
}; |
static reloc_howto_type tilepro_elf_howto_table2 [] = |
@@ -590,6 +633,13 @@ static const reloc_map tilepro_reloc_map [] = |
TH_REMAP (BFD_RELOC_TILEPRO_SHAMT_Y0, R_TILEPRO_SHAMT_Y0) |
TH_REMAP (BFD_RELOC_TILEPRO_SHAMT_Y1, R_TILEPRO_SHAMT_Y1) |
+ TH_REMAP (BFD_RELOC_TILEPRO_TLS_GD_CALL, R_TILEPRO_TLS_GD_CALL) |
+ TH_REMAP (BFD_RELOC_TILEPRO_IMM8_X0_TLS_GD_ADD, R_TILEPRO_IMM8_X0_TLS_GD_ADD) |
+ TH_REMAP (BFD_RELOC_TILEPRO_IMM8_X1_TLS_GD_ADD, R_TILEPRO_IMM8_X1_TLS_GD_ADD) |
+ TH_REMAP (BFD_RELOC_TILEPRO_IMM8_Y0_TLS_GD_ADD, R_TILEPRO_IMM8_Y0_TLS_GD_ADD) |
+ TH_REMAP (BFD_RELOC_TILEPRO_IMM8_Y1_TLS_GD_ADD, R_TILEPRO_IMM8_Y1_TLS_GD_ADD) |
+ TH_REMAP (BFD_RELOC_TILEPRO_TLS_IE_LOAD, R_TILEPRO_TLS_IE_LOAD) |
+ |
TH_REMAP (BFD_RELOC_TILEPRO_IMM16_X0_TLS_GD, R_TILEPRO_IMM16_X0_TLS_GD) |
TH_REMAP (BFD_RELOC_TILEPRO_IMM16_X1_TLS_GD, R_TILEPRO_IMM16_X1_TLS_GD) |
TH_REMAP (BFD_RELOC_TILEPRO_IMM16_X0_TLS_GD_LO, R_TILEPRO_IMM16_X0_TLS_GD_LO) |
@@ -612,6 +662,15 @@ static const reloc_map tilepro_reloc_map [] = |
TH_REMAP (BFD_RELOC_TILEPRO_TLS_DTPOFF32, R_TILEPRO_TLS_DTPOFF32) |
TH_REMAP (BFD_RELOC_TILEPRO_TLS_TPOFF32, R_TILEPRO_TLS_TPOFF32) |
+ TH_REMAP (BFD_RELOC_TILEPRO_IMM16_X0_TLS_LE, R_TILEPRO_IMM16_X0_TLS_LE) |
+ TH_REMAP (BFD_RELOC_TILEPRO_IMM16_X1_TLS_LE, R_TILEPRO_IMM16_X1_TLS_LE) |
+ TH_REMAP (BFD_RELOC_TILEPRO_IMM16_X0_TLS_LE_LO, R_TILEPRO_IMM16_X0_TLS_LE_LO) |
+ TH_REMAP (BFD_RELOC_TILEPRO_IMM16_X1_TLS_LE_LO, R_TILEPRO_IMM16_X1_TLS_LE_LO) |
+ TH_REMAP (BFD_RELOC_TILEPRO_IMM16_X0_TLS_LE_HI, R_TILEPRO_IMM16_X0_TLS_LE_HI) |
+ TH_REMAP (BFD_RELOC_TILEPRO_IMM16_X1_TLS_LE_HI, R_TILEPRO_IMM16_X1_TLS_LE_HI) |
+ TH_REMAP (BFD_RELOC_TILEPRO_IMM16_X0_TLS_LE_HA, R_TILEPRO_IMM16_X0_TLS_LE_HA) |
+ TH_REMAP (BFD_RELOC_TILEPRO_IMM16_X1_TLS_LE_HA, R_TILEPRO_IMM16_X1_TLS_LE_HA) |
+ |
#undef TH_REMAP |
{ BFD_RELOC_VTABLE_INHERIT, R_TILEPRO_GNU_VTINHERIT, tilepro_elf_howto_table2 }, |
@@ -745,7 +804,7 @@ tilepro_info_to_howto_rela (bfd * abfd ATTRIBUTE_UNUSED, |
{ |
unsigned int r_type = ELF32_R_TYPE (dst->r_info); |
- if (r_type <= (unsigned int) R_TILEPRO_TLS_TPOFF32) |
+ if (r_type <= (unsigned int) R_TILEPRO_IMM16_X1_TLS_LE_HA) |
cache_ptr->howto = &tilepro_elf_howto_table [r_type]; |
else if (r_type - R_TILEPRO_GNU_VTINHERIT |
<= (unsigned int) R_TILEPRO_GNU_VTENTRY) |
@@ -845,7 +904,20 @@ static const tilepro_create_func reloc_to_create_func[] = |
create_Imm16_X0, |
create_Imm16_X1, |
create_Imm16_X0, |
- create_Imm16_X1 |
+ create_Imm16_X1, |
+ |
+ NULL, |
+ NULL, |
+ NULL, |
+ |
+ create_Imm16_X0, |
+ create_Imm16_X1, |
+ create_Imm16_X0, |
+ create_Imm16_X1, |
+ create_Imm16_X0, |
+ create_Imm16_X1, |
+ create_Imm16_X0, |
+ create_Imm16_X1, |
}; |
#define NELEMS(a) ((int) (sizeof (a) / sizeof ((a)[0]))) |
@@ -1152,8 +1224,8 @@ tilepro_elf_create_got_section (bfd *abfd, struct bfd_link_info *info) |
struct elf_link_hash_table *htab = elf_hash_table (info); |
/* This function may be called more than once. */ |
- s = bfd_get_section_by_name (abfd, ".got"); |
- if (s != NULL && (s->flags & SEC_LINKER_CREATED) != 0) |
+ s = bfd_get_linker_section (abfd, ".got"); |
+ if (s != NULL) |
return TRUE; |
flags = bed->dynamic_sec_flags; |
@@ -1225,9 +1297,9 @@ tilepro_elf_create_dynamic_sections (bfd *dynobj, |
if (!_bfd_elf_create_dynamic_sections (dynobj, info)) |
return FALSE; |
- htab->sdynbss = bfd_get_section_by_name (dynobj, ".dynbss"); |
+ htab->sdynbss = bfd_get_linker_section (dynobj, ".dynbss"); |
if (!info->shared) |
- htab->srelbss = bfd_get_section_by_name (dynobj, ".rela.bss"); |
+ htab->srelbss = bfd_get_linker_section (dynobj, ".rela.bss"); |
if (!htab->elf.splt || !htab->elf.srelplt || !htab->sdynbss |
|| (!info->shared && !htab->srelbss)) |
@@ -1288,6 +1360,99 @@ tilepro_elf_copy_indirect_symbol (struct bfd_link_info *info, |
_bfd_elf_link_hash_copy_indirect (info, dir, ind); |
} |
+static int |
+tilepro_tls_translate_to_le (int r_type) |
+{ |
+ switch (r_type) |
+ { |
+ case R_TILEPRO_IMM16_X0_TLS_GD: |
+ case R_TILEPRO_IMM16_X0_TLS_IE: |
+ return R_TILEPRO_IMM16_X0_TLS_LE; |
+ |
+ case R_TILEPRO_IMM16_X1_TLS_GD: |
+ case R_TILEPRO_IMM16_X1_TLS_IE: |
+ return R_TILEPRO_IMM16_X1_TLS_LE; |
+ |
+ case R_TILEPRO_IMM16_X0_TLS_GD_LO: |
+ case R_TILEPRO_IMM16_X0_TLS_IE_LO: |
+ return R_TILEPRO_IMM16_X0_TLS_LE_LO; |
+ |
+ case R_TILEPRO_IMM16_X1_TLS_GD_LO: |
+ case R_TILEPRO_IMM16_X1_TLS_IE_LO: |
+ return R_TILEPRO_IMM16_X1_TLS_LE_LO; |
+ |
+ case R_TILEPRO_IMM16_X0_TLS_GD_HI: |
+ case R_TILEPRO_IMM16_X0_TLS_IE_HI: |
+ return R_TILEPRO_IMM16_X0_TLS_LE_HI; |
+ |
+ case R_TILEPRO_IMM16_X1_TLS_GD_HI: |
+ case R_TILEPRO_IMM16_X1_TLS_IE_HI: |
+ return R_TILEPRO_IMM16_X1_TLS_LE_HI; |
+ |
+ case R_TILEPRO_IMM16_X0_TLS_GD_HA: |
+ case R_TILEPRO_IMM16_X0_TLS_IE_HA: |
+ return R_TILEPRO_IMM16_X0_TLS_LE_HA; |
+ |
+ case R_TILEPRO_IMM16_X1_TLS_GD_HA: |
+ case R_TILEPRO_IMM16_X1_TLS_IE_HA: |
+ return R_TILEPRO_IMM16_X1_TLS_LE_HA; |
+ } |
+ return r_type; |
+} |
+ |
+static int |
+tilepro_tls_translate_to_ie (int r_type) |
+{ |
+ switch (r_type) |
+ { |
+ case R_TILEPRO_IMM16_X0_TLS_GD: |
+ case R_TILEPRO_IMM16_X0_TLS_IE: |
+ return R_TILEPRO_IMM16_X0_TLS_IE; |
+ |
+ case R_TILEPRO_IMM16_X1_TLS_GD: |
+ case R_TILEPRO_IMM16_X1_TLS_IE: |
+ return R_TILEPRO_IMM16_X1_TLS_IE; |
+ |
+ case R_TILEPRO_IMM16_X0_TLS_GD_LO: |
+ case R_TILEPRO_IMM16_X0_TLS_IE_LO: |
+ return R_TILEPRO_IMM16_X0_TLS_IE_LO; |
+ |
+ case R_TILEPRO_IMM16_X1_TLS_GD_LO: |
+ case R_TILEPRO_IMM16_X1_TLS_IE_LO: |
+ return R_TILEPRO_IMM16_X1_TLS_IE_LO; |
+ |
+ case R_TILEPRO_IMM16_X0_TLS_GD_HI: |
+ case R_TILEPRO_IMM16_X0_TLS_IE_HI: |
+ return R_TILEPRO_IMM16_X0_TLS_IE_HI; |
+ |
+ case R_TILEPRO_IMM16_X1_TLS_GD_HI: |
+ case R_TILEPRO_IMM16_X1_TLS_IE_HI: |
+ return R_TILEPRO_IMM16_X1_TLS_IE_HI; |
+ |
+ case R_TILEPRO_IMM16_X0_TLS_GD_HA: |
+ case R_TILEPRO_IMM16_X0_TLS_IE_HA: |
+ return R_TILEPRO_IMM16_X0_TLS_IE_HA; |
+ |
+ case R_TILEPRO_IMM16_X1_TLS_GD_HA: |
+ case R_TILEPRO_IMM16_X1_TLS_IE_HA: |
+ return R_TILEPRO_IMM16_X1_TLS_IE_HA; |
+ } |
+ return r_type; |
+} |
+ |
+static int |
+tilepro_elf_tls_transition (struct bfd_link_info *info, int r_type, |
+ int is_local) |
+{ |
+ if (info->shared) |
+ return r_type; |
+ |
+ if (is_local) |
+ return tilepro_tls_translate_to_le (r_type); |
+ else |
+ return tilepro_tls_translate_to_ie (r_type); |
+} |
+ |
/* Look through the relocs for a section during the first phase, and |
allocate space in the global offset table or procedure linkage |
table. */ |
@@ -1348,8 +1513,21 @@ tilepro_elf_check_relocs (bfd *abfd, struct bfd_link_info *info, |
h = (struct elf_link_hash_entry *) h->root.u.i.link; |
} |
+ r_type = tilepro_elf_tls_transition (info, r_type, h == NULL); |
switch (r_type) |
{ |
+ case R_TILEPRO_IMM16_X0_TLS_LE: |
+ case R_TILEPRO_IMM16_X1_TLS_LE: |
+ case R_TILEPRO_IMM16_X0_TLS_LE_LO: |
+ case R_TILEPRO_IMM16_X1_TLS_LE_LO: |
+ case R_TILEPRO_IMM16_X0_TLS_LE_HI: |
+ case R_TILEPRO_IMM16_X1_TLS_LE_HI: |
+ case R_TILEPRO_IMM16_X0_TLS_LE_HA: |
+ case R_TILEPRO_IMM16_X1_TLS_LE_HA: |
+ if (info->shared) |
+ goto r_tilepro_plt32; |
+ break; |
+ |
case R_TILEPRO_IMM16_X0_TLS_GD: |
case R_TILEPRO_IMM16_X1_TLS_GD: |
case R_TILEPRO_IMM16_X0_TLS_GD_LO: |
@@ -1358,7 +1536,8 @@ tilepro_elf_check_relocs (bfd *abfd, struct bfd_link_info *info, |
case R_TILEPRO_IMM16_X1_TLS_GD_HI: |
case R_TILEPRO_IMM16_X0_TLS_GD_HA: |
case R_TILEPRO_IMM16_X1_TLS_GD_HA: |
- tls_type = GOT_TLS_GD; |
+ BFD_ASSERT (info->shared); |
+ tls_type = GOT_TLS_GD; |
goto have_got_reference; |
case R_TILEPRO_IMM16_X0_TLS_IE: |
@@ -1454,6 +1633,24 @@ tilepro_elf_check_relocs (bfd *abfd, struct bfd_link_info *info, |
} |
break; |
+ case R_TILEPRO_TLS_GD_CALL: |
+ if (info->shared) |
+ { |
+ /* These are basically R_TILEPRO_JOFFLONG_X1_PLT relocs |
+ against __tls_get_addr. */ |
+ struct bfd_link_hash_entry *bh = NULL; |
+ if (! _bfd_generic_link_add_one_symbol (info, abfd, |
+ "__tls_get_addr", 0, |
+ bfd_und_section_ptr, 0, |
+ NULL, FALSE, FALSE, |
+ &bh)) |
+ return FALSE; |
+ h = (struct elf_link_hash_entry *) bh; |
+ } |
+ else |
+ break; |
+ /* Fall through */ |
+ |
case R_TILEPRO_JOFFLONG_X1_PLT: |
/* This symbol requires a procedure linkage table entry. We |
actually build the entry in adjust_dynamic_symbol, |
@@ -1523,15 +1720,14 @@ tilepro_elf_check_relocs (bfd *abfd, struct bfd_link_info *info, |
case R_TILEPRO_SHAMT_Y0: |
case R_TILEPRO_SHAMT_Y1: |
if (h != NULL) |
- { |
h->non_got_ref = 1; |
- if (!info->shared) |
- { |
- /* We may need a .plt entry if the function this reloc |
- refers to is in a shared lib. */ |
- h->plt.refcount += 1; |
- } |
+ r_tilepro_plt32: |
+ if (h != NULL && !info->shared) |
+ { |
+ /* We may need a .plt entry if the function this reloc |
+ refers to is in a shared lib. */ |
+ h->plt.refcount += 1; |
} |
/* If we are creating a shared library, and this is a reloc |
@@ -1725,6 +1921,7 @@ tilepro_elf_gc_sweep_hook (bfd *abfd, struct bfd_link_info *info, |
} |
r_type = ELF32_R_TYPE (rel->r_info); |
+ r_type = tilepro_elf_tls_transition (info, r_type, h != NULL); |
switch (r_type) |
{ |
case R_TILEPRO_IMM16_X0_GOT: |
@@ -1758,7 +1955,8 @@ tilepro_elf_gc_sweep_hook (bfd *abfd, struct bfd_link_info *info, |
} |
else |
{ |
- if (local_got_refcounts[r_symndx] > 0) |
+ if (local_got_refcounts && |
+ local_got_refcounts[r_symndx] > 0) |
local_got_refcounts[r_symndx]--; |
} |
break; |
@@ -1935,13 +2133,6 @@ tilepro_elf_adjust_dynamic_symbol (struct bfd_link_info *info, |
return TRUE; |
} |
- if (h->size == 0) |
- { |
- (*_bfd_error_handler) (_("dynamic variable `%s' is zero size"), |
- h->root.root.string); |
- return TRUE; |
- } |
- |
/* We must allocate the symbol in our .dynbss section, which will |
become part of the .bss section of the executable. There will be |
an entry for this symbol in the .dynsym section. The dynamic |
@@ -1956,7 +2147,7 @@ tilepro_elf_adjust_dynamic_symbol (struct bfd_link_info *info, |
to copy the initial value out of the dynamic object and into the |
runtime process image. We need to remember the offset into the |
.rel.bss section we are going to use. */ |
- if ((h->root.u.def.section->flags & SEC_ALLOC) != 0) |
+ if ((h->root.u.def.section->flags & SEC_ALLOC) != 0 && h->size != 0) |
{ |
htab->srelbss->size += TILEPRO_ELF_RELA_BYTES; |
h->needs_copy = 1; |
@@ -2040,7 +2231,14 @@ allocate_dynrelocs (struct elf_link_hash_entry *h, void *inf) |
h->needs_plt = 0; |
} |
- if (h->got.refcount > 0) |
+ /* If a TLS_IE symbol is now local to the binary, make it a TLS_LE |
+ requiring no TLS entry. */ |
+ if (h->got.refcount > 0 |
+ && !info->shared |
+ && h->dynindx == -1 |
+ && tilepro_elf_hash_entry(h)->tls_type == GOT_TLS_IE) |
+ h->got.offset = (bfd_vma) -1; |
+ else if (h->got.refcount > 0) |
{ |
asection *s; |
bfd_boolean dyn; |
@@ -2229,7 +2427,7 @@ tilepro_elf_size_dynamic_sections (bfd *output_bfd, |
/* Set the contents of the .interp section to the interpreter. */ |
if (info->executable) |
{ |
- s = bfd_get_section_by_name (dynobj, ".interp"); |
+ s = bfd_get_linker_section (dynobj, ".interp"); |
BFD_ASSERT (s != NULL); |
s->size = sizeof ELF32_DYNAMIC_INTERPRETER; |
s->contents = (unsigned char *) ELF32_DYNAMIC_INTERPRETER; |
@@ -2467,6 +2665,87 @@ tpoff (struct bfd_link_info *info, bfd_vma address) |
return (address - htab->tls_sec->vma); |
} |
+/* Replace the MASK bits in ADDR with those in INSN, for the next |
+ TILEPRO_BUNDLE_SIZE_IN_BYTES bytes. */ |
+ |
+static void |
+tilepro_replace_insn (bfd_byte *addr, const bfd_byte *mask, |
+ const bfd_byte *insn) |
+{ |
+ int i; |
+ for (i = 0; i < TILEPRO_BUNDLE_SIZE_IN_BYTES; i++) |
+ { |
+ addr[i] = (addr[i] & ~mask[i]) | (insn[i] & mask[i]); |
+ } |
+} |
+ |
+/* Mask to extract the bits corresponding to an instruction in a |
+ specific pipe of a bundle. */ |
+static const bfd_byte insn_mask_X1[] = { |
+ 0x00, 0x00, 0x00, 0x80, 0xff, 0xff, 0xff, 0x7f |
+}; |
+ |
+/* Mask to extract the bits corresponding to an instruction in a |
+ specific pipe of a bundle, minus the destination operand and the |
+ first source operand. */ |
+static const bfd_byte insn_mask_X0_no_dest_no_srca[] = { |
+ 0x00, 0xf0, 0xff, 0x7f, 0x00, 0x00, 0x00, 0x00 |
+}; |
+ |
+static const bfd_byte insn_mask_X1_no_dest_no_srca[] = { |
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0xf8, 0xff, 0x7f |
+}; |
+ |
+static const bfd_byte insn_mask_Y0_no_dest_no_srca[] = { |
+ 0x00, 0xf0, 0x0f, 0x78, 0x00, 0x00, 0x00, 0x00 |
+}; |
+ |
+static const bfd_byte insn_mask_Y1_no_dest_no_srca[] = { |
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0xf8, 0x07, 0x78 |
+}; |
+ |
+/* Mask to extract the first source operand of an instruction. */ |
+static const bfd_byte srca_mask_X0[] = { |
+ 0xc0, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 |
+}; |
+ |
+static const bfd_byte srca_mask_X1[] = { |
+ 0x00, 0x00, 0x00, 0x00, 0xe0, 0x07, 0x00, 0x00 |
+}; |
+ |
+/* Various instructions synthesized to support tls references. */ |
+ |
+/* move r0, r0 in the X1 pipe, used for tls le. */ |
+static const bfd_byte insn_tls_le_move_X1[] = { |
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0xf8, 0x33, 0x08 |
+}; |
+ |
+/* move r0, zero in the X0 and X1 pipe, used for tls le. */ |
+static const bfd_byte insn_tls_le_move_zero_X0X1[] = { |
+ 0xc0, 0xff, 0xcf, 0x00, 0xe0, 0xff, 0x33, 0x08 |
+}; |
+ |
+/* lw r0, r0 in the X1 pipe, used for tls ie. */ |
+static const bfd_byte insn_tls_ie_lw_X1[] = { |
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x70, 0x0b, 0x40 |
+}; |
+ |
+/* add r0, r0, tp in various pipes, used for tls ie. */ |
+static const bfd_byte insn_tls_ie_add_X0X1[] = { |
+ 0x00, 0x50, 0x0f, 0x00, 0x00, 0xa8, 0x07, 0x08 |
+}; |
+static const bfd_byte insn_tls_ie_add_Y0Y1[] = { |
+ 0x00, 0x50, 0x03, 0x08, 0x00, 0xa8, 0x01, 0x8c |
+}; |
+ |
+/* move r0, r0 in various pipes, used for tls gd. */ |
+static const bfd_byte insn_tls_gd_add_X0X1[] = { |
+ 0x00, 0xf0, 0xcf, 0x00, 0x00, 0xf8, 0x33, 0x08 |
+}; |
+static const bfd_byte insn_tls_gd_add_Y0Y1[] = { |
+ 0x00, 0xf0, 0x0b, 0x18, 0x00, 0xf8, 0x05, 0x9c |
+}; |
+ |
/* Relocate an TILEPRO ELF section. |
The RELOCATE_SECTION function is called by the new ELF backend linker |
@@ -2531,6 +2810,7 @@ tilepro_elf_relocate_section (bfd *output_bfd, struct bfd_link_info *info, |
for (; rel < relend; rel++) |
{ |
int r_type, tls_type; |
+ bfd_boolean is_tls_iele, is_tls_le; |
reloc_howto_type *howto; |
unsigned long r_symndx; |
struct elf_link_hash_entry *h; |
@@ -2594,9 +2874,9 @@ tilepro_elf_relocate_section (bfd *output_bfd, struct bfd_link_info *info, |
} |
} |
- if (sec != NULL && elf_discarded_section (sec)) |
+ if (sec != NULL && discarded_section (sec)) |
RELOC_AGAINST_DISCARDED_SECTION (info, input_bfd, input_section, |
- rel, relend, howto, contents); |
+ rel, 1, relend, howto, 0, contents); |
if (info->relocatable) |
continue; |
@@ -2613,6 +2893,118 @@ tilepro_elf_relocate_section (bfd *output_bfd, struct bfd_link_info *info, |
switch (r_type) |
{ |
+ case R_TILEPRO_TLS_GD_CALL: |
+ case R_TILEPRO_IMM8_X0_TLS_GD_ADD: |
+ case R_TILEPRO_IMM8_Y0_TLS_GD_ADD: |
+ case R_TILEPRO_IMM8_X1_TLS_GD_ADD: |
+ case R_TILEPRO_IMM8_Y1_TLS_GD_ADD: |
+ case R_TILEPRO_IMM16_X0_TLS_GD_HA: |
+ case R_TILEPRO_IMM16_X1_TLS_GD_HA: |
+ case R_TILEPRO_IMM16_X0_TLS_IE_HA: |
+ case R_TILEPRO_IMM16_X1_TLS_IE_HA: |
+ tls_type = GOT_UNKNOWN; |
+ if (h == NULL && local_got_offsets) |
+ tls_type = |
+ _bfd_tilepro_elf_local_got_tls_type (input_bfd) [r_symndx]; |
+ else if (h != NULL) |
+ tls_type = tilepro_elf_hash_entry(h)->tls_type; |
+ |
+ is_tls_iele = (! info->shared || tls_type == GOT_TLS_IE); |
+ is_tls_le = is_tls_iele && (!info->shared |
+ && (h == NULL || h->dynindx == -1)); |
+ |
+ if (r_type == R_TILEPRO_TLS_GD_CALL) |
+ { |
+ if (is_tls_le) |
+ { |
+ /* GD -> LE */ |
+ tilepro_replace_insn (contents + rel->r_offset, |
+ insn_mask_X1, insn_tls_le_move_X1); |
+ continue; |
+ } |
+ else if (is_tls_iele) |
+ { |
+ /* GD -> IE */ |
+ tilepro_replace_insn (contents + rel->r_offset, |
+ insn_mask_X1, insn_tls_ie_lw_X1); |
+ continue; |
+ } |
+ |
+ /* GD -> GD */ |
+ h = (struct elf_link_hash_entry *) |
+ bfd_link_hash_lookup (info->hash, "__tls_get_addr", FALSE, |
+ FALSE, TRUE); |
+ BFD_ASSERT (h != NULL); |
+ r_type = R_TILEPRO_JOFFLONG_X1_PLT; |
+ howto = tilepro_elf_howto_table + r_type; |
+ } |
+ else if (r_type == R_TILEPRO_IMM16_X0_TLS_GD_HA |
+ || r_type == R_TILEPRO_IMM16_X0_TLS_IE_HA) |
+ { |
+ if (is_tls_le) |
+ tilepro_replace_insn (contents + rel->r_offset, srca_mask_X0, |
+ insn_tls_le_move_zero_X0X1); |
+ } |
+ else if (r_type == R_TILEPRO_IMM16_X1_TLS_GD_HA |
+ || r_type == R_TILEPRO_IMM16_X1_TLS_IE_HA) |
+ { |
+ if (is_tls_le) |
+ tilepro_replace_insn (contents + rel->r_offset, srca_mask_X1, |
+ insn_tls_le_move_zero_X0X1); |
+ } |
+ else |
+ { |
+ const bfd_byte *mask = NULL; |
+ const bfd_byte *add_insn = NULL; |
+ |
+ switch (r_type) |
+ { |
+ case R_TILEPRO_IMM8_X0_TLS_GD_ADD: |
+ add_insn = is_tls_iele ? insn_tls_ie_add_X0X1 |
+ : insn_tls_gd_add_X0X1; |
+ mask = insn_mask_X0_no_dest_no_srca; |
+ break; |
+ case R_TILEPRO_IMM8_X1_TLS_GD_ADD: |
+ add_insn = is_tls_iele ? insn_tls_ie_add_X0X1 |
+ : insn_tls_gd_add_X0X1; |
+ mask = insn_mask_X1_no_dest_no_srca; |
+ break; |
+ case R_TILEPRO_IMM8_Y0_TLS_GD_ADD: |
+ add_insn = is_tls_iele ? insn_tls_ie_add_Y0Y1 |
+ : insn_tls_gd_add_Y0Y1; |
+ mask = insn_mask_Y0_no_dest_no_srca; |
+ break; |
+ case R_TILEPRO_IMM8_Y1_TLS_GD_ADD: |
+ add_insn = is_tls_iele ? insn_tls_ie_add_Y0Y1 |
+ : insn_tls_gd_add_Y0Y1; |
+ mask = insn_mask_Y1_no_dest_no_srca; |
+ break; |
+ } |
+ |
+ tilepro_replace_insn (contents + rel->r_offset, mask, add_insn); |
+ |
+ continue; |
+ } |
+ break; |
+ case R_TILEPRO_TLS_IE_LOAD: |
+ if (!info->shared && (h == NULL || h->dynindx == -1)) |
+ /* IE -> LE */ |
+ tilepro_replace_insn (contents + rel->r_offset, |
+ insn_mask_X1_no_dest_no_srca, |
+ insn_tls_le_move_X1); |
+ else |
+ /* IE -> IE */ |
+ tilepro_replace_insn (contents + rel->r_offset, |
+ insn_mask_X1_no_dest_no_srca, |
+ insn_tls_ie_lw_X1); |
+ continue; |
+ break; |
+ default: |
+ break; |
+ } |
+ |
+ switch (r_type) |
+ { |
case R_TILEPRO_IMM16_X0_GOT: |
case R_TILEPRO_IMM16_X1_GOT: |
case R_TILEPRO_IMM16_X0_GOT_LO: |
@@ -2908,6 +3300,45 @@ tilepro_elf_relocate_section (bfd *output_bfd, struct bfd_link_info *info, |
} |
break; |
+ case R_TILEPRO_IMM16_X0_TLS_LE: |
+ case R_TILEPRO_IMM16_X1_TLS_LE: |
+ case R_TILEPRO_IMM16_X0_TLS_LE_LO: |
+ case R_TILEPRO_IMM16_X1_TLS_LE_LO: |
+ case R_TILEPRO_IMM16_X0_TLS_LE_HI: |
+ case R_TILEPRO_IMM16_X1_TLS_LE_HI: |
+ case R_TILEPRO_IMM16_X0_TLS_LE_HA: |
+ case R_TILEPRO_IMM16_X1_TLS_LE_HA: |
+ if (info->shared) |
+ { |
+ Elf_Internal_Rela outrel; |
+ bfd_boolean skip; |
+ |
+ BFD_ASSERT (sreloc != NULL); |
+ skip = FALSE; |
+ outrel.r_offset = |
+ _bfd_elf_section_offset (output_bfd, info, input_section, |
+ rel->r_offset); |
+ if (outrel.r_offset == (bfd_vma) -1) |
+ skip = TRUE; |
+ else if (outrel.r_offset == (bfd_vma) -2) |
+ skip = TRUE; |
+ outrel.r_offset += (input_section->output_section->vma |
+ + input_section->output_offset); |
+ if (skip) |
+ memset (&outrel, 0, sizeof outrel); |
+ else |
+ { |
+ outrel.r_info = ELF32_R_INFO (0, r_type); |
+ outrel.r_addend = relocation - dtpoff_base (info) |
+ + rel->r_addend; |
+ } |
+ |
+ tilepro_elf_append_rela_32 (output_bfd, sreloc, &outrel); |
+ continue; |
+ } |
+ relocation = tpoff (info, relocation); |
+ break; |
+ |
case R_TILEPRO_IMM16_X0_TLS_GD: |
case R_TILEPRO_IMM16_X1_TLS_GD: |
case R_TILEPRO_IMM16_X0_TLS_GD_LO: |
@@ -2916,9 +3347,6 @@ tilepro_elf_relocate_section (bfd *output_bfd, struct bfd_link_info *info, |
case R_TILEPRO_IMM16_X1_TLS_GD_HI: |
case R_TILEPRO_IMM16_X0_TLS_GD_HA: |
case R_TILEPRO_IMM16_X1_TLS_GD_HA: |
- tls_type = GOT_TLS_GD; |
- goto have_tls_reference; |
- |
case R_TILEPRO_IMM16_X0_TLS_IE: |
case R_TILEPRO_IMM16_X1_TLS_IE: |
case R_TILEPRO_IMM16_X0_TLS_IE_LO: |
@@ -2927,45 +3355,32 @@ tilepro_elf_relocate_section (bfd *output_bfd, struct bfd_link_info *info, |
case R_TILEPRO_IMM16_X1_TLS_IE_HI: |
case R_TILEPRO_IMM16_X0_TLS_IE_HA: |
case R_TILEPRO_IMM16_X1_TLS_IE_HA: |
- tls_type = GOT_TLS_IE; |
- /* Fall through. */ |
- |
- have_tls_reference: |
+ r_type = tilepro_elf_tls_transition (info, r_type, h == NULL); |
+ tls_type = GOT_UNKNOWN; |
if (h == NULL && local_got_offsets) |
tls_type |
= _bfd_tilepro_elf_local_got_tls_type (input_bfd) [r_symndx]; |
else if (h != NULL) |
{ |
tls_type = tilepro_elf_hash_entry(h)->tls_type; |
+ if (!info->shared && h->dynindx == -1 && tls_type == GOT_TLS_IE) |
+ r_type = tilepro_tls_translate_to_le (r_type); |
} |
if (tls_type == GOT_TLS_IE) |
- switch (r_type) |
- { |
- case R_TILEPRO_IMM16_X0_TLS_GD: |
- r_type = R_TILEPRO_IMM16_X0_TLS_IE; |
- break; |
- case R_TILEPRO_IMM16_X1_TLS_GD: |
- r_type = R_TILEPRO_IMM16_X1_TLS_IE; |
- break; |
- case R_TILEPRO_IMM16_X0_TLS_GD_LO: |
- r_type = R_TILEPRO_IMM16_X0_TLS_IE_LO; |
- break; |
- case R_TILEPRO_IMM16_X1_TLS_GD_LO: |
- r_type = R_TILEPRO_IMM16_X1_TLS_IE_LO; |
- break; |
- case R_TILEPRO_IMM16_X0_TLS_GD_HI: |
- r_type = R_TILEPRO_IMM16_X0_TLS_IE_HI; |
- break; |
- case R_TILEPRO_IMM16_X1_TLS_GD_HI: |
- r_type = R_TILEPRO_IMM16_X1_TLS_IE_HI; |
- break; |
- case R_TILEPRO_IMM16_X0_TLS_GD_HA: |
- r_type = R_TILEPRO_IMM16_X0_TLS_IE_HA; |
- break; |
- case R_TILEPRO_IMM16_X1_TLS_GD_HA: |
- r_type = R_TILEPRO_IMM16_X1_TLS_IE_HA; |
- break; |
- } |
+ r_type = tilepro_tls_translate_to_ie (r_type); |
+ |
+ if (r_type == R_TILEPRO_IMM16_X0_TLS_LE |
+ || r_type == R_TILEPRO_IMM16_X1_TLS_LE |
+ || r_type == R_TILEPRO_IMM16_X0_TLS_LE_LO |
+ || r_type == R_TILEPRO_IMM16_X1_TLS_LE_LO |
+ || r_type == R_TILEPRO_IMM16_X0_TLS_LE_HI |
+ || r_type == R_TILEPRO_IMM16_X1_TLS_LE_HI |
+ || r_type == R_TILEPRO_IMM16_X0_TLS_LE_HA |
+ || r_type == R_TILEPRO_IMM16_X1_TLS_LE_HA) |
+ { |
+ relocation = tpoff (info, relocation); |
+ break; |
+ } |
if (h != NULL) |
{ |
@@ -3360,8 +3775,7 @@ tilepro_elf_finish_dynamic_symbol (bfd *output_bfd, |
/* This symbols needs a copy reloc. Set it up. */ |
BFD_ASSERT (h->dynindx != -1); |
- s = bfd_get_section_by_name (h->root.u.def.section->owner, |
- ".rela.bss"); |
+ s = htab->srelbss; |
BFD_ASSERT (s != NULL); |
rela.r_offset = (h->root.u.def.value |
@@ -3436,14 +3850,14 @@ tilepro_elf_finish_dynamic_sections (bfd *output_bfd, |
BFD_ASSERT (htab != NULL); |
dynobj = htab->elf.dynobj; |
- sdyn = bfd_get_section_by_name (dynobj, ".dynamic"); |
+ sdyn = bfd_get_linker_section (dynobj, ".dynamic"); |
if (elf_hash_table (info)->dynamic_sections_created) |
{ |
asection *splt; |
bfd_boolean ret; |
- splt = bfd_get_section_by_name (dynobj, ".plt"); |
+ splt = htab->elf.splt; |
BFD_ASSERT (splt != NULL && sdyn != NULL); |
ret = tilepro_finish_dyn (output_bfd, info, dynobj, sdyn, splt); |