Improve TLS support on TILE-Gx/TILEPro:

- Add support for TLS LE references.
- Support linker optimization of TLS references.
- Delete relocations of GOT/tp relative offsets beyond 32-bits.

This brings binutils in line with the support expected in gcc 4.7, for
TILE-Gx/TILEPro.

bfd/
	* reloc.c: Add BFD_RELOC_TILEPRO_TLS_GD_CALL,
	BFD_RELOC_TILEPRO_IMM8_X0_TLS_GD_ADD,
	BFD_RELOC_TILEPRO_IMM8_X1_TLS_GD_ADD,
	BFD_RELOC_TILEPRO_IMM8_Y0_TLS_GD_ADD,
	BFD_RELOC_TILEPRO_IMM8_Y1_TLS_GD_ADD,
	BFD_RELOC_TILEPRO_TLS_IE_LOAD, BFD_RELOC_TILEPRO_IMM16_X0_TLS_LE,
	BFD_RELOC_TILEPRO_IMM16_X1_TLS_LE,
	BFD_RELOC_TILEPRO_IMM16_X0_TLS_LE_LO,
	BFD_RELOC_TILEPRO_IMM16_X1_TLS_LE_LO,
	BFD_RELOC_TILEPRO_IMM16_X0_TLS_LE_HI,
	BFD_RELOC_TILEPRO_IMM16_X1_TLS_LE_HI,
	BFD_RELOC_TILEPRO_IMM16_X0_TLS_LE_HA,
	BFD_RELOC_TILEPRO_IMM16_X1_TLS_LE_HA,
	BFD_RELOC_TILEGX_IMM16_X0_HW0_TLS_LE,
	BFD_RELOC_TILEGX_IMM16_X1_HW0_TLS_LE,
	BFD_RELOC_TILEGX_IMM16_X0_HW0_LAST_TLS_LE,
	BFD_RELOC_TILEGX_IMM16_X1_HW0_LAST_TLS_LE,
	BFD_RELOC_TILEGX_IMM16_X0_HW1_LAST_TLS_LE,
	BFD_RELOC_TILEGX_IMM16_X1_HW1_LAST_TLS_LE,
	BFD_RELOC_TILEGX_TLS_GD_CALL, BFD_RELOC_TILEGX_IMM8_X0_TLS_GD_ADD,
	BFD_RELOC_TILEGX_IMM8_X1_TLS_GD_ADD,
	BFD_RELOC_TILEGX_IMM8_Y0_TLS_GD_ADD,
	BFD_RELOC_TILEGX_IMM8_Y1_TLS_GD_ADD, BFD_RELOC_TILEGX_TLS_IE_LOAD,
	BFD_RELOC_TILEGX_IMM8_X0_TLS_ADD,
	BFD_RELOC_TILEGX_IMM8_X1_TLS_ADD,
	BFD_RELOC_TILEGX_IMM8_Y0_TLS_ADD, BFD_RELOC_TILEGX_IMM8_Y1_TLS_ADD.
	Delete BFD_RELOC_TILEGX_IMM16_X0_HW1_GOT,
	BFD_RELOC_TILEGX_IMM16_X1_HW1_GOT,
	BFD_RELOC_TILEGX_IMM16_X0_HW2_GOT,
	BFD_RELOC_TILEGX_IMM16_X1_HW2_GOT,
	BFD_RELOC_TILEGX_IMM16_X0_HW3_GOT,
	BFD_RELOC_TILEGX_IMM16_X1_HW3_GOT,
	BFD_RELOC_TILEGX_IMM16_X0_HW2_LAST_GOT,
	BFD_RELOC_TILEGX_IMM16_X1_HW2_LAST_GOT,
	BFD_RELOC_TILEGX_IMM16_X0_HW1_TLS_GD,
	BFD_RELOC_TILEGX_IMM16_X1_HW1_TLS_GD,
	BFD_RELOC_TILEGX_IMM16_X0_HW2_TLS_GD,
	BFD_RELOC_TILEGX_IMM16_X1_HW2_TLS_GD,
	BFD_RELOC_TILEGX_IMM16_X0_HW3_TLS_GD,
	BFD_RELOC_TILEGX_IMM16_X1_HW3_TLS_GD,
	BFD_RELOC_TILEGX_IMM16_X0_HW2_LAST_TLS_GD,
	BFD_RELOC_TILEGX_IMM16_X1_HW2_LAST_TLS_GD,
	BFD_RELOC_TILEGX_IMM16_X0_HW1_TLS_IE,
	BFD_RELOC_TILEGX_IMM16_X1_HW1_TLS_IE,
	BFD_RELOC_TILEGX_IMM16_X0_HW2_TLS_IE,
	BFD_RELOC_TILEGX_IMM16_X1_HW2_TLS_IE,
	BFD_RELOC_TILEGX_IMM16_X0_HW3_TLS_IE,
	BFD_RELOC_TILEGX_IMM16_X1_HW3_TLS_IE,
	BFD_RELOC_TILEGX_IMM16_X0_HW2_LAST_TLS_IE,
	BFD_RELOC_TILEGX_IMM16_X1_HW2_LAST_TLS_IE.
	* elf32-tilepro.c (tilepro_elf_howto_table): Update tilepro
	relocations.
	(tilepro_reloc_map): Ditto.
	(tilepro_info_to_howto_rela): Ditto.
	(reloc_to_create_func): Ditto.
	(tilepro_tls_translate_to_le): New.
	(tilepro_tls_translate_to_ie): New.
	(tilepro_elf_tls_transition): New.
	(tilepro_elf_check_relocs): Handle new tls relocations.
	(tilepro_elf_gc_sweep_hook): Ditto.
	(allocate_dynrelocs): Ditto.
	(tilepro_elf_relocate_section): Ditto.
	(tilepro_replace_insn): New.
	(insn_mask_X1): New.
	(insn_mask_X0_no_dest_no_srca): New
	(insn_mask_X1_no_dest_no_srca): New
	(insn_mask_Y0_no_dest_no_srca): New
	(insn_mask_Y1_no_dest_no_srca): New
	(srca_mask_X0): New
	(srca_mask_X1): New
	(insn_tls_le_move_X1): New
	(insn_tls_le_move_zero_X0X1): New
	(insn_tls_ie_lw_X1): New
	(insn_tls_ie_add_X0X1): New
	(insn_tls_ie_add_Y0Y1): New
	(insn_tls_gd_add_X0X1): New
	(insn_tls_gd_add_Y0Y1): New
	* elfxx-tilegx.c (tilegx_elf_howto_table): Update tilegx
	relocations.
	(tilegx_reloc_map): Ditto.
	(tilegx_info_to_howto_rela): Ditto.
	(reloc_to_create_func): Ditto.
	(tilegx_elf_link_hash_table): New field disable_le_transition.
	(tilegx_tls_translate_to_le): New.
	(tilegx_tls_translate_to_ie): New.
	(tilegx_elf_tls_transition): New.
	(tilegx_elf_check_relocs): Handle new tls relocations.
	(tilegx_elf_gc_sweep_hook): Ditto.
	(allocate_dynrelocs): Ditto.
	(tilegx_elf_relocate_section): Ditto.
	(tilegx_copy_bits): New.
	(tilegx_replace_insn): New.
	(insn_mask_X1): New.
	(insn_mask_X0_no_dest_no_srca): New.
	(insn_mask_X1_no_dest_no_srca): New.
	(insn_mask_Y0_no_dest_no_srca): New.
	(insn_mask_Y1_no_dest_no_srca): New.
	(insn_mask_X0_no_operand): New.
	(insn_mask_X1_no_operand): New.
	(insn_mask_Y0_no_operand): New.
	(insn_mask_Y1_no_operand): New.
	(insn_tls_ie_ld_X1): New.
	(insn_tls_ie_ld4s_X1): New.
	(insn_tls_ie_add_X0X1): New.
	(insn_tls_ie_add_Y0Y1): New.
	(insn_tls_ie_addx_X0X1): New.
	(insn_tls_ie_addx_Y0Y1): New.
	(insn_tls_gd_add_X0X1): New.
	(insn_tls_gd_add_Y0Y1): New.
	(insn_move_X0X1): New.
	(insn_move_Y0Y1): New.
	(insn_add_X0X1): New.
	(insn_add_Y0Y1): New.
	(insn_addx_X0X1): New.
	(insn_addx_Y0Y1): New.
	* libbfd.h: Regenerate.
	* bfd-in2.h: Regenerate.

