* ARM: Support for TLS relocations
@ 2005-03-26 12:16 Daniel Jacobowitz
2005-03-29 16:38 ` Richard Earnshaw
0 siblings, 1 reply; 3+ messages in thread
From: Daniel Jacobowitz @ 2005-03-26 12:16 UTC (permalink / raw)
To: binutils
This patch implements the ARM-documented TLS relocations, except for the
twelve-bit instruction relocations. The first version was implemented by
Phil, although I'm afraid he won't recognize much of it; mistakes all mine.
The implemented relocations are, for the assembler:
.word foo(tlsgd)
.word foo(tlsldm)
.word foo(tlsldo)
.word foo(gottpoff)
.word foo(tpoff)
They support trailing addends, e.g. a typical usage:
.word foo(tlsgd) + (. - .L2 + 8)
No linker relaxations are supported; the compiler's choice is final.
Dynamic relocations are avoided when unneeded, though.
Tested on arm-linux, including NPTL with appropriate gcc/glibc patches.
Is this OK for HEAD?
[Full disclosure - I actually tested a different version of this patch,
which used a different name for the IE32 relocation operator. After
changing it to gottpoff I've started a new test cycle which is running now.]
--
Daniel Jacobowitz
CodeSourcery, LLC
2005-03-25 Daniel Jacobowitz <dan@codesourcery.com>
Phil Blundell <philb@gnu.org>
* bfd-in2.h, libbfd.h: Regenerated.
* reloc.c: Add ARM TLS relocations.
* elf32-arm.c (elf32_arm_howto_table): Add dynamic TLS
relocations.
(elf32_arm_tls_gd32_howto, elf32_arm_tls_ldo32_howto)
(elf32_arm_tls_ldm32_howto, elf32_arm_tls_le32_howto)
(elf32_arm_tls_ie32_howto): New.
(elf32_arm_howto_from_type): Support TLS relocations.
(elf32_arm_reloc_map): Likewise.
(elf32_arm_reloc_type_lookup): Likewise.
(TCB_SIZE): Define.
(struct elf32_arm_obj_tdata): New.
(elf32_arm_tdata, elf32_arm_local_got_tls_type): Define.
(elf32_arm_mkobject): New function.
(struct elf32_arm_relocs_copied): Add pc_count.
(elf32_arm_hash_entry, GOT_UNKNOWN, GOT_NORMAL, GOT_TLS_GD)
(GOT_TLS_IE): Define.
(struct elf32_arm_link_hash_table): Add tls_ldm_got.
(elf32_arm_link_hash_newfunc): Initialize tls_type.
(elf32_arm_copy_indirect_symbol): Copy pc_count and tls_type.
(elf32_arm_link_hash_table_create): Initialize tls_ldm_got.
(dtpoff_base, tpoff): New functions.
(elf32_arm_final_link_relocate): Handle TLS relocations.
(IS_ARM_TLS_RELOC): Define.
(elf32_arm_relocate_section): Warn about TLS mismatches.
(elf32_arm_gc_sweep_hook): Handle TLS relocations and pc_count.
(elf32_arm_check_relocs): Detect invalid symbol indexes. Handle
TLS relocations and pc_count.
(elf32_arm_adjust_dynamic_symbol): Check non_got_ref.
(allocate_dynrelocs): Handle TLS. Bind REL32 relocs to local
calls.
(elf32_arm_size_dynamic_sections): Handle TLS.
(elf32_arm_finish_dynamic_symbol): Likewise.
(bfd_elf32_mkobject): Define.
2005-03-25 Daniel Jacobowitz <dan@codesourcery.com>
Phil Blundell <philb@gnu.org>
* config/tc-arm.c (arm_parse_reloc): Add TLS relocations.
(md_apply_fix3): Mark TLS symbols.
(tc_gen_reloc): Handle TLS relocations.
(arm_fix_adjustable): Ignore TLS relocations.
(s_arm_elf_cons): Support expressions after decorated symbols.
2005-03-25 Daniel Jacobowitz <dan@codesourcery.com>
* gas/arm/tls.s, gas/arm/tls.d: New files.
* gas/arm/arm.exp: Run TLS test.
2005-03-25 Daniel Jacobowitz <dan@codesourcery.com>
Phil Blundell <philb@gnu.org>
* elf/arm.h: Add TLS relocations.
2005-03-25 Daniel Jacobowitz <dan@codesourcery.com>
* ld-arm/tls-lib.s, ld-arm/tls-lib.d, ld-arm/tls-lib.r,
ld-arm/tls-app.s, ld-arm/tls-app.d, ld-arm/tls-app.r: New files.
* ld-arm/arm-lib.ld, ld-arm/arm-dyn.ld: Increase data segment
alignment.
* ld-arm/arm-elf.exp: Run TLS tests.
Index: binutils/bfd/bfd-in2.h
===================================================================
--- binutils.orig/bfd/bfd-in2.h 2005-03-25 11:15:11.809447416 -0500
+++ binutils/bfd/bfd-in2.h 2005-03-25 11:17:27.933909131 -0500
@@ -2688,6 +2688,14 @@ field in the instruction. */
BFD_RELOC_ARM_RELATIVE,
BFD_RELOC_ARM_GOTOFF,
BFD_RELOC_ARM_GOTPC,
+ BFD_RELOC_ARM_TLS_GD32,
+ BFD_RELOC_ARM_TLS_LDO32,
+ BFD_RELOC_ARM_TLS_LDM32,
+ BFD_RELOC_ARM_TLS_DTPOFF32,
+ BFD_RELOC_ARM_TLS_DTPMOD32,
+ BFD_RELOC_ARM_TLS_TPOFF32,
+ BFD_RELOC_ARM_TLS_IE32,
+ BFD_RELOC_ARM_TLS_LE32,
/* Pc-relative or absolute relocation depending on target. Used for
entries in .init_array sections. */
Index: binutils/bfd/libbfd.h
===================================================================
--- binutils.orig/bfd/libbfd.h 2005-03-25 11:15:11.809447416 -0500
+++ binutils/bfd/libbfd.h 2005-03-25 11:17:27.933909131 -0500
@@ -1177,6 +1177,14 @@ static const char *const bfd_reloc_code_
"BFD_RELOC_ARM_RELATIVE",
"BFD_RELOC_ARM_GOTOFF",
"BFD_RELOC_ARM_GOTPC",
+ "BFD_RELOC_ARM_TLS_GD32",
+ "BFD_RELOC_ARM_TLS_LDO32",
+ "BFD_RELOC_ARM_TLS_LDM32",
+ "BFD_RELOC_ARM_TLS_DTPOFF32",
+ "BFD_RELOC_ARM_TLS_DTPMOD32",
+ "BFD_RELOC_ARM_TLS_TPOFF32",
+ "BFD_RELOC_ARM_TLS_IE32",
+ "BFD_RELOC_ARM_TLS_LE32",
"BFD_RELOC_ARM_TARGET1",
"BFD_RELOC_ARM_ROSEGREL32",
"BFD_RELOC_ARM_SBREL32",
Index: binutils/bfd/reloc.c
===================================================================
--- binutils.orig/bfd/reloc.c 2005-03-25 11:15:11.809447416 -0500
+++ binutils/bfd/reloc.c 2005-03-25 11:17:27.935908652 -0500
@@ -2678,6 +2678,22 @@ ENUMX
BFD_RELOC_ARM_GOTOFF
ENUMX
BFD_RELOC_ARM_GOTPC
+ENUMX
+ BFD_RELOC_ARM_TLS_GD32
+ENUMX
+ BFD_RELOC_ARM_TLS_LDO32
+ENUMX
+ BFD_RELOC_ARM_TLS_LDM32
+ENUMX
+ BFD_RELOC_ARM_TLS_DTPOFF32
+ENUMX
+ BFD_RELOC_ARM_TLS_DTPMOD32
+ENUMX
+ BFD_RELOC_ARM_TLS_TPOFF32
+ENUMX
+ BFD_RELOC_ARM_TLS_IE32
+ENUMX
+ BFD_RELOC_ARM_TLS_LE32
ENUMDOC
These relocs are only used within the ARM assembler. They are not
(at present) written to any object files.
Index: binutils/gas/config/tc-arm.c
===================================================================
--- binutils.orig/gas/config/tc-arm.c 2005-03-25 11:17:24.678687612 -0500
+++ binutils/gas/config/tc-arm.c 2005-03-25 11:17:27.941907218 -0500
@@ -4873,6 +4873,11 @@ arm_parse_reloc (void)
MAP ("(target1)", BFD_RELOC_ARM_TARGET1),
MAP ("(sbrel)", BFD_RELOC_ARM_SBREL32),
MAP ("(target2)", BFD_RELOC_ARM_TARGET2),
+ MAP ("(tlsgd)", BFD_RELOC_ARM_TLS_GD32),
+ MAP ("(tlsldm)", BFD_RELOC_ARM_TLS_LDM32),
+ MAP ("(tlsldo)", BFD_RELOC_ARM_TLS_LDO32),
+ MAP ("(gottpoff)", BFD_RELOC_ARM_TLS_IE32),
+ MAP ("(tpoff)", BFD_RELOC_ARM_TLS_LE32),
{ NULL, 0, BFD_RELOC_UNUSED }
#undef MAP
};
@@ -12209,6 +12214,14 @@ md_apply_fix3 (fixS * fixP,
break;
#ifdef OBJ_ELF
+ case BFD_RELOC_ARM_TLS_GD32:
+ case BFD_RELOC_ARM_TLS_LE32:
+ case BFD_RELOC_ARM_TLS_IE32:
+ case BFD_RELOC_ARM_TLS_LDM32:
+ case BFD_RELOC_ARM_TLS_LDO32:
+ S_SET_THREAD_LOCAL (fixP->fx_addsy);
+ /* fall through */
+
case BFD_RELOC_ARM_GOT32:
case BFD_RELOC_ARM_GOTOFF:
case BFD_RELOC_ARM_TARGET2:
@@ -12532,6 +12545,18 @@ tc_gen_reloc (asection * section ATTRIBU
case BFD_RELOC_ARM_SBREL32:
case BFD_RELOC_ARM_PREL31:
case BFD_RELOC_ARM_TARGET2:
+ case BFD_RELOC_ARM_TLS_LE32:
+ case BFD_RELOC_ARM_TLS_LDO32:
+ code = fixp->fx_r_type;
+ break;
+
+ case BFD_RELOC_ARM_TLS_GD32:
+ case BFD_RELOC_ARM_TLS_IE32:
+ case BFD_RELOC_ARM_TLS_LDM32:
+ /* BFD will include the symbol's address in the addend.
+ But we don't want that, so subtract it out again here. */
+ if (!S_IS_COMMON (fixp->fx_addsy))
+ reloc->addend -= (*reloc->sym_ptr_ptr)->value;
code = fixp->fx_r_type;
break;
#endif
@@ -13828,6 +13853,11 @@ arm_fix_adjustable (fixS * fixP)
if (fixP->fx_r_type == BFD_RELOC_ARM_PLT32
|| fixP->fx_r_type == BFD_RELOC_ARM_GOT32
|| fixP->fx_r_type == BFD_RELOC_ARM_GOTOFF
+ || fixP->fx_r_type == BFD_RELOC_ARM_TLS_GD32
+ || fixP->fx_r_type == BFD_RELOC_ARM_TLS_LE32
+ || fixP->fx_r_type == BFD_RELOC_ARM_TLS_IE32
+ || fixP->fx_r_type == BFD_RELOC_ARM_TLS_LDM32
+ || fixP->fx_r_type == BFD_RELOC_ARM_TLS_LDO32
|| fixP->fx_r_type == BFD_RELOC_ARM_TARGET2)
return 0;
@@ -13883,8 +13913,12 @@ s_arm_elf_cons (int nbytes)
do
{
bfd_reloc_code_real_type reloc;
+ char *sym_start;
+ int sym_len;
+ sym_start = input_line_pointer;
expression (& exp);
+ sym_len = input_line_pointer - sym_start;
if (exp.X_op == O_symbol
&& * input_line_pointer == '('
@@ -13898,9 +13932,22 @@ s_arm_elf_cons (int nbytes)
howto->name, nbytes);
else
{
- char *p = frag_more ((int) nbytes);
+ char *p;
int offset = nbytes - size;
+ char *saved_buf = alloca (sym_len), *saved_input;
+
+ /* We've parsed an expression stopping at O_symbol. But there
+ may be more expression left now that we have parsed the
+ relocation marker. Parse it again. */
+ saved_input = input_line_pointer - sym_len;
+ memcpy (saved_buf, saved_input, sym_len);
+ memmove (saved_input, sym_start, sym_len);
+ input_line_pointer = saved_input;
+ expression (& exp);
+ memcpy (saved_input, saved_buf, sym_len);
+ assert (input_line_pointer >= saved_input + sym_len);
+ p = frag_more ((int) nbytes);
fix_new_exp (frag_now, p - frag_now->fr_literal + offset, size,
&exp, 0, reloc);
}
Index: binutils/include/elf/arm.h
===================================================================
--- binutils.orig/include/elf/arm.h 2005-03-25 11:15:11.829442638 -0500
+++ binutils/include/elf/arm.h 2005-03-25 11:17:27.941907218 -0500
@@ -114,6 +114,9 @@ START_RELOC_NUMBERS (elf_arm_reloc_type)
RELOC_NUMBER (R_ARM_THM_SWI8, 14)
RELOC_NUMBER (R_ARM_XPC25, 15)
RELOC_NUMBER (R_ARM_THM_XPC22, 16)
+ RELOC_NUMBER (R_ARM_TLS_DTPMOD32, 17)
+ RELOC_NUMBER (R_ARM_TLS_DTPOFF32, 18)
+ RELOC_NUMBER (R_ARM_TLS_TPOFF32, 19)
#endif /* not OLD_ARM_ABI */
RELOC_NUMBER (R_ARM_COPY, 20) /* Copy symbol at runtime. */
RELOC_NUMBER (R_ARM_GLOB_DAT, 21) /* Create GOT entry. */
@@ -153,7 +156,12 @@ START_RELOC_NUMBERS (elf_arm_reloc_type)
RELOC_NUMBER (R_ARM_GNU_VTINHERIT, 101)
RELOC_NUMBER (R_ARM_THM_PC11, 102) /* Cygnus extension to abi: Thumb unconditional branch. */
RELOC_NUMBER (R_ARM_THM_PC9, 103) /* Cygnus extension to abi: Thumb conditional branch. */
- FAKE_RELOC (FIRST_INVALID_RELOC3, 104)
+ RELOC_NUMBER (R_ARM_TLS_GD32, 104)
+ RELOC_NUMBER (R_ARM_TLS_LDM32, 105)
+ RELOC_NUMBER (R_ARM_TLS_LDO32, 106)
+ RELOC_NUMBER (R_ARM_TLS_IE32, 107)
+ RELOC_NUMBER (R_ARM_TLS_LE32, 108)
+ FAKE_RELOC (FIRST_INVALID_RELOC3, 109)
FAKE_RELOC (LAST_INVALID_RELOC3, 248)
RELOC_NUMBER (R_ARM_RXPC25, 249)
#endif /* not OLD_ARM_ABI */
Index: binutils/bfd/elf32-arm.c
===================================================================
--- binutils.orig/bfd/elf32-arm.c 2005-03-25 11:17:23.581949891 -0500
+++ binutils/bfd/elf32-arm.c 2005-03-25 11:17:27.945906261 -0500
@@ -294,49 +294,49 @@ static reloc_howto_type elf32_arm_howto_
0x07ff07ff, /* dst_mask */
TRUE), /* pcrel_offset */
- /* These next three relocs are not defined, but we need to fill the space. */
+ /* Dynamic TLS relocations. */
- HOWTO (R_ARM_NONE, /* type */
- 0, /* rightshift */
- 0, /* size (0 = byte, 1 = short, 2 = long) */
- 0, /* bitsize */
- FALSE, /* pc_relative */
- 0, /* bitpos */
- complain_overflow_dont,/* complain_on_overflow */
- bfd_elf_generic_reloc, /* special_function */
- "R_ARM_unknown_17", /* name */
- FALSE, /* partial_inplace */
- 0, /* src_mask */
- 0, /* dst_mask */
- FALSE), /* pcrel_offset */
+ HOWTO (R_ARM_TLS_DTPMOD32, /* type */
+ 0, /* rightshift */
+ 2, /* size (0 = byte, 1 = short, 2 = long) */
+ 32, /* bitsize */
+ FALSE, /* pc_relative */
+ 0, /* bitpos */
+ complain_overflow_bitfield,/* complain_on_overflow */
+ bfd_elf_generic_reloc, /* special_function */
+ "R_ARM_TLS_DTPMOD32", /* name */
+ TRUE, /* partial_inplace */
+ 0xffffffff, /* src_mask */
+ 0xffffffff, /* dst_mask */
+ FALSE), /* pcrel_offset */
- HOWTO (R_ARM_NONE, /* type */
- 0, /* rightshift */
- 0, /* size (0 = byte, 1 = short, 2 = long) */
- 0, /* bitsize */
- FALSE, /* pc_relative */
- 0, /* bitpos */
- complain_overflow_dont,/* complain_on_overflow */
- bfd_elf_generic_reloc, /* special_function */
- "R_ARM_unknown_18", /* name */
- FALSE, /* partial_inplace */
- 0, /* src_mask */
- 0, /* dst_mask */
- FALSE), /* pcrel_offset */
+ HOWTO (R_ARM_TLS_DTPOFF32, /* type */
+ 0, /* rightshift */
+ 2, /* size (0 = byte, 1 = short, 2 = long) */
+ 32, /* bitsize */
+ FALSE, /* pc_relative */
+ 0, /* bitpos */
+ complain_overflow_bitfield,/* complain_on_overflow */
+ bfd_elf_generic_reloc, /* special_function */
+ "R_ARM_TLS_DTPOFF32", /* name */
+ TRUE, /* partial_inplace */
+ 0xffffffff, /* src_mask */
+ 0xffffffff, /* dst_mask */
+ FALSE), /* pcrel_offset */
- HOWTO (R_ARM_NONE, /* type */
- 0, /* rightshift */
- 0, /* size (0 = byte, 1 = short, 2 = long) */
- 0, /* bitsize */
- FALSE, /* pc_relative */
- 0, /* bitpos */
- complain_overflow_dont,/* complain_on_overflow */
- bfd_elf_generic_reloc, /* special_function */
- "R_ARM_unknown_19", /* name */
- FALSE, /* partial_inplace */
- 0, /* src_mask */
- 0, /* dst_mask */
- FALSE), /* pcrel_offset */
+ HOWTO (R_ARM_TLS_TPOFF32, /* type */
+ 0, /* rightshift */
+ 2, /* size (0 = byte, 1 = short, 2 = long) */
+ 32, /* bitsize */
+ FALSE, /* pc_relative */
+ 0, /* bitpos */
+ complain_overflow_bitfield,/* complain_on_overflow */
+ bfd_elf_generic_reloc, /* special_function */
+ "R_ARM_TLS_TPOFF32", /* name */
+ TRUE, /* partial_inplace */
+ 0xffffffff, /* src_mask */
+ 0xffffffff, /* dst_mask */
+ FALSE), /* pcrel_offset */
/* Relocs used in ARM Linux */
@@ -663,6 +663,81 @@ static reloc_howto_type elf32_arm_howto_
TRUE), /* pcrel_offset */
};
+static reloc_howto_type elf32_arm_tls_gd32_howto =
+ HOWTO (R_ARM_TLS_GD32, /* type */
+ 0, /* rightshift */
+ 2, /* size (0 = byte, 1 = short, 2 = long) */
+ 32, /* bitsize */
+ FALSE, /* pc_relative */
+ 0, /* bitpos */
+ complain_overflow_bitfield,/* complain_on_overflow */
+ NULL, /* special_function */
+ "R_ARM_TLS_GD32", /* name */
+ TRUE, /* partial_inplace */
+ 0xffffffff, /* src_mask */
+ 0xffffffff, /* dst_mask */
+ FALSE); /* pcrel_offset */
+
+static reloc_howto_type elf32_arm_tls_ldo32_howto =
+ HOWTO (R_ARM_TLS_LDO32, /* type */
+ 0, /* rightshift */
+ 2, /* size (0 = byte, 1 = short, 2 = long) */
+ 32, /* bitsize */
+ FALSE, /* pc_relative */
+ 0, /* bitpos */
+ complain_overflow_bitfield,/* complain_on_overflow */
+ bfd_elf_generic_reloc, /* special_function */
+ "R_ARM_TLS_LDO32", /* name */
+ TRUE, /* partial_inplace */
+ 0xffffffff, /* src_mask */
+ 0xffffffff, /* dst_mask */
+ FALSE); /* pcrel_offset */
+
+static reloc_howto_type elf32_arm_tls_ldm32_howto =
+ HOWTO (R_ARM_TLS_LDM32, /* type */
+ 0, /* rightshift */
+ 2, /* size (0 = byte, 1 = short, 2 = long) */
+ 32, /* bitsize */
+ FALSE, /* pc_relative */
+ 0, /* bitpos */
+ complain_overflow_bitfield,/* complain_on_overflow */
+ bfd_elf_generic_reloc, /* special_function */
+ "R_ARM_TLS_LDM32", /* name */
+ TRUE, /* partial_inplace */
+ 0xffffffff, /* src_mask */
+ 0xffffffff, /* dst_mask */
+ FALSE); /* pcrel_offset */
+
+static reloc_howto_type elf32_arm_tls_le32_howto =
+ HOWTO (R_ARM_TLS_LE32, /* type */
+ 0, /* rightshift */
+ 2, /* size (0 = byte, 1 = short, 2 = long) */
+ 32, /* bitsize */
+ FALSE, /* pc_relative */
+ 0, /* bitpos */
+ complain_overflow_bitfield,/* complain_on_overflow */
+ bfd_elf_generic_reloc, /* special_function */
+ "R_ARM_TLS_LE32", /* name */
+ TRUE, /* partial_inplace */
+ 0xffffffff, /* src_mask */
+ 0xffffffff, /* dst_mask */
+ FALSE); /* pcrel_offset */
+
+static reloc_howto_type elf32_arm_tls_ie32_howto =
+ HOWTO (R_ARM_TLS_IE32, /* type */
+ 0, /* rightshift */
+ 2, /* size (0 = byte, 1 = short, 2 = long) */
+ 32, /* bitsize */
+ FALSE, /* pc_relative */
+ 0, /* bitpos */
+ complain_overflow_bitfield,/* complain_on_overflow */
+ NULL, /* special_function */
+ "R_ARM_TLS_IE32", /* name */
+ TRUE, /* partial_inplace */
+ 0xffffffff, /* src_mask */
+ 0xffffffff, /* dst_mask */
+ FALSE); /* pcrel_offset */
+
/* GNU extension to record C++ vtable hierarchy */
static reloc_howto_type elf32_arm_vtinherit_howto =
HOWTO (R_ARM_GNU_VTINHERIT, /* type */
@@ -825,6 +900,26 @@ elf32_arm_howto_from_type (unsigned int
case R_ARM_THM_PC9:
return &elf32_arm_thm_pc9_howto;
+
+ case R_ARM_TLS_GD32:
+ return &elf32_arm_tls_gd32_howto;
+ break;
+
+ case R_ARM_TLS_LDO32:
+ return &elf32_arm_tls_ldo32_howto;
+ break;
+
+ case R_ARM_TLS_LDM32:
+ return &elf32_arm_tls_ldm32_howto;
+ break;
+
+ case R_ARM_TLS_IE32:
+ return &elf32_arm_tls_ie32_howto;
+ break;
+
+ case R_ARM_TLS_LE32:
+ return &elf32_arm_tls_le32_howto;
+ break;
case R_ARM_RREL32:
case R_ARM_RABS32:
@@ -879,7 +974,16 @@ static const struct elf32_arm_reloc_map
{BFD_RELOC_ARM_ROSEGREL32, R_ARM_ROSEGREL32},
{BFD_RELOC_ARM_SBREL32, R_ARM_SBREL32},
{BFD_RELOC_ARM_PREL31, R_ARM_PREL31},
- {BFD_RELOC_ARM_TARGET2, R_ARM_TARGET2}
+ {BFD_RELOC_ARM_TARGET2, R_ARM_TARGET2},
+ {BFD_RELOC_ARM_PLT32, R_ARM_PLT32},
+ {BFD_RELOC_ARM_TLS_GD32, R_ARM_TLS_GD32},
+ {BFD_RELOC_ARM_TLS_LDO32, R_ARM_TLS_LDO32},
+ {BFD_RELOC_ARM_TLS_LDM32, R_ARM_TLS_LDM32},
+ {BFD_RELOC_ARM_TLS_DTPMOD32, R_ARM_TLS_DTPMOD32},
+ {BFD_RELOC_ARM_TLS_DTPOFF32, R_ARM_TLS_DTPOFF32},
+ {BFD_RELOC_ARM_TLS_TPOFF32, R_ARM_TLS_TPOFF32},
+ {BFD_RELOC_ARM_TLS_IE32, R_ARM_TLS_IE32},
+ {BFD_RELOC_ARM_TLS_LE32, R_ARM_TLS_LE32},
};
static reloc_howto_type *
@@ -903,6 +1007,21 @@ elf32_arm_reloc_type_lookup (abfd, code)
case BFD_RELOC_THUMB_PCREL_BRANCH9:
return & elf32_arm_thm_pc9_howto;
+ case BFD_RELOC_ARM_TLS_GD32:
+ return & elf32_arm_tls_gd32_howto;
+
+ case BFD_RELOC_ARM_TLS_LDO32:
+ return & elf32_arm_tls_ldo32_howto;
+
+ case BFD_RELOC_ARM_TLS_LDM32:
+ return & elf32_arm_tls_ldm32_howto;
+
+ case BFD_RELOC_ARM_TLS_IE32:
+ return & elf32_arm_tls_ie32_howto;
+
+ case BFD_RELOC_ARM_TLS_LE32:
+ return & elf32_arm_tls_le32_howto;
+
default:
for (i = 0; i < NUM_ELEM (elf32_arm_reloc_map); i ++)
if (elf32_arm_reloc_map[i].bfd_reloc_val == code)
@@ -1093,14 +1212,41 @@ struct _arm_elf_section_data
#define elf32_arm_section_data(sec) \
((struct _arm_elf_section_data *) elf_section_data (sec))
+/* The size of the thread control block. */
+#define TCB_SIZE 8
+
+struct elf32_arm_obj_tdata
+{
+ struct elf_obj_tdata root;
+
+ /* tls_type for each local got entry. */
+ char *local_got_tls_type;
+};
+
+#define elf32_arm_tdata(abfd) \
+ ((struct elf32_arm_obj_tdata *) (abfd)->tdata.any)
+
+#define elf32_arm_local_got_tls_type(abfd) \
+ (elf32_arm_tdata (abfd)->local_got_tls_type)
+
+static bfd_boolean
+elf32_arm_mkobject (bfd *abfd)
+{
+ bfd_size_type amt = sizeof (struct elf32_arm_obj_tdata);
+ abfd->tdata.any = bfd_zalloc (abfd, amt);
+ if (abfd->tdata.any == NULL)
+ return FALSE;
+ return TRUE;
+}
+
/* The ARM linker needs to keep track of the number of relocs that it
decides to copy in check_relocs for each symbol. This is so that
it can discard PC relative relocs if it doesn't need them when
linking with -Bsymbolic. We store the information in a field
extending the regular ELF linker hash table. */
-/* This structure keeps track of the number of PC relative relocs we
- have copied for a given symbol. */
+/* This structure keeps track of the number of relocs we have copied
+ for a given symbol. */
struct elf32_arm_relocs_copied
{
/* Next section. */
@@ -1109,8 +1255,12 @@ struct elf32_arm_relocs_copied
asection * section;
/* Number of relocs copied in this section. */
bfd_size_type count;
+ /* Number of PC-relative relocs copied in this section. */
+ bfd_size_type pc_count;
};
+#define elf32_arm_hash_entry(ent) ((struct elf32_arm_link_hash_entry *)(ent))
+
/* Arm ELF linker hash entry. */
struct elf32_arm_link_hash_entry
{
@@ -1127,6 +1277,12 @@ struct elf32_arm_link_hash_entry
used, we need to record the index into .got.plt instead of
recomputing it from the PLT offset. */
bfd_signed_vma plt_got_offset;
+
+#define GOT_UNKNOWN 0
+#define GOT_NORMAL 1
+#define GOT_TLS_GD 2
+#define GOT_TLS_IE 4
+ unsigned char tls_type;
};
/* Traverse an arm ELF linker hash table. */
@@ -1189,6 +1345,12 @@ struct elf32_arm_link_hash_table
asection *sdynbss;
asection *srelbss;
+ /* Data for R_ARM_TLS_LDM32 relocations. */
+ union {
+ bfd_signed_vma refcount;
+ bfd_vma offset;
+ } tls_ldm_got;
+
/* Small local sym to section mapping cache. */
struct sym_sec_cache sym_sec;
@@ -1220,6 +1382,7 @@ elf32_arm_link_hash_newfunc (struct bfd_
if (ret != NULL)
{
ret->relocs_copied = NULL;
+ ret->tls_type = GOT_UNKNOWN;
ret->plt_thumb_refcount = 0;
ret->plt_got_offset = -1;
}
@@ -1321,6 +1484,7 @@ elf32_arm_copy_indirect_symbol (const st
for (q = edir->relocs_copied; q != NULL; q = q->next)
if (q->section == p->section)
{
+ q->pc_count += p->pc_count;
q->count += p->count;
*pp = p->next;
break;
@@ -1346,6 +1510,13 @@ elf32_arm_copy_indirect_symbol (const st
else
BFD_ASSERT (eind->plt_thumb_refcount == 0);
+ if (ind->root.type == bfd_link_hash_indirect
+ && dir->got.refcount <= 0)
+ {
+ edir->tls_type = eind->tls_type;
+ eind->tls_type = GOT_UNKNOWN;
+ }
+
_bfd_elf_link_hash_copy_indirect (bed, dir, ind);
}
@@ -1392,6 +1563,7 @@ elf32_arm_link_hash_table_create (bfd *a
ret->use_rel = 1;
ret->sym_sec.abfd = NULL;
ret->obfd = abfd;
+ ret->tls_ldm_got.refcount = 0;
return &ret->root.root;
}
@@ -2228,6 +2400,35 @@ arm_real_reloc_type (struct elf32_arm_li
#endif /* OLD_ARM_ABI */
+/* Return the base VMA address which should be subtracted from real addresses
+ when resolving @dtpoff relocation.
+ This is PT_TLS segment p_vaddr. */
+
+static bfd_vma
+dtpoff_base (struct bfd_link_info *info)
+{
+ /* If tls_sec is NULL, we should have signalled an error already. */
+ if (elf_hash_table (info)->tls_sec == NULL)
+ return 0;
+ return elf_hash_table (info)->tls_sec->vma;
+}
+
+/* Return the relocation value for @tpoff relocation
+ if STT_TLS virtual address is ADDRESS. */
+
+static bfd_vma
+tpoff (struct bfd_link_info *info, bfd_vma address)
+{
+ struct elf_link_hash_table *htab = elf_hash_table (info);
+ bfd_vma base;
+
+ /* If tls_sec is NULL, we should have signalled an error already. */
+ if (htab->tls_sec == NULL)
+ return 0;
+ base = align_power ((bfd_vma) TCB_SIZE, htab->tls_sec->alignment_power);
+ return address - htab->tls_sec->vma + base;
+}
+
/* Perform a relocation as part of a final link. */
static bfd_reloc_status_type
@@ -2979,6 +3180,222 @@ elf32_arm_final_link_relocate (reloc_how
contents, rel->r_offset, value,
(bfd_vma) 0);
+ case R_ARM_TLS_LDO32:
+ value = value - dtpoff_base (info);
+
+ return _bfd_final_link_relocate (howto, input_bfd, input_section,
+ contents, rel->r_offset, value, (bfd_vma) 0);
+
+ case R_ARM_TLS_LDM32:
+ {
+ bfd_vma off;
+
+ if (globals->sgot == NULL)
+ abort ();
+
+ off = globals->tls_ldm_got.offset;
+
+ if ((off & 1) != 0)
+ off &= ~1;
+ else
+ {
+ /* If we don't know the module number, create a relocation
+ for it. */
+ if (info->shared)
+ {
+ Elf_Internal_Rela outrel;
+ bfd_byte *loc;
+
+ if (globals->srelgot == NULL)
+ abort ();
+
+ outrel.r_offset = (globals->sgot->output_section->vma
+ + globals->sgot->output_offset + off);
+ outrel.r_info = ELF32_R_INFO (0, R_ARM_TLS_DTPMOD32);
+
+ bfd_put_32 (output_bfd, 0, globals->sgot->contents + off);
+
+ loc = globals->srelgot->contents;
+ loc += globals->srelgot->reloc_count++ * sizeof (Elf32_External_Rel);
+ bfd_elf32_swap_reloc_out (output_bfd, &outrel, loc);
+ }
+ else
+ bfd_put_32 (output_bfd, 1, globals->sgot->contents + off);
+
+ globals->tls_ldm_got.offset |= 1;
+ }
+
+ value = globals->sgot->output_section->vma + globals->sgot->output_offset + off
+ - (input_section->output_section->vma + input_section->output_offset + rel->r_offset);
+
+ return _bfd_final_link_relocate (howto, input_bfd, input_section,
+ contents, rel->r_offset, value,
+ (bfd_vma) 0);
+ }
+
+ case R_ARM_TLS_GD32:
+ case R_ARM_TLS_IE32:
+ {
+ bfd_vma off;
+ int indx;
+ char tls_type;
+
+ if (globals->sgot == NULL)
+ abort ();
+
+ indx = 0;
+ if (h != NULL)
+ {
+ bfd_boolean dyn;
+ dyn = globals->root.dynamic_sections_created;
+ if (WILL_CALL_FINISH_DYNAMIC_SYMBOL (dyn, info->shared, h)
+ && (!info->shared
+ || !SYMBOL_REFERENCES_LOCAL (info, h)))
+ {
+ *unresolved_reloc_p = FALSE;
+ indx = h->dynindx;
+ }
+ off = h->got.offset;
+ tls_type = ((struct elf32_arm_link_hash_entry *) h)->tls_type;
+ }
+ else
+ {
+ if (local_got_offsets == NULL)
+ abort ();
+ off = local_got_offsets[r_symndx];
+ tls_type = elf32_arm_local_got_tls_type (input_bfd)[r_symndx];
+ }
+
+ if (tls_type == GOT_UNKNOWN)
+ abort ();
+
+ if ((off & 1) != 0)
+ off &= ~1;
+ else
+ {
+ bfd_boolean need_relocs = FALSE;
+ Elf_Internal_Rela outrel;
+ bfd_byte *loc = NULL;
+ int cur_off = off;
+
+ /* The GOT entries have not been initialized yet. Do it
+ now, and emit any relocations. If both an IE GOT and a
+ GD GOT are necessary, we emit the GD first. */
+
+ if ((info->shared || indx != 0)
+ && (h == NULL
+ || ELF_ST_VISIBILITY (h->other) == STV_DEFAULT
+ || h->root.type != bfd_link_hash_undefweak))
+ {
+ need_relocs = TRUE;
+ if (globals->srelgot == NULL)
+ abort ();
+ loc = globals->srelgot->contents;
+ loc += globals->srelgot->reloc_count * sizeof (Elf32_External_Rel);
+ }
+
+ if (tls_type & GOT_TLS_GD)
+ {
+ if (need_relocs)
+ {
+ outrel.r_offset = (globals->sgot->output_section->vma
+ + globals->sgot->output_offset + cur_off);
+ outrel.r_info = ELF32_R_INFO (indx, R_ARM_TLS_DTPMOD32);
+ bfd_put_32 (output_bfd, 0, globals->sgot->contents + cur_off);
+
+ bfd_elf32_swap_reloc_out (output_bfd, &outrel, loc);
+ globals->srelgot->reloc_count++;
+ loc += sizeof (Elf32_External_Rel);
+
+ if (indx == 0)
+ bfd_put_32 (output_bfd, value - dtpoff_base (info),
+ globals->sgot->contents + cur_off + 4);
+ else
+ {
+ bfd_put_32 (output_bfd, 0,
+ globals->sgot->contents + cur_off + 4);
+
+ outrel.r_info = ELF32_R_INFO (indx,
+ R_ARM_TLS_DTPOFF32);
+ outrel.r_offset += 4;
+ bfd_elf32_swap_reloc_out (output_bfd, &outrel, loc);
+ globals->srelgot->reloc_count++;
+ loc += sizeof (Elf32_External_Rel);
+ }
+ }
+ else
+ {
+ /* If we are not emitting relocations for a
+ general dynamic reference, then we must be in a
+ static link or an executable link with the
+ symbol binding locally. Mark it as belonging
+ to module 1, the executable. */
+ bfd_put_32 (output_bfd, 1,
+ globals->sgot->contents + cur_off);
+ bfd_put_32 (output_bfd, value - dtpoff_base (info),
+ globals->sgot->contents + cur_off + 4);
+ }
+
+ cur_off += 8;
+ }
+
+ if (tls_type & GOT_TLS_IE)
+ {
+ if (need_relocs)
+ {
+ outrel.r_offset = (globals->sgot->output_section->vma
+ + globals->sgot->output_offset
+ + cur_off);
+ outrel.r_info = ELF32_R_INFO (indx, R_ARM_TLS_TPOFF32);
+
+ if (indx == 0)
+ bfd_put_32 (output_bfd, value - dtpoff_base (info),
+ globals->sgot->contents + cur_off);
+ else
+ bfd_put_32 (output_bfd, 0,
+ globals->sgot->contents + cur_off);
+
+ bfd_elf32_swap_reloc_out (output_bfd, &outrel, loc);
+ globals->srelgot->reloc_count++;
+ loc += sizeof (Elf32_External_Rel);
+ }
+ else
+ bfd_put_32 (output_bfd, tpoff (info, value),
+ globals->sgot->contents + cur_off);
+ cur_off += 4;
+ }
+
+ if (h != NULL)
+ h->got.offset |= 1;
+ else
+ local_got_offsets[r_symndx] |= 1;
+ }
+
+ if ((tls_type & GOT_TLS_GD) && r_type != R_ARM_TLS_GD32)
+ off += 8;
+ value = globals->sgot->output_section->vma + globals->sgot->output_offset + off
+ - (input_section->output_section->vma + input_section->output_offset + rel->r_offset);
+
+ return _bfd_final_link_relocate (howto, input_bfd, input_section,
+ contents, rel->r_offset, value,
+ (bfd_vma) 0);
+ }
+
+ case R_ARM_TLS_LE32:
+ if (info->shared)
+ {
+ (*_bfd_error_handler)
+ (_("%B(%A+0x%lx): R_ARM_TLS_LE32 relocation not permitted in shared object"),
+ input_bfd, input_section,
+ (long) rel->r_offset, howto->name);
+ return FALSE;
+ }
+ else
+ value = tpoff (info, value);
+
+ return _bfd_final_link_relocate (howto, input_bfd, input_section,
+ contents, rel->r_offset, value, (bfd_vma) 0);
+
case R_ARM_SBREL32:
return bfd_reloc_notsupported;
@@ -3098,6 +3515,16 @@ arm_add_to_rel (bfd * abfd,
}
}
+#define IS_ARM_TLS_RELOC(R_TYPE) \
+ ((R_TYPE) == R_ARM_TLS_GD32 \
+ || (R_TYPE) == R_ARM_TLS_LDO32 \
+ || (R_TYPE) == R_ARM_TLS_LDM32 \
+ || (R_TYPE) == R_ARM_TLS_DTPOFF32 \
+ || (R_TYPE) == R_ARM_TLS_DTPMOD32 \
+ || (R_TYPE) == R_ARM_TLS_TPOFF32 \
+ || (R_TYPE) == R_ARM_TLS_LE32 \
+ || (R_TYPE) == R_ARM_TLS_IE32)
+
/* Relocate an ARM ELF section. */
static bfd_boolean
elf32_arm_relocate_section (bfd * output_bfd,
@@ -3136,6 +3563,7 @@ elf32_arm_relocate_section (bfd *
bfd_vma relocation;
bfd_reloc_status_type r;
arelent bfd_reloc;
+ char sym_type;
bfd_boolean unresolved_reloc = FALSE;
r_symndx = ELF32_R_SYM (rel->r_info);
@@ -3179,6 +3607,7 @@ elf32_arm_relocate_section (bfd *
if (r_symndx < symtab_hdr->sh_info)
{
sym = local_syms + r_symndx;
+ sym_type = ELF32_ST_TYPE (sym->st_info);
sec = local_sections[r_symndx];
if (globals->use_rel)
{
@@ -3232,6 +3661,8 @@ elf32_arm_relocate_section (bfd *
r_symndx, symtab_hdr, sym_hashes,
h, sec, relocation,
unresolved_reloc, warned);
+
+ sym_type = h->type;
}
if (h != NULL)
@@ -3244,6 +3675,24 @@ elf32_arm_relocate_section (bfd *
name = bfd_section_name (input_bfd, sec);
}
+ if (r_symndx != 0
+ && r_type != R_ARM_NONE
+ && (h == NULL
+ || h->root.type == bfd_link_hash_defined
+ || h->root.type == bfd_link_hash_defweak)
+ && IS_ARM_TLS_RELOC (r_type) != (sym_type == STT_TLS))
+ {
+ (*_bfd_error_handler)
+ ((sym_type == STT_TLS
+ ? _("%B(%A+0x%lx): %s used with TLS symbol %s")
+ : _("%B(%A+0x%lx): %s used with non-TLS symbol %s")),
+ input_bfd,
+ input_section,
+ (long) rel->r_offset,
+ howto->name,
+ name);
+ }
+
r = elf32_arm_final_link_relocate (howto, input_bfd, output_bfd,
input_section, contents, rel,
relocation, info, sec, name,
@@ -3823,10 +4272,10 @@ elf32_arm_gc_mark_hook (asection *
/* Update the got entry reference counts for the section being removed. */
static bfd_boolean
-elf32_arm_gc_sweep_hook (bfd * abfd ATTRIBUTE_UNUSED,
- struct bfd_link_info * info ATTRIBUTE_UNUSED,
- asection * sec ATTRIBUTE_UNUSED,
- const Elf_Internal_Rela * relocs ATTRIBUTE_UNUSED)
+elf32_arm_gc_sweep_hook (bfd * abfd,
+ struct bfd_link_info * info,
+ asection * sec,
+ const Elf_Internal_Rela * relocs)
{
Elf_Internal_Shdr *symtab_hdr;
struct elf_link_hash_entry **sym_hashes;
@@ -3868,6 +4317,8 @@ elf32_arm_gc_sweep_hook (bfd *
#ifndef OLD_ARM_ABI
case R_ARM_GOT_PREL:
#endif
+ case R_ARM_TLS_GD32:
+ case R_ARM_TLS_IE32:
if (h != NULL)
{
if (h->got.refcount > 0)
@@ -3880,6 +4331,10 @@ elf32_arm_gc_sweep_hook (bfd *
}
break;
+ case R_ARM_TLS_LDM32:
+ elf32_arm_hash_table (info)->tls_ldm_got.refcount -= 1;
+ break;
+
case R_ARM_ABS32:
case R_ARM_REL32:
case R_ARM_PC24:
@@ -3915,6 +4370,8 @@ elf32_arm_gc_sweep_hook (bfd *
if (p->section == sec)
{
p->count -= 1;
+ if (ELF32_R_TYPE (rel->r_info) == R_ARM_REL32)
+ p->pc_count -= 1;
if (p->count == 0)
*pp = p->next;
break;
@@ -3986,6 +4443,14 @@ elf32_arm_check_relocs (bfd *abfd, struc
#ifndef OLD_ARM_ABI
r_type = arm_real_reloc_type (htab, r_type);
#endif
+
+ if (r_symndx >= NUM_SHDR_ENTRIES (symtab_hdr))
+ {
+ (*_bfd_error_handler) (_("%B: bad symbol index: %d"), abfd,
+ r_symndx);
+ return FALSE;
+ }
+
if (r_symndx < symtab_hdr->sh_info)
h = NULL;
else
@@ -3999,33 +4464,69 @@ elf32_arm_check_relocs (bfd *abfd, struc
#ifndef OLD_ARM_ABI
case R_ARM_GOT_PREL:
#endif
+ case R_ARM_TLS_GD32:
+ case R_ARM_TLS_IE32:
/* This symbol requires a global offset table entry. */
- if (h != NULL)
- {
- h->got.refcount++;
- }
- else
- {
- bfd_signed_vma *local_got_refcounts;
+ {
+ int tls_type, old_tls_type;
- /* This is a global offset table entry for a local symbol. */
- local_got_refcounts = elf_local_got_refcounts (abfd);
- if (local_got_refcounts == NULL)
- {
- bfd_size_type size;
+ switch (r_type)
+ {
+ case R_ARM_TLS_GD32: tls_type = GOT_TLS_GD; break;
+ case R_ARM_TLS_IE32: tls_type = GOT_TLS_IE; break;
+ default: tls_type = GOT_NORMAL; break;
+ }
- size = symtab_hdr->sh_info;
- size *= (sizeof (bfd_signed_vma) + sizeof (char));
- local_got_refcounts = bfd_zalloc (abfd, size);
- if (local_got_refcounts == NULL)
- return FALSE;
- elf_local_got_refcounts (abfd) = local_got_refcounts;
- }
- local_got_refcounts[r_symndx] += 1;
- }
- if (r_type == R_ARM_GOT32)
- break;
- /* Fall through. */
+ if (h != NULL)
+ {
+ h->got.refcount++;
+ old_tls_type = elf32_arm_hash_entry (h)->tls_type;
+ }
+ else
+ {
+ bfd_signed_vma *local_got_refcounts;
+
+ /* This is a global offset table entry for a local symbol. */
+ local_got_refcounts = elf_local_got_refcounts (abfd);
+ if (local_got_refcounts == NULL)
+ {
+ bfd_size_type size;
+
+ size = symtab_hdr->sh_info;
+ size *= (sizeof (bfd_signed_vma) + sizeof(char));
+ local_got_refcounts = bfd_zalloc (abfd, size);
+ if (local_got_refcounts == NULL)
+ return FALSE;
+ elf_local_got_refcounts (abfd) = local_got_refcounts;
+ elf32_arm_local_got_tls_type (abfd)
+ = (char *) (local_got_refcounts + symtab_hdr->sh_info);
+ }
+ local_got_refcounts[r_symndx] += 1;
+ old_tls_type = elf32_arm_local_got_tls_type (abfd) [r_symndx];
+ }
+
+ /* We will already have issued an error message if there is a
+ TLS / non-TLS mismatch, based on the symbol type. We don't
+ support any linker relaxations. So just combine any TLS
+ types needed. */
+ if (old_tls_type != GOT_UNKNOWN && old_tls_type != GOT_NORMAL
+ && tls_type != GOT_NORMAL)
+ tls_type |= old_tls_type;
+
+ if (old_tls_type != tls_type)
+ {
+ if (h != NULL)
+ elf32_arm_hash_entry (h)->tls_type = tls_type;
+ else
+ elf32_arm_local_got_tls_type (abfd) [r_symndx] = tls_type;
+ }
+ }
+ /* Fall through */
+
+ case R_ARM_TLS_LDM32:
+ if (r_type == R_ARM_TLS_LDM32)
+ htab->tls_ldm_got.refcount++;
+ /* Fall through */
case R_ARM_GOTOFF:
case R_ARM_GOTPC:
@@ -4176,8 +4677,11 @@ elf32_arm_check_relocs (bfd *abfd, struc
*head = p;
p->section = sec;
p->count = 0;
+ p->pc_count = 0;
}
+ if (r_type == R_ARM_REL32)
+ p->pc_count += 1;
p->count += 1;
}
break;
@@ -4404,6 +4908,11 @@ elf32_arm_adjust_dynamic_symbol (struct
return TRUE;
}
+ /* If there are no non-GOT references, we do not need a copy
+ relocation. */
+ if (!h->non_got_ref)
+ return TRUE;
+
/* This is a reference to a symbol defined by a dynamic object which
is not a function. */
@@ -4571,6 +5080,8 @@ allocate_dynrelocs (struct elf_link_hash
{
asection *s;
bfd_boolean dyn;
+ int tls_type = elf32_arm_hash_entry (h)->tls_type;
+ int indx;
/* Make sure this symbol is output as a dynamic symbol.
Undefined weak syms won't yet be marked as dynamic. */
@@ -4585,12 +5096,49 @@ allocate_dynrelocs (struct elf_link_hash
{
s = htab->sgot;
h->got.offset = s->size;
- s->size += 4;
+
+ if (tls_type == GOT_UNKNOWN)
+ abort ();
+
+ if (tls_type == GOT_NORMAL)
+ /* Non-TLS symbols need one GOT slot. */
+ s->size += 4;
+ else
+ {
+ if (tls_type & GOT_TLS_GD)
+ /* R_ARM_TLS_GD32 needs 2 consecutive GOT slots. */
+ s->size += 8;
+ if (tls_type & GOT_TLS_IE)
+ /* R_ARM_TLS_IE32 needs one GOT slot. */
+ s->size += 4;
+ }
+
dyn = htab->root.dynamic_sections_created;
- if ((ELF_ST_VISIBILITY (h->other) == STV_DEFAULT
- || h->root.type != bfd_link_hash_undefweak)
- && (info->shared
- || WILL_CALL_FINISH_DYNAMIC_SYMBOL (dyn, 0, h)))
+
+ indx = 0;
+ if (WILL_CALL_FINISH_DYNAMIC_SYMBOL (dyn, info->shared, h)
+ && (!info->shared
+ || !SYMBOL_REFERENCES_LOCAL (info, h)))
+ indx = h->dynindx;
+
+ if (tls_type != GOT_NORMAL
+ && (info->shared || indx != 0)
+ && (ELF_ST_VISIBILITY (h->other) == STV_DEFAULT
+ || h->root.type != bfd_link_hash_undefweak))
+ {
+ if (tls_type & GOT_TLS_IE)
+ htab->srelgot->size += sizeof (Elf32_External_Rel);
+
+ if (tls_type & GOT_TLS_GD)
+ htab->srelgot->size += sizeof (Elf32_External_Rel);
+
+ if ((tls_type & GOT_TLS_GD) && indx != 0)
+ htab->srelgot->size += sizeof (Elf32_External_Rel);
+ }
+ else if ((ELF_ST_VISIBILITY (h->other) == STV_DEFAULT
+ || h->root.type != bfd_link_hash_undefweak)
+ && (info->shared
+ || WILL_CALL_FINISH_DYNAMIC_SYMBOL (dyn, 0, h)))
htab->srelgot->size += sizeof (Elf32_External_Rel);
}
}
@@ -4608,7 +5156,28 @@ allocate_dynrelocs (struct elf_link_hash
if (info->shared || htab->root.is_relocatable_executable)
{
- /* Discard relocs on undefined weak syms with non-default
+ /* The only reloc that uses pc_count is R_ARM_REL32, which will
+ appear on something like ".long foo - .". We want calls to
+ protected symbols to resolve directly to the function rather
+ than going via the plt. If people want function pointer
+ comparisons to work as expected then they should avoid
+ writing assembly like ".long foo - .". */
+ if (SYMBOL_CALLS_LOCAL (info, h))
+ {
+ struct elf32_arm_relocs_copied **pp;
+
+ for (pp = &eh->relocs_copied; (p = *pp) != NULL; )
+ {
+ p->count -= p->pc_count;
+ p->pc_count = 0;
+ if (p->count == 0)
+ *pp = p->next;
+ else
+ pp = &p->next;
+ }
+ }
+
+ /* Also discard relocs on undefined weak syms with non-default
visibility. */
if (ELF_ST_VISIBILITY (h->other) != STV_DEFAULT
&& h->root.type == bfd_link_hash_undefweak)
@@ -4773,6 +5342,7 @@ elf32_arm_size_dynamic_sections (bfd * o
symtab_hdr = &elf_tdata (ibfd)->symtab_hdr;
locsymcount = symtab_hdr->sh_info;
end_local_got = local_got + locsymcount;
+ local_tls_type = elf32_arm_local_got_tls_type (ibfd);
s = htab->sgot;
srel = htab->srelgot;
for (; local_got < end_local_got; ++local_got, ++local_tls_type)
@@ -4780,8 +5350,15 @@ elf32_arm_size_dynamic_sections (bfd * o
if (*local_got > 0)
{
*local_got = s->size;
- s->size += 4;
- if (info->shared)
+ if (*local_tls_type & GOT_TLS_GD)
+ /* TLS_GD relocs need an 8-byte structure in the GOT. */
+ s->size += 8;
+ if (*local_tls_type & GOT_TLS_IE)
+ s->size += 4;
+ if (*local_tls_type == GOT_NORMAL)
+ s->size += 4;
+
+ if (info->shared || *local_tls_type == GOT_TLS_GD)
srel->size += sizeof (Elf32_External_Rel);
}
else
@@ -4789,6 +5366,18 @@ elf32_arm_size_dynamic_sections (bfd * o
}
}
+ if (htab->tls_ldm_got.refcount > 0)
+ {
+ /* Allocate two GOT entries and one dynamic relocation (if necessary)
+ for R_ARM_TLS_LDM32 relocations. */
+ htab->tls_ldm_got.offset = htab->sgot->size;
+ htab->sgot->size += 8;
+ if (info->shared)
+ htab->srelgot->size += sizeof (Elf32_External_Rel);
+ }
+ else
+ htab->tls_ldm_got.offset = -1;
+
/* Allocate global sym .plt and .got entries, and space for global
sym dynamic relocs. */
elf_link_hash_traverse (& htab->root, allocate_dynrelocs, info);
@@ -5059,7 +5648,9 @@ elf32_arm_finish_dynamic_symbol (bfd * o
}
}
- if (h->got.offset != (bfd_vma) -1)
+ if (h->got.offset != (bfd_vma) -1
+ && (elf32_arm_hash_entry (h)->tls_type & GOT_TLS_GD) == 0
+ && (elf32_arm_hash_entry (h)->tls_type & GOT_TLS_IE) == 0)
{
asection * sgot;
asection * srel;
@@ -5752,6 +6343,8 @@ const struct elf_size_info elf32_arm_siz
#endif
#define ELF_MINPAGESIZE 0x1000
+#define bfd_elf32_mkobject elf32_arm_mkobject
+
#define bfd_elf32_bfd_copy_private_bfd_data elf32_arm_copy_private_bfd_data
#define bfd_elf32_bfd_merge_private_bfd_data elf32_arm_merge_private_bfd_data
#define bfd_elf32_bfd_set_private_flags elf32_arm_set_private_flags
Index: binutils/gas/testsuite/gas/arm/tls.s
===================================================================
--- /dev/null 1970-01-01 00:00:00.000000000 +0000
+++ binutils/gas/testsuite/gas/arm/tls.s 2005-03-25 11:17:27.945906261 -0500
@@ -0,0 +1,14 @@
+ .text
+ .globl main
+ .type main, %function
+main:
+ nop
+.L2:
+ nop
+ mov pc, lr
+
+.Lpool:
+ .word a(tlsgd) + (. - .L2 - 8)
+ .word b(tlsldm) + (. - .L2 - 8)
+ .word c(gottpoff) + (. - .L2 - 8)
+ .word d(tpoff)
Index: binutils/ld/testsuite/ld-arm/tls-lib.s
===================================================================
--- /dev/null 1970-01-01 00:00:00.000000000 +0000
+++ binutils/ld/testsuite/ld-arm/tls-lib.s 2005-03-25 11:17:27.946906022 -0500
@@ -0,0 +1,22 @@
+ .text
+ .globl foo
+ .type foo, %function
+foo:
+ nop
+.L2:
+ nop
+ mov pc, lr
+
+.Lpool:
+ .word lib_gd(tlsgd) + (. - .L2 - 8)
+ .word lib_ld(tlsldm) + (. - .L2 - 8)
+ .word lib_ld(tlsldo)
+
+ .section .tdata,"awT"
+ .global lib_gd
+lib_gd:
+ .space 4
+
+ .global lib_ld
+lib_ld:
+ .space 4
Index: binutils/gas/testsuite/gas/arm/arm.exp
===================================================================
--- binutils.orig/gas/testsuite/gas/arm/arm.exp 2005-03-25 11:15:11.829442638 -0500
+++ binutils/gas/testsuite/gas/arm/arm.exp 2005-03-25 11:17:27.946906022 -0500
@@ -72,6 +72,8 @@ if {[istarget *arm*-*-*] || [istarget "x
run_dump_test "mapping"
gas_test "bignum1.s" "" $stdoptlist "bignums"
run_dump_test "unwind"
+
+ run_dump_test "tls"
}
if {! [istarget arm*-*-aout] && ![istarget arm-*-pe]} then {
Index: binutils/ld/testsuite/ld-arm/tls-app.d
===================================================================
--- /dev/null 1970-01-01 00:00:00.000000000 +0000
+++ binutils/ld/testsuite/ld-arm/tls-app.d 2005-03-25 11:17:27.946906022 -0500
@@ -0,0 +1,18 @@
+
+.*: file format elf32-.*arm
+architecture: arm, flags 0x00000112:
+EXEC_P, HAS_SYMS, D_PAGED
+start address 0x00008274
+
+Disassembly of section .text:
+
+00008274 <foo>:
+ 8274: e1a00000 nop \(mov r0,r0\)
+ 8278: e1a00000 nop \(mov r0,r0\)
+ 827c: e1a0f00e mov pc, lr
+ 8280: 000080bc streqh r8, \[r0\], -ip
+ 8284: 000080b4 streqh r8, \[r0\], -r4
+ 8288: 000080ac andeq r8, r0, ip, lsr #1
+ 828c: 00000004 andeq r0, r0, r4
+ 8290: 000080c4 andeq r8, r0, r4, asr #1
+ 8294: 00000014 andeq r0, r0, r4, lsl r0
Index: binutils/ld/testsuite/ld-arm/tls-app.r
===================================================================
--- /dev/null 1970-01-01 00:00:00.000000000 +0000
+++ binutils/ld/testsuite/ld-arm/tls-app.r 2005-03-25 11:17:27.946906022 -0500
@@ -0,0 +1,12 @@
+
+.*: file format elf32-.*arm
+
+DYNAMIC RELOCATION RECORDS
+OFFSET TYPE VALUE
+00010334 R_ARM_TLS_DTPMOD32 app_gd
+00010338 R_ARM_TLS_DTPOFF32 app_gd
+0001033c R_ARM_TLS_DTPMOD32 lib_gd
+00010340 R_ARM_TLS_DTPOFF32 lib_gd
+00010344 R_ARM_TLS_TPOFF32 app_ie
+
+
Index: binutils/ld/testsuite/ld-arm/tls-app.s
===================================================================
--- /dev/null 1970-01-01 00:00:00.000000000 +0000
+++ binutils/ld/testsuite/ld-arm/tls-app.s 2005-03-25 11:17:27.947905783 -0500
@@ -0,0 +1,34 @@
+ .text
+ .globl foo
+ .type foo, %function
+foo:
+ nop
+.L2:
+ nop
+ mov pc, lr
+
+.Lpool:
+ .word lib_gd(tlsgd) + (. - .L2 - 8)
+ .word app_gd(tlsgd) + (. - .L2 - 8)
+ .word app_ld(tlsldm) + (. - .L2 - 8)
+ .word app_ld(tlsldo)
+ .word app_ie(gottpoff) + (. - .L2 - 8)
+ .word app_le(tpoff)
+
+ .section .tdata,"awT"
+ .global app_gd
+app_gd:
+ .space 4
+
+ .global app_ld
+app_ld:
+ .space 4
+
+ .section .tbss,"awT",%nobits
+ .global app_ie
+app_ie:
+ .space 4
+
+ .global app_le
+app_le:
+ .space 4
Index: binutils/ld/testsuite/ld-arm/arm-elf.exp
===================================================================
--- binutils.orig/ld/testsuite/ld-arm/arm-elf.exp 2005-03-25 11:15:11.846438578 -0500
+++ binutils/ld/testsuite/ld-arm/arm-elf.exp 2005-03-25 11:17:27.947905783 -0500
@@ -75,6 +75,12 @@ set armelftests {
{"arm-rel31" "-static -T arm.ld" "" {arm-rel31.s}
{{objdump -s arm-rel31.d}}
"arm-rel31"}
+ {"TLS shared library" "-shared -T arm-lib.ld" "" {tls-lib.s}
+ {{objdump -fdw tls-lib.d} {objdump -Rw tls-lib.r}}
+ "tls-lib.so"}
+ {"TLS dynamic application" "-T arm-dyn.ld tmpdir/tls-lib.so" "" {tls-app.s}
+ {{objdump -fdw tls-app.d} {objdump -Rw tls-app.r}}
+ "tls-app"}
}
run_ld_link_tests $armelftests
Index: binutils/ld/testsuite/ld-arm/tls-lib.d
===================================================================
--- /dev/null 1970-01-01 00:00:00.000000000 +0000
+++ binutils/ld/testsuite/ld-arm/tls-lib.d 2005-03-25 11:17:27.947905783 -0500
@@ -0,0 +1,15 @@
+
+.*: file format elf32-.*arm
+architecture: arm, flags 0x00000150:
+HAS_SYMS, DYNAMIC, D_PAGED
+start address 0x.*
+
+Disassembly of section .text:
+
+00000328 <foo>:
+ 328: e1a00000 nop \(mov r0,r0\)
+ 32c: e1a00000 nop \(mov r0,r0\)
+ 330: e1a0f00e mov pc, lr
+ 334: 00008098 muleq r0, r8, r0
+ 338: 0000808c andeq r8, r0, ip, lsl #1
+ 33c: 00000004 andeq r0, r0, r4
Index: binutils/ld/testsuite/ld-arm/tls-lib.r
===================================================================
--- /dev/null 1970-01-01 00:00:00.000000000 +0000
+++ binutils/ld/testsuite/ld-arm/tls-lib.r 2005-03-25 11:17:27.947905783 -0500
@@ -0,0 +1,10 @@
+
+.*: file format elf32-.*arm
+
+DYNAMIC RELOCATION RECORDS
+OFFSET TYPE VALUE
+000083c4 R_ARM_TLS_DTPMOD32 \*ABS\*
+000083cc R_ARM_TLS_DTPMOD32 lib_gd
+000083d0 R_ARM_TLS_DTPOFF32 lib_gd
+
+
Index: binutils/gas/testsuite/gas/arm/tls.d
===================================================================
--- /dev/null 1970-01-01 00:00:00.000000000 +0000
+++ binutils/gas/testsuite/gas/arm/tls.d 2005-03-23 16:17:18.000000000 -0500
@@ -0,0 +1,21 @@
+#objdump: -dr
+#name: TLS
+
+# Test generation of TLS relocations
+
+.*: +file format .*arm.*
+
+Disassembly of section .text:
+
+00+0 <main>:
+ 0: e1a00000 nop \(mov r0,r0\)
+ 4: e1a00000 nop \(mov r0,r0\)
+ 8: e1a0f00e mov pc, lr
+ c: 00000000 andeq r0, r0, r0
+ c: R_ARM_TLS_GD32 a
+ 10: 00000004 andeq r0, r0, r4
+ 10: R_ARM_TLS_LDM32 b
+ 14: 00000008 andeq r0, r0, r8
+ 14: R_ARM_TLS_IE32 c
+ 18: 00000000 andeq r0, r0, r0
+ 18: R_ARM_TLS_LE32 d
Index: binutils/ld/testsuite/ld-arm/arm-lib.ld
===================================================================
--- binutils.orig/ld/testsuite/ld-arm/arm-lib.ld 2005-03-25 11:17:07.096891954 -0500
+++ binutils/ld/testsuite/ld-arm/arm-lib.ld 2005-03-25 11:17:53.659756201 -0500
@@ -75,7 +75,7 @@ SECTIONS
.gcc_except_table : ONLY_IF_RO { KEEP (*(.gcc_except_table)) *(.gcc_except_table.*) }
/* Adjust the address for the data segment. We want to adjust up to
the same address within the page on the next page up. */
- . = ALIGN(256) + (. & (256 - 1));
+ . = ALIGN (0x8000) - ((0x8000 - .) & (0x8000 - 1)); . = DATA_SEGMENT_ALIGN (0x8000, 0x1000);
/* Exception handling */
.eh_frame : ONLY_IF_RW { KEEP (*(.eh_frame)) }
.gcc_except_table : ONLY_IF_RW { KEEP (*(.gcc_except_table)) *(.gcc_except_table.*) }
Index: binutils/ld/testsuite/ld-arm/arm-dyn.ld
===================================================================
--- binutils.orig/ld/testsuite/ld-arm/arm-dyn.ld 2005-03-25 11:17:07.070898170 -0500
+++ binutils/ld/testsuite/ld-arm/arm-dyn.ld 2005-03-25 11:17:53.658756440 -0500
@@ -76,7 +76,7 @@ SECTIONS
.gcc_except_table : ONLY_IF_RO { KEEP (*(.gcc_except_table)) *(.gcc_except_table.*) }
/* Adjust the address for the data segment. We want to adjust up to
the same address within the page on the next page up. */
- . = ALIGN(256) + (. & (256 - 1));
+ . = ALIGN (0x8000) - ((0x8000 - .) & (0x8000 - 1)); . = DATA_SEGMENT_ALIGN (0x8000, 0x1000);
/* Exception handling */
.eh_frame : ONLY_IF_RW { KEEP (*(.eh_frame)) }
.gcc_except_table : ONLY_IF_RW { KEEP (*(.gcc_except_table)) *(.gcc_except_table.*) }
^ permalink raw reply [flat|nested] 3+ messages in thread
* Re: ARM: Support for TLS relocations
2005-03-26 12:16 ARM: Support for TLS relocations Daniel Jacobowitz
@ 2005-03-29 16:38 ` Richard Earnshaw
2005-03-29 21:11 ` Daniel Jacobowitz
0 siblings, 1 reply; 3+ messages in thread
From: Richard Earnshaw @ 2005-03-29 16:38 UTC (permalink / raw)
To: Daniel Jacobowitz; +Cc: binutils
On Fri, 2005-03-25 at 16:53, Daniel Jacobowitz wrote:
> This patch implements the ARM-documented TLS relocations, except for the
> twelve-bit instruction relocations. The first version was implemented by
> Phil, although I'm afraid he won't recognize much of it; mistakes all mine.
>
> The implemented relocations are, for the assembler:
> .word foo(tlsgd)
> .word foo(tlsldm)
> .word foo(tlsldo)
> .word foo(gottpoff)
> .word foo(tpoff)
>
> They support trailing addends, e.g. a typical usage:
> .word foo(tlsgd) + (. - .L2 + 8)
>
> No linker relaxations are supported; the compiler's choice is final.
> Dynamic relocations are avoided when unneeded, though.
>
> Tested on arm-linux, including NPTL with appropriate gcc/glibc patches.
> Is this OK for HEAD?
>
> [Full disclosure - I actually tested a different version of this patch,
> which used a different name for the IE32 relocation operator. After
> changing it to gottpoff I've started a new test cycle which is running now.]
I assume this has completed testing by now... and since you've said
nothing further that there weren't any problems.
This is OK provided it doesn't cause any failures for coff formats.
R.
^ permalink raw reply [flat|nested] 3+ messages in thread
* Re: ARM: Support for TLS relocations
2005-03-29 16:38 ` Richard Earnshaw
@ 2005-03-29 21:11 ` Daniel Jacobowitz
0 siblings, 0 replies; 3+ messages in thread
From: Daniel Jacobowitz @ 2005-03-29 21:11 UTC (permalink / raw)
To: binutils
On Tue, Mar 29, 2005 at 04:37:51PM +0100, Richard Earnshaw wrote:
> I assume this has completed testing by now... and since you've said
> nothing further that there weren't any problems.
Correct.
> This is OK provided it doesn't cause any failures for coff formats.
Thanks. I ran before and after test runs on arm-coff, and there were
no changes.
--
Daniel Jacobowitz
CodeSourcery, LLC
^ permalink raw reply [flat|nested] 3+ messages in thread
end of thread, other threads:[~2005-03-29 16:54 UTC | newest]
Thread overview: 3+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2005-03-26 12:16 ARM: Support for TLS relocations Daniel Jacobowitz
2005-03-29 16:38 ` Richard Earnshaw
2005-03-29 21:11 ` Daniel Jacobowitz
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).