Index: bfd/elfxx-tilegx.c |
diff --git a/bfd/elfxx-tilegx.c b/bfd/elfxx-tilegx.c |
index 2aaa3d317570a6172cd351cda540a28182bde4d6..6f748ece7f09a477f23315f3757782f25b984090 100644 |
--- a/bfd/elfxx-tilegx.c |
+++ b/bfd/elfxx-tilegx.c |
@@ -1,5 +1,5 @@ |
/* TILE-Gx-specific support for 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/tilegx.h" |
@@ -490,35 +490,38 @@ static reloc_howto_type tilegx_elf_howto_table [] = |
TILEGX_IMM16_HOWTO (R_TILEGX_IMM16_X0_HW0_GOT, 0), |
TILEGX_IMM16_HOWTO (R_TILEGX_IMM16_X1_HW0_GOT, 0), |
- TILEGX_IMM16_HOWTO (R_TILEGX_IMM16_X0_HW1_GOT, 16), |
- TILEGX_IMM16_HOWTO (R_TILEGX_IMM16_X1_HW1_GOT, 16), |
- TILEGX_IMM16_HOWTO (R_TILEGX_IMM16_X0_HW2_GOT, 32), |
- TILEGX_IMM16_HOWTO (R_TILEGX_IMM16_X1_HW2_GOT, 32), |
- TILEGX_IMM16_HOWTO (R_TILEGX_IMM16_X0_HW3_GOT, 48), |
- TILEGX_IMM16_HOWTO (R_TILEGX_IMM16_X1_HW3_GOT, 48), |
+ /* These relocs are currently not defined. */ |
+ EMPTY_HOWTO (66), |
+ EMPTY_HOWTO (67), |
+ EMPTY_HOWTO (68), |
+ EMPTY_HOWTO (69), |
+ EMPTY_HOWTO (70), |
+ EMPTY_HOWTO (71), |
TILEGX_IMM16_HOWTO_LAST (R_TILEGX_IMM16_X0_HW0_LAST_GOT, 0), |
TILEGX_IMM16_HOWTO_LAST (R_TILEGX_IMM16_X1_HW0_LAST_GOT, 0), |
TILEGX_IMM16_HOWTO_LAST (R_TILEGX_IMM16_X0_HW1_LAST_GOT, 16), |
TILEGX_IMM16_HOWTO_LAST (R_TILEGX_IMM16_X1_HW1_LAST_GOT, 16), |
- TILEGX_IMM16_HOWTO_LAST (R_TILEGX_IMM16_X0_HW2_LAST_GOT, 32), |
- TILEGX_IMM16_HOWTO_LAST (R_TILEGX_IMM16_X1_HW2_LAST_GOT, 32), |
+ /* These relocs are currently not defined. */ |
+ EMPTY_HOWTO (76), |
+ EMPTY_HOWTO (77), |
TILEGX_IMM16_HOWTO (R_TILEGX_IMM16_X0_HW0_TLS_GD, 0), |
TILEGX_IMM16_HOWTO (R_TILEGX_IMM16_X1_HW0_TLS_GD, 0), |
- TILEGX_IMM16_HOWTO (R_TILEGX_IMM16_X0_HW1_TLS_GD, 16), |
- TILEGX_IMM16_HOWTO (R_TILEGX_IMM16_X1_HW1_TLS_GD, 16), |
- TILEGX_IMM16_HOWTO (R_TILEGX_IMM16_X0_HW2_TLS_GD, 32), |
- TILEGX_IMM16_HOWTO (R_TILEGX_IMM16_X1_HW2_TLS_GD, 32), |
- TILEGX_IMM16_HOWTO (R_TILEGX_IMM16_X0_HW3_TLS_GD, 48), |
- TILEGX_IMM16_HOWTO (R_TILEGX_IMM16_X1_HW3_TLS_GD, 48), |
+ |
+ TILEGX_IMM16_HOWTO (R_TILEGX_IMM16_X0_HW0_TLS_LE, 0), |
+ TILEGX_IMM16_HOWTO (R_TILEGX_IMM16_X1_HW0_TLS_LE, 0), |
+ TILEGX_IMM16_HOWTO_LAST (R_TILEGX_IMM16_X0_HW0_LAST_TLS_LE, 0), |
+ TILEGX_IMM16_HOWTO_LAST (R_TILEGX_IMM16_X1_HW0_LAST_TLS_LE, 0), |
+ TILEGX_IMM16_HOWTO_LAST (R_TILEGX_IMM16_X0_HW1_LAST_TLS_LE, 16), |
+ TILEGX_IMM16_HOWTO_LAST (R_TILEGX_IMM16_X1_HW1_LAST_TLS_LE, 16), |
TILEGX_IMM16_HOWTO_LAST (R_TILEGX_IMM16_X0_HW0_LAST_TLS_GD, 0), |
TILEGX_IMM16_HOWTO_LAST (R_TILEGX_IMM16_X1_HW0_LAST_TLS_GD, 0), |
TILEGX_IMM16_HOWTO_LAST (R_TILEGX_IMM16_X0_HW1_LAST_TLS_GD, 16), |
TILEGX_IMM16_HOWTO_LAST (R_TILEGX_IMM16_X1_HW1_LAST_TLS_GD, 16), |
- TILEGX_IMM16_HOWTO_LAST (R_TILEGX_IMM16_X0_HW2_LAST_TLS_GD, 32), |
- TILEGX_IMM16_HOWTO_LAST (R_TILEGX_IMM16_X1_HW2_LAST_TLS_GD, 32), |
+ EMPTY_HOWTO (90), |
+ EMPTY_HOWTO (91), |
#define TILEGX_IMM16_HOWTO_TLS_IE(name, rshift) \ |
HOWTO (name, rshift, 1, 16, FALSE, 0, \ |
@@ -527,12 +530,12 @@ static reloc_howto_type tilegx_elf_howto_table [] = |
TILEGX_IMM16_HOWTO_TLS_IE (R_TILEGX_IMM16_X0_HW0_TLS_IE, 0), |
TILEGX_IMM16_HOWTO_TLS_IE (R_TILEGX_IMM16_X1_HW0_TLS_IE, 0), |
- TILEGX_IMM16_HOWTO_TLS_IE (R_TILEGX_IMM16_X0_HW1_TLS_IE, 16), |
- TILEGX_IMM16_HOWTO_TLS_IE (R_TILEGX_IMM16_X1_HW1_TLS_IE, 16), |
- TILEGX_IMM16_HOWTO_TLS_IE (R_TILEGX_IMM16_X0_HW2_TLS_IE, 32), |
- TILEGX_IMM16_HOWTO_TLS_IE (R_TILEGX_IMM16_X1_HW2_TLS_IE, 32), |
- TILEGX_IMM16_HOWTO_TLS_IE (R_TILEGX_IMM16_X0_HW3_TLS_IE, 48), |
- TILEGX_IMM16_HOWTO_TLS_IE (R_TILEGX_IMM16_X1_HW3_TLS_IE, 48), |
+ EMPTY_HOWTO (94), |
+ EMPTY_HOWTO (95), |
+ EMPTY_HOWTO (96), |
+ EMPTY_HOWTO (97), |
+ EMPTY_HOWTO (98), |
+ EMPTY_HOWTO (99), |
#define TILEGX_IMM16_HOWTO_LAST_TLS_IE(name, rshift) \ |
HOWTO (name, rshift, 1, 16, FALSE, 0, \ |
@@ -543,8 +546,8 @@ static reloc_howto_type tilegx_elf_howto_table [] = |
TILEGX_IMM16_HOWTO_LAST_TLS_IE (R_TILEGX_IMM16_X1_HW0_LAST_TLS_IE, 0), |
TILEGX_IMM16_HOWTO_LAST_TLS_IE (R_TILEGX_IMM16_X0_HW1_LAST_TLS_IE, 16), |
TILEGX_IMM16_HOWTO_LAST_TLS_IE (R_TILEGX_IMM16_X1_HW1_LAST_TLS_IE, 16), |
- TILEGX_IMM16_HOWTO_LAST_TLS_IE (R_TILEGX_IMM16_X0_HW2_LAST_TLS_IE, 32), |
- TILEGX_IMM16_HOWTO_LAST_TLS_IE (R_TILEGX_IMM16_X1_HW2_LAST_TLS_IE, 32), |
+ EMPTY_HOWTO (104), |
+ EMPTY_HOWTO (105), |
HOWTO(R_TILEGX_TLS_DTPMOD64, 0, 0, 0, FALSE, 0, complain_overflow_dont, |
bfd_elf_generic_reloc, "R_TILEGX_TLS_DTPMOD64", |
@@ -564,7 +567,31 @@ static reloc_howto_type tilegx_elf_howto_table [] = |
FALSE, 0, -1, TRUE), |
HOWTO(R_TILEGX_TLS_TPOFF32, 0, 0, 0, FALSE, 0, complain_overflow_dont, |
bfd_elf_generic_reloc, "R_TILEGX_TLS_TPOFF32", |
- FALSE, 0, 0, TRUE) |
+ FALSE, 0, 0, TRUE), |
+ |
+ HOWTO (R_TILEGX_TLS_GD_CALL, /* type */ |
+ TILEGX_LOG2_BUNDLE_ALIGNMENT_IN_BYTES, /* rightshift */ |
+ 2, /* size (0 = byte, 1 = short, 2 = long) */ |
+ 27, /* bitsize */ |
+ TRUE, /* pc_relative */ |
+ 0, /* bitpos */ |
+ complain_overflow_signed,/* complain_on_overflow */ |
+ bfd_elf_generic_reloc, /* special_function */ |
+ "R_TILEGX_TLS_GD_CALL", /* name */ |
+ FALSE, /* partial_inplace */ |
+ 0, /* src_mask */ |
+ -1, /* dst_mask */ |
+ TRUE), /* pcrel_offset */ |
+ |
+ TILEGX_IMM_HOWTO(R_TILEGX_IMM8_X0_TLS_GD_ADD, 0, 8), |
+ TILEGX_IMM_HOWTO(R_TILEGX_IMM8_X1_TLS_GD_ADD, 0, 8), |
+ TILEGX_IMM_HOWTO(R_TILEGX_IMM8_Y0_TLS_GD_ADD, 0, 8), |
+ TILEGX_IMM_HOWTO(R_TILEGX_IMM8_Y1_TLS_GD_ADD, 0, 8), |
+ TILEGX_IMM_HOWTO(R_TILEGX_TLS_IE_LOAD, 0, 8), |
+ TILEGX_IMM_HOWTO(R_TILEGX_IMM8_X0_TLS_ADD, 0, 8), |
+ TILEGX_IMM_HOWTO(R_TILEGX_IMM8_X1_TLS_ADD, 0, 8), |
+ TILEGX_IMM_HOWTO(R_TILEGX_IMM8_Y0_TLS_ADD, 0, 8), |
+ TILEGX_IMM_HOWTO(R_TILEGX_IMM8_Y1_TLS_ADD, 0, 8), |
}; |
static reloc_howto_type tilegx_elf_howto_table2 [] = |
@@ -686,46 +713,28 @@ static const reloc_map tilegx_reloc_map [] = |
SIMPLE_REMAP (TILEGX_IMM16_X1_HW2_LAST_PCREL) |
SIMPLE_REMAP (TILEGX_IMM16_X0_HW0_GOT) |
SIMPLE_REMAP (TILEGX_IMM16_X1_HW0_GOT) |
- SIMPLE_REMAP (TILEGX_IMM16_X0_HW1_GOT) |
- SIMPLE_REMAP (TILEGX_IMM16_X1_HW1_GOT) |
- SIMPLE_REMAP (TILEGX_IMM16_X0_HW2_GOT) |
- SIMPLE_REMAP (TILEGX_IMM16_X1_HW2_GOT) |
- SIMPLE_REMAP (TILEGX_IMM16_X0_HW3_GOT) |
- SIMPLE_REMAP (TILEGX_IMM16_X1_HW3_GOT) |
SIMPLE_REMAP (TILEGX_IMM16_X0_HW0_LAST_GOT) |
SIMPLE_REMAP (TILEGX_IMM16_X1_HW0_LAST_GOT) |
SIMPLE_REMAP (TILEGX_IMM16_X0_HW1_LAST_GOT) |
SIMPLE_REMAP (TILEGX_IMM16_X1_HW1_LAST_GOT) |
- SIMPLE_REMAP (TILEGX_IMM16_X0_HW2_LAST_GOT) |
- SIMPLE_REMAP (TILEGX_IMM16_X1_HW2_LAST_GOT) |
SIMPLE_REMAP (TILEGX_IMM16_X0_HW0_TLS_GD) |
SIMPLE_REMAP (TILEGX_IMM16_X1_HW0_TLS_GD) |
- SIMPLE_REMAP (TILEGX_IMM16_X0_HW1_TLS_GD) |
- SIMPLE_REMAP (TILEGX_IMM16_X1_HW1_TLS_GD) |
- SIMPLE_REMAP (TILEGX_IMM16_X0_HW2_TLS_GD) |
- SIMPLE_REMAP (TILEGX_IMM16_X1_HW2_TLS_GD) |
- SIMPLE_REMAP (TILEGX_IMM16_X0_HW3_TLS_GD) |
- SIMPLE_REMAP (TILEGX_IMM16_X1_HW3_TLS_GD) |
+ SIMPLE_REMAP (TILEGX_IMM16_X0_HW0_TLS_LE) |
+ SIMPLE_REMAP (TILEGX_IMM16_X1_HW0_TLS_LE) |
+ SIMPLE_REMAP (TILEGX_IMM16_X0_HW0_LAST_TLS_LE) |
+ SIMPLE_REMAP (TILEGX_IMM16_X1_HW0_LAST_TLS_LE) |
+ SIMPLE_REMAP (TILEGX_IMM16_X0_HW1_LAST_TLS_LE) |
+ SIMPLE_REMAP (TILEGX_IMM16_X1_HW1_LAST_TLS_LE) |
SIMPLE_REMAP (TILEGX_IMM16_X0_HW0_LAST_TLS_GD) |
SIMPLE_REMAP (TILEGX_IMM16_X1_HW0_LAST_TLS_GD) |
SIMPLE_REMAP (TILEGX_IMM16_X0_HW1_LAST_TLS_GD) |
SIMPLE_REMAP (TILEGX_IMM16_X1_HW1_LAST_TLS_GD) |
- SIMPLE_REMAP (TILEGX_IMM16_X0_HW2_LAST_TLS_GD) |
- SIMPLE_REMAP (TILEGX_IMM16_X1_HW2_LAST_TLS_GD) |
SIMPLE_REMAP (TILEGX_IMM16_X0_HW0_TLS_IE) |
SIMPLE_REMAP (TILEGX_IMM16_X1_HW0_TLS_IE) |
- SIMPLE_REMAP (TILEGX_IMM16_X0_HW1_TLS_IE) |
- SIMPLE_REMAP (TILEGX_IMM16_X1_HW1_TLS_IE) |
- SIMPLE_REMAP (TILEGX_IMM16_X0_HW2_TLS_IE) |
- SIMPLE_REMAP (TILEGX_IMM16_X1_HW2_TLS_IE) |
- SIMPLE_REMAP (TILEGX_IMM16_X0_HW3_TLS_IE) |
- SIMPLE_REMAP (TILEGX_IMM16_X1_HW3_TLS_IE) |
SIMPLE_REMAP (TILEGX_IMM16_X0_HW0_LAST_TLS_IE) |
SIMPLE_REMAP (TILEGX_IMM16_X1_HW0_LAST_TLS_IE) |
SIMPLE_REMAP (TILEGX_IMM16_X0_HW1_LAST_TLS_IE) |
SIMPLE_REMAP (TILEGX_IMM16_X1_HW1_LAST_TLS_IE) |
- SIMPLE_REMAP (TILEGX_IMM16_X0_HW2_LAST_TLS_IE) |
- SIMPLE_REMAP (TILEGX_IMM16_X1_HW2_LAST_TLS_IE) |
SIMPLE_REMAP (TILEGX_TLS_DTPMOD64) |
SIMPLE_REMAP (TILEGX_TLS_DTPOFF64) |
@@ -735,6 +744,17 @@ static const reloc_map tilegx_reloc_map [] = |
SIMPLE_REMAP (TILEGX_TLS_DTPOFF32) |
SIMPLE_REMAP (TILEGX_TLS_TPOFF32) |
+ SIMPLE_REMAP (TILEGX_TLS_GD_CALL) |
+ SIMPLE_REMAP (TILEGX_IMM8_X0_TLS_GD_ADD) |
+ SIMPLE_REMAP (TILEGX_IMM8_X1_TLS_GD_ADD) |
+ SIMPLE_REMAP (TILEGX_IMM8_Y0_TLS_GD_ADD) |
+ SIMPLE_REMAP (TILEGX_IMM8_Y1_TLS_GD_ADD) |
+ SIMPLE_REMAP (TILEGX_TLS_IE_LOAD) |
+ SIMPLE_REMAP (TILEGX_IMM8_X0_TLS_ADD) |
+ SIMPLE_REMAP (TILEGX_IMM8_X1_TLS_ADD) |
+ SIMPLE_REMAP (TILEGX_IMM8_Y0_TLS_ADD) |
+ SIMPLE_REMAP (TILEGX_IMM8_Y1_TLS_ADD) |
+ |
#undef SIMPLE_REMAP |
#undef TH_REMAP |
@@ -824,6 +844,10 @@ struct tilegx_elf_link_hash_table |
asection *sdynbss; |
asection *srelbss; |
+ /* Whether LE transition has been disabled for some of the |
+ sections. */ |
+ bfd_boolean disable_le_transition; |
+ |
/* Small local sym to section mapping cache. */ |
struct sym_cache sym_cache; |
}; |
@@ -920,7 +944,7 @@ tilegx_info_to_howto_rela (bfd *abfd ATTRIBUTE_UNUSED, |
{ |
unsigned int r_type = TILEGX_ELF_R_TYPE (dst->r_info); |
- if (r_type <= (unsigned int) R_TILEGX_TLS_TPOFF32) |
+ if (r_type <= (unsigned int) R_TILEGX_IMM8_Y1_TLS_ADD) |
cache_ptr->howto = &tilegx_elf_howto_table [r_type]; |
else if (r_type - R_TILEGX_GNU_VTINHERIT |
<= (unsigned int) R_TILEGX_GNU_VTENTRY) |
@@ -1003,10 +1027,18 @@ static const tilegx_create_func reloc_to_create_func[] = |
create_Imm16_X1, |
create_Imm16_X0, |
create_Imm16_X1, |
+ NULL, |
+ NULL, |
+ NULL, |
+ NULL, |
+ NULL, |
+ NULL, |
create_Imm16_X0, |
create_Imm16_X1, |
create_Imm16_X0, |
create_Imm16_X1, |
+ NULL, |
+ NULL, |
create_Imm16_X0, |
create_Imm16_X1, |
create_Imm16_X0, |
@@ -1019,30 +1051,20 @@ static const tilegx_create_func reloc_to_create_func[] = |
create_Imm16_X1, |
create_Imm16_X0, |
create_Imm16_X1, |
+ NULL, |
+ NULL, |
create_Imm16_X0, |
create_Imm16_X1, |
+ NULL, |
+ NULL, |
+ NULL, |
+ 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, |
- create_Imm16_X0, |
- create_Imm16_X1, |
- create_Imm16_X0, |
- create_Imm16_X1, |
- create_Imm16_X0, |
- create_Imm16_X1, |
- create_Imm16_X0, |
- create_Imm16_X1, |
- create_Imm16_X0, |
- create_Imm16_X1, |
- create_Imm16_X0, |
- create_Imm16_X1, |
- create_Imm16_X0, |
- create_Imm16_X1 |
}; |
static void |
@@ -1402,23 +1424,23 @@ tilegx_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; |
- s = bfd_make_section_with_flags (abfd, |
- (bed->rela_plts_and_copies_p |
- ? ".rela.got" : ".rel.got"), |
- (bed->dynamic_sec_flags |
- | SEC_READONLY)); |
+ s = bfd_make_section_anyway_with_flags (abfd, |
+ (bed->rela_plts_and_copies_p |
+ ? ".rela.got" : ".rel.got"), |
+ (bed->dynamic_sec_flags |
+ | SEC_READONLY)); |
if (s == NULL |
|| ! bfd_set_section_alignment (abfd, s, bed->s->log_file_align)) |
return FALSE; |
htab->srelgot = s; |
- s = s_got = bfd_make_section_with_flags (abfd, ".got", flags); |
+ s = s_got = bfd_make_section_anyway_with_flags (abfd, ".got", flags); |
if (s == NULL |
|| !bfd_set_section_alignment (abfd, s, bed->s->log_file_align)) |
return FALSE; |
@@ -1429,7 +1451,7 @@ tilegx_elf_create_got_section (bfd *abfd, struct bfd_link_info *info) |
if (bed->want_got_plt) |
{ |
- s = bfd_make_section_with_flags (abfd, ".got.plt", flags); |
+ s = bfd_make_section_anyway_with_flags (abfd, ".got.plt", flags); |
if (s == NULL |
|| !bfd_set_section_alignment (abfd, s, |
bed->s->log_file_align)) |
@@ -1475,9 +1497,9 @@ tilegx_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)) |
@@ -1538,6 +1560,83 @@ tilegx_elf_copy_indirect_symbol (struct bfd_link_info *info, |
_bfd_elf_link_hash_copy_indirect (info, dir, ind); |
} |
+static int |
+tilegx_tls_translate_to_le (int r_type) |
+{ |
+ switch (r_type) |
+ { |
+ case R_TILEGX_IMM16_X0_HW0_TLS_GD: |
+ case R_TILEGX_IMM16_X0_HW0_TLS_IE: |
+ return R_TILEGX_IMM16_X0_HW0_TLS_LE; |
+ |
+ case R_TILEGX_IMM16_X1_HW0_TLS_GD: |
+ case R_TILEGX_IMM16_X1_HW0_TLS_IE: |
+ return R_TILEGX_IMM16_X1_HW0_TLS_LE; |
+ |
+ case R_TILEGX_IMM16_X0_HW0_LAST_TLS_GD: |
+ case R_TILEGX_IMM16_X0_HW0_LAST_TLS_IE: |
+ return R_TILEGX_IMM16_X0_HW0_LAST_TLS_LE; |
+ |
+ case R_TILEGX_IMM16_X1_HW0_LAST_TLS_GD: |
+ case R_TILEGX_IMM16_X1_HW0_LAST_TLS_IE: |
+ return R_TILEGX_IMM16_X1_HW0_LAST_TLS_LE; |
+ |
+ case R_TILEGX_IMM16_X0_HW1_LAST_TLS_GD: |
+ case R_TILEGX_IMM16_X0_HW1_LAST_TLS_IE: |
+ return R_TILEGX_IMM16_X0_HW1_LAST_TLS_LE; |
+ |
+ case R_TILEGX_IMM16_X1_HW1_LAST_TLS_GD: |
+ case R_TILEGX_IMM16_X1_HW1_LAST_TLS_IE: |
+ return R_TILEGX_IMM16_X1_HW1_LAST_TLS_LE; |
+ } |
+ return r_type; |
+} |
+ |
+static int |
+tilegx_tls_translate_to_ie (int r_type) |
+{ |
+ switch (r_type) |
+ { |
+ case R_TILEGX_IMM16_X0_HW0_TLS_GD: |
+ case R_TILEGX_IMM16_X0_HW0_TLS_IE: |
+ return R_TILEGX_IMM16_X0_HW0_TLS_IE; |
+ |
+ case R_TILEGX_IMM16_X1_HW0_TLS_GD: |
+ case R_TILEGX_IMM16_X1_HW0_TLS_IE: |
+ return R_TILEGX_IMM16_X1_HW0_TLS_IE; |
+ |
+ case R_TILEGX_IMM16_X0_HW0_LAST_TLS_GD: |
+ case R_TILEGX_IMM16_X0_HW0_LAST_TLS_IE: |
+ return R_TILEGX_IMM16_X0_HW0_LAST_TLS_IE; |
+ |
+ case R_TILEGX_IMM16_X1_HW0_LAST_TLS_GD: |
+ case R_TILEGX_IMM16_X1_HW0_LAST_TLS_IE: |
+ return R_TILEGX_IMM16_X1_HW0_LAST_TLS_IE; |
+ |
+ case R_TILEGX_IMM16_X0_HW1_LAST_TLS_GD: |
+ case R_TILEGX_IMM16_X0_HW1_LAST_TLS_IE: |
+ return R_TILEGX_IMM16_X0_HW1_LAST_TLS_IE; |
+ |
+ case R_TILEGX_IMM16_X1_HW1_LAST_TLS_GD: |
+ case R_TILEGX_IMM16_X1_HW1_LAST_TLS_IE: |
+ return R_TILEGX_IMM16_X1_HW1_LAST_TLS_IE; |
+ } |
+ return r_type; |
+} |
+ |
+static int |
+tilegx_elf_tls_transition (struct bfd_link_info *info, int r_type, |
+ int is_local, bfd_boolean disable_le_transition) |
+{ |
+ if (info->shared) |
+ return r_type; |
+ |
+ if (is_local && !disable_le_transition) |
+ return tilegx_tls_translate_to_le (r_type); |
+ else |
+ return tilegx_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. */ |
@@ -1553,6 +1652,7 @@ tilegx_elf_check_relocs (bfd *abfd, struct bfd_link_info *info, |
const Elf_Internal_Rela *rel_end; |
asection *sreloc; |
int num_relocs; |
+ bfd_boolean has_tls_gd_or_ie = FALSE, has_tls_add = FALSE; |
if (info->relocatable) |
return TRUE; |
@@ -1571,6 +1671,33 @@ tilegx_elf_check_relocs (bfd *abfd, struct bfd_link_info *info, |
htab->elf.dynobj = abfd; |
rel_end = relocs + num_relocs; |
+ |
+ /* Check whether to do optimization to transform TLS GD/IE |
+ referehces to TLS LE. We disable it if we're linking with old |
+ TLS code sequences that do not support such optimization. Old |
+ TLS code sequences have tls_gd_call/tls_ie_load relocations but |
+ no tls_add relocations. */ |
+ for (rel = relocs; rel < rel_end && !has_tls_add; rel++) |
+ { |
+ int r_type = TILEGX_ELF_R_TYPE (rel->r_info); |
+ switch (r_type) |
+ { |
+ case R_TILEGX_TLS_GD_CALL: |
+ case R_TILEGX_TLS_IE_LOAD: |
+ has_tls_gd_or_ie = TRUE; |
+ break; |
+ case R_TILEGX_IMM8_X0_TLS_ADD: |
+ case R_TILEGX_IMM8_Y0_TLS_ADD: |
+ case R_TILEGX_IMM8_X1_TLS_ADD: |
+ case R_TILEGX_IMM8_Y1_TLS_ADD: |
+ has_tls_add = TRUE; |
+ break; |
+ } |
+ } |
+ |
+ sec->sec_flg0 = (has_tls_gd_or_ie && !has_tls_add); |
+ htab->disable_le_transition |= sec->sec_flg0; |
+ |
for (rel = relocs; rel < rel_end; rel++) |
{ |
unsigned int r_type; |
@@ -1598,39 +1725,36 @@ tilegx_elf_check_relocs (bfd *abfd, struct bfd_link_info *info, |
h = (struct elf_link_hash_entry *) h->root.u.i.link; |
} |
+ r_type = tilegx_elf_tls_transition (info, r_type, h == NULL, |
+ sec->sec_flg0); |
switch (r_type) |
{ |
+ case R_TILEGX_IMM16_X0_HW0_TLS_LE: |
+ case R_TILEGX_IMM16_X1_HW0_TLS_LE: |
+ case R_TILEGX_IMM16_X0_HW0_LAST_TLS_LE: |
+ case R_TILEGX_IMM16_X1_HW0_LAST_TLS_LE: |
+ case R_TILEGX_IMM16_X0_HW1_LAST_TLS_LE: |
+ case R_TILEGX_IMM16_X1_HW1_LAST_TLS_LE: |
+ if (info->shared) |
+ goto r_tilegx_plt32; |
+ break; |
+ |
case R_TILEGX_IMM16_X0_HW0_TLS_GD: |
case R_TILEGX_IMM16_X1_HW0_TLS_GD: |
- case R_TILEGX_IMM16_X0_HW1_TLS_GD: |
- case R_TILEGX_IMM16_X1_HW1_TLS_GD: |
- case R_TILEGX_IMM16_X0_HW2_TLS_GD: |
- case R_TILEGX_IMM16_X1_HW2_TLS_GD: |
- case R_TILEGX_IMM16_X0_HW3_TLS_GD: |
- case R_TILEGX_IMM16_X1_HW3_TLS_GD: |
case R_TILEGX_IMM16_X0_HW0_LAST_TLS_GD: |
case R_TILEGX_IMM16_X1_HW0_LAST_TLS_GD: |
case R_TILEGX_IMM16_X0_HW1_LAST_TLS_GD: |
case R_TILEGX_IMM16_X1_HW1_LAST_TLS_GD: |
- case R_TILEGX_IMM16_X0_HW2_LAST_TLS_GD: |
- case R_TILEGX_IMM16_X1_HW2_LAST_TLS_GD: |
- tls_type = GOT_TLS_GD; |
+ BFD_ASSERT (info->shared); |
+ tls_type = GOT_TLS_GD; |
goto have_got_reference; |
case R_TILEGX_IMM16_X0_HW0_TLS_IE: |
case R_TILEGX_IMM16_X1_HW0_TLS_IE: |
- case R_TILEGX_IMM16_X0_HW1_TLS_IE: |
- case R_TILEGX_IMM16_X1_HW1_TLS_IE: |
- case R_TILEGX_IMM16_X0_HW2_TLS_IE: |
- case R_TILEGX_IMM16_X1_HW2_TLS_IE: |
- case R_TILEGX_IMM16_X0_HW3_TLS_IE: |
- case R_TILEGX_IMM16_X1_HW3_TLS_IE: |
case R_TILEGX_IMM16_X0_HW0_LAST_TLS_IE: |
case R_TILEGX_IMM16_X1_HW0_LAST_TLS_IE: |
case R_TILEGX_IMM16_X0_HW1_LAST_TLS_IE: |
case R_TILEGX_IMM16_X1_HW1_LAST_TLS_IE: |
- case R_TILEGX_IMM16_X0_HW2_LAST_TLS_IE: |
- case R_TILEGX_IMM16_X1_HW2_LAST_TLS_IE: |
tls_type = GOT_TLS_IE; |
if (info->shared) |
info->flags |= DF_STATIC_TLS; |
@@ -1638,18 +1762,10 @@ tilegx_elf_check_relocs (bfd *abfd, struct bfd_link_info *info, |
case R_TILEGX_IMM16_X0_HW0_GOT: |
case R_TILEGX_IMM16_X1_HW0_GOT: |
- case R_TILEGX_IMM16_X0_HW1_GOT: |
- case R_TILEGX_IMM16_X1_HW1_GOT: |
- case R_TILEGX_IMM16_X0_HW2_GOT: |
- case R_TILEGX_IMM16_X1_HW2_GOT: |
- case R_TILEGX_IMM16_X0_HW3_GOT: |
- case R_TILEGX_IMM16_X1_HW3_GOT: |
case R_TILEGX_IMM16_X0_HW0_LAST_GOT: |
case R_TILEGX_IMM16_X1_HW0_LAST_GOT: |
case R_TILEGX_IMM16_X0_HW1_LAST_GOT: |
case R_TILEGX_IMM16_X1_HW1_LAST_GOT: |
- case R_TILEGX_IMM16_X0_HW2_LAST_GOT: |
- case R_TILEGX_IMM16_X1_HW2_LAST_GOT: |
tls_type = GOT_NORMAL; |
/* Fall Through */ |
@@ -1720,6 +1836,24 @@ tilegx_elf_check_relocs (bfd *abfd, struct bfd_link_info *info, |
} |
break; |
+ case R_TILEGX_TLS_GD_CALL: |
+ if (info->shared) |
+ { |
+ /* These are basically R_TILEGX_JUMPOFF_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_TILEGX_JUMPOFF_X1_PLT: |
/* This symbol requires a procedure linkage table entry. We |
actually build the entry in adjust_dynamic_symbol, |
@@ -1805,16 +1939,15 @@ tilegx_elf_check_relocs (bfd *abfd, struct bfd_link_info *info, |
case R_TILEGX_IMM16_X0_HW2_LAST: |
case R_TILEGX_IMM16_X1_HW2_LAST: |
if (h != NULL) |
- { |
- h->non_got_ref = 1; |
+ 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_tilegx_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 |
against a global symbol, or a non PC relative reloc |
@@ -2008,51 +2141,28 @@ tilegx_elf_gc_sweep_hook (bfd *abfd, struct bfd_link_info *info, |
} |
r_type = TILEGX_ELF_R_TYPE (rel->r_info); |
- |
+ r_type = tilegx_elf_tls_transition (info, r_type, h != NULL, |
+ sec->sec_flg0); |
switch (r_type) |
{ |
case R_TILEGX_IMM16_X0_HW0_GOT: |
case R_TILEGX_IMM16_X1_HW0_GOT: |
- case R_TILEGX_IMM16_X0_HW1_GOT: |
- case R_TILEGX_IMM16_X1_HW1_GOT: |
- case R_TILEGX_IMM16_X0_HW2_GOT: |
- case R_TILEGX_IMM16_X1_HW2_GOT: |
- case R_TILEGX_IMM16_X0_HW3_GOT: |
- case R_TILEGX_IMM16_X1_HW3_GOT: |
case R_TILEGX_IMM16_X0_HW0_LAST_GOT: |
case R_TILEGX_IMM16_X1_HW0_LAST_GOT: |
case R_TILEGX_IMM16_X0_HW1_LAST_GOT: |
case R_TILEGX_IMM16_X1_HW1_LAST_GOT: |
- case R_TILEGX_IMM16_X0_HW2_LAST_GOT: |
- case R_TILEGX_IMM16_X1_HW2_LAST_GOT: |
case R_TILEGX_IMM16_X0_HW0_TLS_GD: |
case R_TILEGX_IMM16_X1_HW0_TLS_GD: |
- case R_TILEGX_IMM16_X0_HW1_TLS_GD: |
- case R_TILEGX_IMM16_X1_HW1_TLS_GD: |
- case R_TILEGX_IMM16_X0_HW2_TLS_GD: |
- case R_TILEGX_IMM16_X1_HW2_TLS_GD: |
- case R_TILEGX_IMM16_X0_HW3_TLS_GD: |
- case R_TILEGX_IMM16_X1_HW3_TLS_GD: |
case R_TILEGX_IMM16_X0_HW0_LAST_TLS_GD: |
case R_TILEGX_IMM16_X1_HW0_LAST_TLS_GD: |
case R_TILEGX_IMM16_X0_HW1_LAST_TLS_GD: |
case R_TILEGX_IMM16_X1_HW1_LAST_TLS_GD: |
- case R_TILEGX_IMM16_X0_HW2_LAST_TLS_GD: |
- case R_TILEGX_IMM16_X1_HW2_LAST_TLS_GD: |
case R_TILEGX_IMM16_X0_HW0_TLS_IE: |
case R_TILEGX_IMM16_X1_HW0_TLS_IE: |
- case R_TILEGX_IMM16_X0_HW1_TLS_IE: |
- case R_TILEGX_IMM16_X1_HW1_TLS_IE: |
- case R_TILEGX_IMM16_X0_HW2_TLS_IE: |
- case R_TILEGX_IMM16_X1_HW2_TLS_IE: |
- case R_TILEGX_IMM16_X0_HW3_TLS_IE: |
- case R_TILEGX_IMM16_X1_HW3_TLS_IE: |
case R_TILEGX_IMM16_X0_HW0_LAST_TLS_IE: |
case R_TILEGX_IMM16_X1_HW0_LAST_TLS_IE: |
case R_TILEGX_IMM16_X0_HW1_LAST_TLS_IE: |
case R_TILEGX_IMM16_X1_HW1_LAST_TLS_IE: |
- case R_TILEGX_IMM16_X0_HW2_LAST_TLS_IE: |
- case R_TILEGX_IMM16_X1_HW2_LAST_TLS_IE: |
if (h != NULL) |
{ |
if (h->got.refcount > 0) |
@@ -2060,7 +2170,8 @@ tilegx_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; |
@@ -2256,13 +2367,6 @@ tilegx_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 |
@@ -2277,7 +2381,7 @@ tilegx_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 += TILEGX_ELF_RELA_BYTES (htab); |
h->needs_copy = 1; |
@@ -2361,7 +2465,15 @@ 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 |
+ && !htab->disable_le_transition |
+ && !info->shared |
+ && h->dynindx == -1 |
+ && tilegx_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; |
@@ -2543,7 +2655,7 @@ tilegx_elf_size_dynamic_sections (bfd *output_bfd ATTRIBUTE_UNUSED, |
/* 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 = strlen (htab->dynamic_interpreter) + 1; |
s->contents = (unsigned char *) htab->dynamic_interpreter; |
@@ -2781,6 +2893,125 @@ tpoff (struct bfd_link_info *info, bfd_vma address) |
return (address - htab->tls_sec->vma); |
} |
+/* Copy SIZE bits from FROM to TO at address ADDR. */ |
+ |
+static void |
+tilegx_copy_bits (bfd_byte *addr, int from, int to, int size) |
+{ |
+ int i; |
+ for (i = 0; i < size; i++) |
+ { |
+ int from_byte = (from + i) / 8; |
+ int from_bit = (from + i) % 8; |
+ int to_byte = (to + i) / 8; |
+ int to_bit = (to + i) % 8; |
+ bfd_byte to_mask = 1 << to_bit; |
+ addr[to_byte] = (addr[to_byte] & ~to_mask) |
+ | ((addr[from_byte] >> from_bit << to_bit) & to_mask); |
+ } |
+} |
+ |
+/* Replace the MASK bits in ADDR with those in INSN, for the next |
+ TILEGX_BUNDLE_SIZE_IN_BYTES bytes. */ |
+ |
+static void |
+tilegx_replace_insn (bfd_byte *addr, const bfd_byte *mask, |
+ const bfd_byte *insn) |
+{ |
+ int i; |
+ for (i = 0; i < TILEGX_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, 0x3f |
+}; |
+ |
+/* 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, 0x3f |
+}; |
+ |
+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, 0x3c |
+}; |
+ |
+/* Mask to extract the bits corresponding to an instruction in a |
+ specific pipe of a bundle, minus the register operands. */ |
+static const bfd_byte insn_mask_X0_no_operand[] = { |
+ 0x00, 0x00, 0xfc, 0x7f, 0x00, 0x00, 0x00, 0x00 |
+}; |
+ |
+static const bfd_byte insn_mask_X1_no_operand[] = { |
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, 0x3f |
+}; |
+ |
+static const bfd_byte insn_mask_Y0_no_operand[] = { |
+ 0x00, 0x00, 0x0c, 0x78, 0x00, 0x00, 0x00, 0x00 |
+}; |
+ |
+static const bfd_byte insn_mask_Y1_no_operand[] = { |
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x06, 0x3c |
+}; |
+ |
+/* Various instructions synthesized to support tls references. */ |
+ |
+/* ld r0, r0 in the X1 pipe, used for tls ie. */ |
+static const bfd_byte insn_tls_ie_ld_X1[] = { |
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0xe8, 0x6a, 0x28 |
+}; |
+ |
+/* ld4s r0, r0 in the X1 pipe, used for tls ie. */ |
+static const bfd_byte insn_tls_ie_ld4s_X1[] = { |
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x98, 0x6a, 0x28 |
+}; |
+ |
+/* add r0, r0, tp in various pipes, used for tls ie. */ |
+static const bfd_byte insn_tls_ie_add_X0X1[] = { |
+ 0x00, 0x50, 0x0f, 0x50, 0x00, 0xa8, 0x07, 0x28 |
+}; |
+static const bfd_byte insn_tls_ie_add_Y0Y1[] = { |
+ 0x00, 0x50, 0x27, 0x2c, 0x00, 0xa8, 0x13, 0x9a |
+}; |
+ |
+/* addx r0, r0, tp in various pipes, used for tls ie. */ |
+static const bfd_byte insn_tls_ie_addx_X0X1[] = { |
+ 0x00, 0x50, 0x0b, 0x50, 0x00, 0xa8, 0x05, 0x28 |
+}; |
+static const bfd_byte insn_tls_ie_addx_Y0Y1[] = { |
+ 0x00, 0x50, 0x03, 0x2c, 0x00, 0xa8, 0x01, 0x9a |
+}; |
+ |
+/* move r0, r0 in various pipes, used for tls gd. */ |
+static const bfd_byte insn_tls_gd_add_X0X1[] = { |
+ 0x00, 0xf0, 0x07, 0x51, 0x00, 0xf8, 0x3b, 0x28 |
+}; |
+static const bfd_byte insn_tls_gd_add_Y0Y1[] = { |
+ 0x00, 0xf0, 0x0b, 0x54, 0x00, 0xf8, 0x05, 0xae |
+}; |
+ |
+static const bfd_byte *insn_move_X0X1 = insn_tls_gd_add_X0X1; |
+static const bfd_byte *insn_move_Y0Y1 = insn_tls_gd_add_Y0Y1; |
+ |
+static const bfd_byte *insn_add_X0X1 = insn_tls_ie_add_X0X1; |
+static const bfd_byte *insn_add_Y0Y1 = insn_tls_ie_add_Y0Y1; |
+ |
+static const bfd_byte *insn_addx_X0X1 = insn_tls_ie_addx_X0X1; |
+static const bfd_byte *insn_addx_Y0Y1 = insn_tls_ie_addx_Y0Y1; |
+ |
/* Relocate an TILEGX ELF section. |
The RELOCATE_SECTION function is called by the new ELF backend linker |
@@ -2845,6 +3076,7 @@ tilegx_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; |
@@ -2908,9 +3140,9 @@ tilegx_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; |
@@ -2927,20 +3159,203 @@ tilegx_elf_relocate_section (bfd *output_bfd, struct bfd_link_info *info, |
switch (r_type) |
{ |
+ case R_TILEGX_TLS_GD_CALL: |
+ case R_TILEGX_IMM8_X0_TLS_GD_ADD: |
+ case R_TILEGX_IMM8_Y0_TLS_GD_ADD: |
+ case R_TILEGX_IMM8_X1_TLS_GD_ADD: |
+ case R_TILEGX_IMM8_Y1_TLS_GD_ADD: |
+ case R_TILEGX_IMM8_X0_TLS_ADD: |
+ case R_TILEGX_IMM8_Y0_TLS_ADD: |
+ case R_TILEGX_IMM8_X1_TLS_ADD: |
+ case R_TILEGX_IMM8_Y1_TLS_ADD: |
+ tls_type = GOT_UNKNOWN; |
+ if (h == NULL && local_got_offsets) |
+ tls_type = |
+ _bfd_tilegx_elf_local_got_tls_type (input_bfd) [r_symndx]; |
+ else if (h != NULL) |
+ tls_type = tilegx_elf_hash_entry(h)->tls_type; |
+ |
+ is_tls_iele = (! info->shared || tls_type == GOT_TLS_IE); |
+ is_tls_le = is_tls_iele && (!input_section->sec_flg0 |
+ && !info->shared |
+ && (h == NULL || h->dynindx == -1)); |
+ |
+ if (r_type == R_TILEGX_TLS_GD_CALL) |
+ { |
+ if (is_tls_le) |
+ { |
+ /* GD -> LE */ |
+ tilegx_replace_insn (contents + rel->r_offset, |
+ insn_mask_X1, insn_move_X0X1); |
+ continue; |
+ } |
+ else if (is_tls_iele) |
+ { |
+ /* GD -> IE */ |
+ if (ABI_64_P (output_bfd)) |
+ tilegx_replace_insn (contents + rel->r_offset, |
+ insn_mask_X1, insn_tls_ie_ld_X1); |
+ else |
+ tilegx_replace_insn (contents + rel->r_offset, |
+ insn_mask_X1, insn_tls_ie_ld4s_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_TILEGX_JUMPOFF_X1_PLT; |
+ howto = tilegx_elf_howto_table + r_type; |
+ } |
+ else if (r_type == R_TILEGX_IMM8_X0_TLS_ADD |
+ || r_type == R_TILEGX_IMM8_X1_TLS_ADD |
+ || r_type == R_TILEGX_IMM8_Y0_TLS_ADD |
+ || r_type == R_TILEGX_IMM8_Y1_TLS_ADD) |
+ { |
+ bfd_boolean is_pipe0 = |
+ (r_type == R_TILEGX_IMM8_X0_TLS_ADD |
+ || r_type == R_TILEGX_IMM8_Y0_TLS_ADD); |
+ bfd_boolean is_X0X1 = |
+ (r_type == R_TILEGX_IMM8_X0_TLS_ADD |
+ || r_type == R_TILEGX_IMM8_X1_TLS_ADD); |
+ int dest_begin = is_pipe0 ? 0 : 31; |
+ int src_begin; |
+ const bfd_byte *insn; |
+ const bfd_byte *mask = NULL; |
+ |
+ if (is_tls_le) |
+ { |
+ /* 1. copy dest operand into the first source operand. |
+ 2. change the opcode to "move". */ |
+ src_begin = is_pipe0 ? 6 : 37; |
+ insn = is_X0X1 ? insn_move_X0X1 : insn_move_Y0Y1; |
+ |
+ switch (r_type) |
+ { |
+ case R_TILEGX_IMM8_X0_TLS_ADD: |
+ mask = insn_mask_X0_no_dest_no_srca; |
+ break; |
+ case R_TILEGX_IMM8_X1_TLS_ADD: |
+ mask = insn_mask_X1_no_dest_no_srca; |
+ break; |
+ case R_TILEGX_IMM8_Y0_TLS_ADD: |
+ mask = insn_mask_Y0_no_dest_no_srca; |
+ break; |
+ case R_TILEGX_IMM8_Y1_TLS_ADD: |
+ mask = insn_mask_Y1_no_dest_no_srca; |
+ break; |
+ } |
+ } |
+ else |
+ { |
+ /* 1. copy dest operand into the second source operand. |
+ 2. change the opcode to "add". */ |
+ src_begin = is_pipe0 ? 12 : 43; |
+ if (ABI_64_P (output_bfd)) |
+ insn = is_X0X1 ? insn_add_X0X1 : insn_add_Y0Y1; |
+ else |
+ insn = is_X0X1 ? insn_addx_X0X1 : insn_addx_Y0Y1; |
+ |
+ switch (r_type) |
+ { |
+ case R_TILEGX_IMM8_X0_TLS_ADD: |
+ mask = insn_mask_X0_no_operand; |
+ break; |
+ case R_TILEGX_IMM8_X1_TLS_ADD: |
+ mask = insn_mask_X1_no_operand; |
+ break; |
+ case R_TILEGX_IMM8_Y0_TLS_ADD: |
+ mask = insn_mask_Y0_no_operand; |
+ break; |
+ case R_TILEGX_IMM8_Y1_TLS_ADD: |
+ mask = insn_mask_Y1_no_operand; |
+ break; |
+ } |
+ } |
+ |
+ tilegx_copy_bits (contents + rel->r_offset, dest_begin, |
+ src_begin, 6); |
+ tilegx_replace_insn (contents + rel->r_offset, mask, insn); |
+ |
+ continue; |
+ } |
+ else |
+ { |
+ const bfd_byte *mask = NULL; |
+ const bfd_byte *add_insn = NULL; |
+ bfd_boolean is_64bit = ABI_64_P (output_bfd); |
+ |
+ switch (r_type) |
+ { |
+ case R_TILEGX_IMM8_X0_TLS_GD_ADD: |
+ add_insn = is_tls_iele |
+ ? (is_64bit ? insn_tls_ie_add_X0X1 : insn_tls_ie_addx_X0X1) |
+ : insn_tls_gd_add_X0X1; |
+ mask = insn_mask_X0_no_dest_no_srca; |
+ break; |
+ case R_TILEGX_IMM8_X1_TLS_GD_ADD: |
+ add_insn = is_tls_iele |
+ ? (is_64bit ? insn_tls_ie_add_X0X1 : insn_tls_ie_addx_X0X1) |
+ : insn_tls_gd_add_X0X1; |
+ mask = insn_mask_X1_no_dest_no_srca; |
+ break; |
+ case R_TILEGX_IMM8_Y0_TLS_GD_ADD: |
+ add_insn = is_tls_iele |
+ ? (is_64bit ? insn_tls_ie_add_Y0Y1 : insn_tls_ie_addx_Y0Y1) |
+ : insn_tls_gd_add_Y0Y1; |
+ mask = insn_mask_Y0_no_dest_no_srca; |
+ break; |
+ case R_TILEGX_IMM8_Y1_TLS_GD_ADD: |
+ add_insn = is_tls_iele |
+ ? (is_64bit ? insn_tls_ie_add_Y0Y1 : insn_tls_ie_addx_Y0Y1) |
+ : insn_tls_gd_add_Y0Y1; |
+ mask = insn_mask_Y1_no_dest_no_srca; |
+ break; |
+ } |
+ |
+ tilegx_replace_insn (contents + rel->r_offset, mask, add_insn); |
+ |
+ continue; |
+ } |
+ break; |
+ case R_TILEGX_TLS_IE_LOAD: |
+ if (!input_section->sec_flg0 |
+ && !info->shared |
+ && (h == NULL || h->dynindx == -1)) |
+ { |
+ /* IE -> LE */ |
+ tilegx_replace_insn (contents + rel->r_offset, |
+ insn_mask_X1_no_dest_no_srca, |
+ insn_move_X0X1); |
+ } |
+ else |
+ { |
+ /* IE -> IE */ |
+ if (ABI_64_P (output_bfd)) |
+ tilegx_replace_insn (contents + rel->r_offset, |
+ insn_mask_X1_no_dest_no_srca, |
+ insn_tls_ie_ld_X1); |
+ else |
+ tilegx_replace_insn (contents + rel->r_offset, |
+ insn_mask_X1_no_dest_no_srca, |
+ insn_tls_ie_ld4s_X1); |
+ } |
+ continue; |
+ break; |
+ default: |
+ break; |
+ } |
+ |
+ switch (r_type) |
+ { |
case R_TILEGX_IMM16_X0_HW0_GOT: |
case R_TILEGX_IMM16_X1_HW0_GOT: |
- case R_TILEGX_IMM16_X0_HW1_GOT: |
- case R_TILEGX_IMM16_X1_HW1_GOT: |
- case R_TILEGX_IMM16_X0_HW2_GOT: |
- case R_TILEGX_IMM16_X1_HW2_GOT: |
- case R_TILEGX_IMM16_X0_HW3_GOT: |
- case R_TILEGX_IMM16_X1_HW3_GOT: |
case R_TILEGX_IMM16_X0_HW0_LAST_GOT: |
case R_TILEGX_IMM16_X1_HW0_LAST_GOT: |
case R_TILEGX_IMM16_X0_HW1_LAST_GOT: |
case R_TILEGX_IMM16_X1_HW1_LAST_GOT: |
- case R_TILEGX_IMM16_X0_HW2_LAST_GOT: |
- case R_TILEGX_IMM16_X1_HW2_LAST_GOT: |
/* Relocation is to the entry for this symbol in the global |
offset table. */ |
if (htab->elf.sgot == NULL) |
@@ -3248,92 +3663,83 @@ tilegx_elf_relocate_section (bfd *output_bfd, struct bfd_link_info *info, |
} |
break; |
+ case R_TILEGX_IMM16_X0_HW0_TLS_LE: |
+ case R_TILEGX_IMM16_X1_HW0_TLS_LE: |
+ case R_TILEGX_IMM16_X0_HW0_LAST_TLS_LE: |
+ case R_TILEGX_IMM16_X1_HW0_LAST_TLS_LE: |
+ case R_TILEGX_IMM16_X0_HW1_LAST_TLS_LE: |
+ case R_TILEGX_IMM16_X1_HW1_LAST_TLS_LE: |
+ 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 = TILEGX_ELF_R_INFO (htab, NULL, 0, r_type); |
+ outrel.r_addend = relocation - dtpoff_base (info) |
+ + rel->r_addend; |
+ } |
+ |
+ tilegx_elf_append_rela (output_bfd, sreloc, &outrel); |
+ continue; |
+ } |
+ relocation = tpoff (info, relocation); |
+ break; |
+ |
case R_TILEGX_IMM16_X0_HW0_TLS_GD: |
case R_TILEGX_IMM16_X1_HW0_TLS_GD: |
- case R_TILEGX_IMM16_X0_HW1_TLS_GD: |
- case R_TILEGX_IMM16_X1_HW1_TLS_GD: |
- case R_TILEGX_IMM16_X0_HW2_TLS_GD: |
- case R_TILEGX_IMM16_X1_HW2_TLS_GD: |
- case R_TILEGX_IMM16_X0_HW3_TLS_GD: |
- case R_TILEGX_IMM16_X1_HW3_TLS_GD: |
case R_TILEGX_IMM16_X0_HW0_LAST_TLS_GD: |
case R_TILEGX_IMM16_X1_HW0_LAST_TLS_GD: |
case R_TILEGX_IMM16_X0_HW1_LAST_TLS_GD: |
case R_TILEGX_IMM16_X1_HW1_LAST_TLS_GD: |
- case R_TILEGX_IMM16_X0_HW2_LAST_TLS_GD: |
- case R_TILEGX_IMM16_X1_HW2_LAST_TLS_GD: |
- tls_type = GOT_TLS_GD; |
- goto have_tls_reference; |
- |
case R_TILEGX_IMM16_X0_HW0_TLS_IE: |
case R_TILEGX_IMM16_X1_HW0_TLS_IE: |
- case R_TILEGX_IMM16_X0_HW1_TLS_IE: |
- case R_TILEGX_IMM16_X1_HW1_TLS_IE: |
- case R_TILEGX_IMM16_X0_HW2_TLS_IE: |
- case R_TILEGX_IMM16_X1_HW2_TLS_IE: |
- case R_TILEGX_IMM16_X0_HW3_TLS_IE: |
- case R_TILEGX_IMM16_X1_HW3_TLS_IE: |
case R_TILEGX_IMM16_X0_HW0_LAST_TLS_IE: |
case R_TILEGX_IMM16_X1_HW0_LAST_TLS_IE: |
case R_TILEGX_IMM16_X0_HW1_LAST_TLS_IE: |
case R_TILEGX_IMM16_X1_HW1_LAST_TLS_IE: |
- case R_TILEGX_IMM16_X0_HW2_LAST_TLS_IE: |
- case R_TILEGX_IMM16_X1_HW2_LAST_TLS_IE: |
- tls_type = GOT_TLS_IE; |
- /* Fall through. */ |
- |
- have_tls_reference: |
+ r_type = tilegx_elf_tls_transition (info, r_type, h == NULL, |
+ input_section->sec_flg0); |
+ tls_type = GOT_UNKNOWN; |
if (h == NULL && local_got_offsets) |
- tls_type = _bfd_tilegx_elf_local_got_tls_type (input_bfd) [r_symndx]; |
+ tls_type = |
+ _bfd_tilegx_elf_local_got_tls_type (input_bfd) [r_symndx]; |
else if (h != NULL) |
- tls_type = tilegx_elf_hash_entry(h)->tls_type; |
+ { |
+ tls_type = tilegx_elf_hash_entry(h)->tls_type; |
+ if (!info->shared && h->dynindx == -1 && tls_type == GOT_TLS_IE) |
+ r_type = (!input_section->sec_flg0 |
+ ? tilegx_tls_translate_to_le (r_type) |
+ : tilegx_tls_translate_to_ie (r_type)); |
+ } |
if (tls_type == GOT_TLS_IE) |
- switch (r_type) |
- { |
- case R_TILEGX_IMM16_X0_HW0_TLS_GD: |
- r_type = R_TILEGX_IMM16_X0_HW0_TLS_IE; |
- break; |
- case R_TILEGX_IMM16_X1_HW0_TLS_GD: |
- r_type = R_TILEGX_IMM16_X1_HW0_TLS_IE; |
- break; |
- case R_TILEGX_IMM16_X0_HW1_TLS_GD: |
- r_type = R_TILEGX_IMM16_X0_HW1_TLS_IE; |
- break; |
- case R_TILEGX_IMM16_X1_HW1_TLS_GD: |
- r_type = R_TILEGX_IMM16_X1_HW1_TLS_IE; |
- break; |
- case R_TILEGX_IMM16_X0_HW2_TLS_GD: |
- r_type = R_TILEGX_IMM16_X0_HW2_TLS_IE; |
- break; |
- case R_TILEGX_IMM16_X1_HW2_TLS_GD: |
- r_type = R_TILEGX_IMM16_X1_HW2_TLS_IE; |
- break; |
- case R_TILEGX_IMM16_X0_HW3_TLS_GD: |
- r_type = R_TILEGX_IMM16_X0_HW3_TLS_IE; |
- break; |
- case R_TILEGX_IMM16_X1_HW3_TLS_GD: |
- r_type = R_TILEGX_IMM16_X1_HW3_TLS_IE; |
- break; |
- case R_TILEGX_IMM16_X0_HW0_LAST_TLS_GD: |
- r_type = R_TILEGX_IMM16_X0_HW0_LAST_TLS_IE; |
- break; |
- case R_TILEGX_IMM16_X1_HW0_LAST_TLS_GD: |
- r_type = R_TILEGX_IMM16_X1_HW0_LAST_TLS_IE; |
- break; |
- case R_TILEGX_IMM16_X0_HW1_LAST_TLS_GD: |
- r_type = R_TILEGX_IMM16_X0_HW1_LAST_TLS_IE; |
- break; |
- case R_TILEGX_IMM16_X1_HW1_LAST_TLS_GD: |
- r_type = R_TILEGX_IMM16_X1_HW1_LAST_TLS_IE; |
- break; |
- case R_TILEGX_IMM16_X0_HW2_LAST_TLS_GD: |
- r_type = R_TILEGX_IMM16_X0_HW2_LAST_TLS_IE; |
- break; |
- case R_TILEGX_IMM16_X1_HW2_LAST_TLS_GD: |
- r_type = R_TILEGX_IMM16_X1_HW2_LAST_TLS_IE; |
- break; |
- } |
+ r_type = tilegx_tls_translate_to_ie (r_type); |
+ |
+ if (r_type == R_TILEGX_IMM16_X0_HW0_TLS_LE |
+ || r_type == R_TILEGX_IMM16_X1_HW0_TLS_LE |
+ || r_type == R_TILEGX_IMM16_X0_HW0_LAST_TLS_LE |
+ || r_type == R_TILEGX_IMM16_X1_HW0_LAST_TLS_LE |
+ || r_type == R_TILEGX_IMM16_X0_HW1_LAST_TLS_LE |
+ || r_type == R_TILEGX_IMM16_X1_HW1_LAST_TLS_LE) |
+ { |
+ relocation = tpoff (info, relocation); |
+ break; |
+ } |
if (h != NULL) |
{ |
@@ -3386,18 +3792,10 @@ tilegx_elf_relocate_section (bfd *output_bfd, struct bfd_link_info *info, |
{ |
case R_TILEGX_IMM16_X0_HW0_TLS_IE: |
case R_TILEGX_IMM16_X1_HW0_TLS_IE: |
- case R_TILEGX_IMM16_X0_HW1_TLS_IE: |
- case R_TILEGX_IMM16_X1_HW1_TLS_IE: |
- case R_TILEGX_IMM16_X0_HW2_TLS_IE: |
- case R_TILEGX_IMM16_X1_HW2_TLS_IE: |
- case R_TILEGX_IMM16_X0_HW3_TLS_IE: |
- case R_TILEGX_IMM16_X1_HW3_TLS_IE: |
case R_TILEGX_IMM16_X0_HW0_LAST_TLS_IE: |
case R_TILEGX_IMM16_X1_HW0_LAST_TLS_IE: |
case R_TILEGX_IMM16_X0_HW1_LAST_TLS_IE: |
case R_TILEGX_IMM16_X1_HW1_LAST_TLS_IE: |
- case R_TILEGX_IMM16_X0_HW2_LAST_TLS_IE: |
- case R_TILEGX_IMM16_X1_HW2_LAST_TLS_IE: |
if (need_relocs) { |
TILEGX_ELF_PUT_WORD (htab, output_bfd, 0, |
htab->elf.sgot->contents + off); |
@@ -3418,18 +3816,10 @@ tilegx_elf_relocate_section (bfd *output_bfd, struct bfd_link_info *info, |
case R_TILEGX_IMM16_X0_HW0_TLS_GD: |
case R_TILEGX_IMM16_X1_HW0_TLS_GD: |
- case R_TILEGX_IMM16_X0_HW1_TLS_GD: |
- case R_TILEGX_IMM16_X1_HW1_TLS_GD: |
- case R_TILEGX_IMM16_X0_HW2_TLS_GD: |
- case R_TILEGX_IMM16_X1_HW2_TLS_GD: |
- case R_TILEGX_IMM16_X0_HW3_TLS_GD: |
- case R_TILEGX_IMM16_X1_HW3_TLS_GD: |
case R_TILEGX_IMM16_X0_HW0_LAST_TLS_GD: |
case R_TILEGX_IMM16_X1_HW0_LAST_TLS_GD: |
case R_TILEGX_IMM16_X0_HW1_LAST_TLS_GD: |
case R_TILEGX_IMM16_X1_HW1_LAST_TLS_GD: |
- case R_TILEGX_IMM16_X0_HW2_LAST_TLS_GD: |
- case R_TILEGX_IMM16_X1_HW2_LAST_TLS_GD: |
if (need_relocs) { |
outrel.r_offset = (htab->elf.sgot->output_section->vma |
+ htab->elf.sgot->output_offset + off); |
@@ -3726,8 +4116,7 @@ tilegx_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 |
@@ -3806,14 +4195,14 @@ tilegx_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 = tilegx_finish_dyn (output_bfd, info, dynobj, sdyn, splt); |