gas/
	* tc-tilepro.c (O_tls_le): Define operator.
	(O_tls_le_lo16): Ditto.
	(O_tls_le_hi16): Ditto.
	(O_tls_le_ha16): Ditto.
	(O_tls_gd_call): Ditto.
	(O_tls_gd_add): Ditto.
	(O_tls_ie_load): Ditto.
	(md_begin): Delete old operators; handle new operators.
	(emit_tilepro_instruction): Ditto.
	(md_apply_fix): Ditto.
	* tc-tilegx.c (O_hw1_got): Delete operator.
	(O_hw2_got): Ditto.
	(O_hw3_got): Ditto.
	(O_hw2_last_got): Ditto.
	(O_hw1_tls_gd): Ditto.
	(O_hw2_tls_gd): Ditto.
	(O_hw3_tls_gd): Ditto.
	(O_hw2_last_tls_gd): Ditto.
	(O_hw1_tls_ie): Ditto.
	(O_hw2_tls_ie): Ditto.
	(O_hw3_tls_ie): Ditto.
	(O_hw2_last_tls_ie): Ditto.
	(O_hw0_tls_le): Define operator.
	(O_hw0_last_tls_le): Ditto.
	(O_hw1_last_tls_le): Ditto.
	(O_tls_gd_call): Ditto.
	(O_tls_gd_add): Ditto.
	(O_tls_ie_load): Ditto.
	(O_tls_add): Ditto.
	(md_begin): Delete old operators; handle new operators.
	(emit_tilegx_instruction): Ditto.
	(md_apply_fix): Ditto.
	* doc/c-tilegx.texi: Delete old operators; document new operators.
	* doc/c-tilepro.texi: Ditto.

include/elf/
	* tilegx.h (R_TILEGX_IMM16_X0_HW1_GOT): Delete.
	(R_TILEGX_IMM16_X1_HW1_GOT): Ditto.
	(R_TILEGX_IMM16_X0_HW2_GOT): Ditto.
	(R_TILEGX_IMM16_X1_HW2_GOT): Ditto.
	(R_TILEGX_IMM16_X0_HW3_GOT): Ditto.
	(R_TILEGX_IMM16_X1_HW3_GOT): Ditto.
	(R_TILEGX_IMM16_X0_HW2_LAST_GOT): Ditto.
	(R_TILEGX_IMM16_X1_HW2_LAST_GOT): Ditto.
	(R_TILEGX_IMM16_X0_HW1_TLS_GD): Ditto.
	(R_TILEGX_IMM16_X1_HW1_TLS_GD): Ditto.
	(R_TILEGX_IMM16_X0_HW2_TLS_GD): Ditto.
	(R_TILEGX_IMM16_X1_HW2_TLS_GD): Ditto.
	(R_TILEGX_IMM16_X0_HW3_TLS_GD): Ditto.
	(R_TILEGX_IMM16_X1_HW3_TLS_GD): Ditto.
	(R_TILEGX_IMM16_X0_HW2_LAST_TLS_GD): Ditto.
	(R_TILEGX_IMM16_X1_HW2_LAST_TLS_GD): Ditto.
	(R_TILEGX_IMM16_X0_HW1_TLS_IE): Ditto.
	(R_TILEGX_IMM16_X1_HW1_TLS_IE): Ditto.
	(R_TILEGX_IMM16_X0_HW2_TLS_IE): Ditto.
	(R_TILEGX_IMM16_X1_HW2_TLS_IE): Ditto.
	(R_TILEGX_IMM16_X0_HW3_TLS_IE): Ditto.
	(R_TILEGX_IMM16_X1_HW3_TLS_IE): Ditto.
	(R_TILEGX_IMM16_X0_HW2_LAST_TLS_IE): Ditto.
	(R_TILEGX_IMM16_X1_HW2_LAST_TLS_IE): Ditto.
	(R_TILEGX_IMM16_X0_HW0_TLS_LE): New relocation.
	(R_TILEGX_IMM16_X1_HW0_TLS_LE): Ditto.
	(R_TILEGX_IMM16_X0_HW0_LAST_TLS_LE): Ditto.
	(R_TILEGX_IMM16_X1_HW0_LAST_TLS_LE): Ditto.
	(R_TILEGX_IMM16_X0_HW1_LAST_TLS_LE): Ditto.
	(R_TILEGX_IMM16_X1_HW1_LAST_TLS_LE): Ditto.
	(R_TILEGX_TLS_GD_CALL): Ditto.
	(R_TILEGX_IMM8_X0_TLS_GD_ADD): Ditto.
	(R_TILEGX_IMM8_X1_TLS_GD_ADD): Ditto.
	(R_TILEGX_IMM8_Y0_TLS_GD_ADD): Ditto.
	(R_TILEGX_IMM8_Y1_TLS_GD_ADD): Ditto.
	(R_TILEGX_TLS_IE_LOAD): Ditto.
	(R_TILEGX_IMM8_X0_TLS_ADD): Ditto.
	(R_TILEGX_IMM8_X1_TLS_ADD): Ditto.
	(R_TILEGX_IMM8_Y0_TLS_ADD): Ditto.
	(R_TILEGX_IMM8_Y1_TLS_ADD): Ditto.
	* tilepro.h (R_TILEPRO_TLS_GD_CALL): New relocation.
	(R_TILEPRO_IMM8_X0_TLS_GD_ADD): Ditto.
	(R_TILEPRO_IMM8_X1_TLS_GD_ADD): Ditto.
	(R_TILEPRO_IMM8_Y0_TLS_GD_ADD): Ditto.
	(R_TILEPRO_IMM8_Y1_TLS_GD_ADD): Ditto.
	(R_TILEPRO_TLS_IE_LOAD): Ditto.
	(R_TILEPRO_IMM16_X0_TLS_LE): Ditto.
	(R_TILEPRO_IMM16_X1_TLS_LE): Ditto.
	(R_TILEPRO_IMM16_X0_TLS_LE_LO): Ditto.
	(R_TILEPRO_IMM16_X1_TLS_LE_LO): Ditto.
	(R_TILEPRO_IMM16_X0_TLS_LE_HI): Ditto.
	(R_TILEPRO_IMM16_X1_TLS_LE_HI): Ditto.
	(R_TILEPRO_IMM16_X0_TLS_LE_HA): Ditto.
	(R_TILEPRO_IMM16_X1_TLS_LE_HA): Ditto.

include/opcode/
	* tilegx.h (tilegx_mnemonic): Add TILEGX_OPC_LD4S_TLS,
	TILEGX_OPC_LD_TLS.
	* tilepro.h (tilepro_mnemonic): Add TILEPRO_OPC_LW_TLS,
	TILEPRO_OPC_LW_TLS_SN.

opcodes/
	* tilegx-opc.c: Handle TILEGX_OPC_LD4S_TLS and TILEGX_OPC_LD_TLS.
	* tilepro-opc.c: Handle TILEPRO_OPC_LW_TLS and
	TILEPRO_OPC_LW_TLS_SN.
This commit is contained in:
Walter Lee
2012-02-25 22:24:21 +00:00
parent 5414dbefea
commit 6f7be9592d
20 changed files with 2894 additions and 1560 deletions

View File

@@ -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])))
@@ -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;
@@ -2040,7 +2238,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;
@@ -2467,6 +2672,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 +2817,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;
@@ -2611,6 +2898,118 @@ tilepro_elf_relocate_section (bfd *output_bfd, struct bfd_link_info *info,
name = bfd_section_name (input_bfd, sec);
}
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:
@@ -2908,6 +3307,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 +3354,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 +3362,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)
{