* 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.
gas/
	* 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.
gas/testuite/
	* gas/arm/tls.s, gas/arm/tls.d: New files.
	* gas/arm/arm.exp: Run TLS test.
include/elf/
	* arm.h: Add TLS relocations.
ld/testsuite/
	* 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.
This commit is contained in:
Daniel Jacobowitz 2005-03-29 16:54:22 +00:00
parent 71a976dd82
commit ba93b8aced
23 changed files with 983 additions and 84 deletions

View File

@ -1,3 +1,41 @@
2005-03-29 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-29 Daniel Jacobowitz <dan@codesourcery.com>
* elf32-arm.c (elf32_arm_check_relocs): Increment count for all

View File

@ -2691,6 +2691,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. */

View File

@ -294,49 +294,49 @@ static reloc_howto_type elf32_arm_howto_table[] =
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_table[] =
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 r_type)
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 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_hash_entry * entry,
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 struct elf_backend_data *bed,
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 struct elf_backend_data *bed,
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 *abfd)
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_link_hash_table * globals,
#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_howto_type * howto,
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 * output_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 * output_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 * output_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 * output_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 * sec,
/* 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 * abfd ATTRIBUTE_UNUSED,
#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 * abfd ATTRIBUTE_UNUSED,
}
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 * abfd ATTRIBUTE_UNUSED,
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, struct bfd_link_info *info,
#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, struct bfd_link_info *info,
#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, struct bfd_link_info *info,
*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 bfd_link_info * info,
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_entry *h, void * inf)
{
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_entry *h, void * inf)
{
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_entry *h, void * inf)
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 * output_bfd ATTRIBUTE_UNUSED,
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 * output_bfd ATTRIBUTE_UNUSED,
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 * output_bfd ATTRIBUTE_UNUSED,
}
}
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 * output_bfd, struct bfd_link_info * info,
}
}
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;
@ -5754,6 +6345,8 @@ const struct elf_size_info elf32_arm_size_info = {
#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

View File

@ -1177,6 +1177,14 @@ static const char *const bfd_reloc_code_real_names[] = { "@@uninitialized@@",
"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",

View File

@ -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.

View File

@ -1,3 +1,12 @@
2005-03-29 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-29 Julian Brown <julian@codesourcery.com>
* config/tc-arm.c (marked_pr_dependency): New bitmap, bit N indicates

View File

@ -4881,6 +4881,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
};
@ -12224,6 +12229,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:
@ -12547,6 +12560,18 @@ tc_gen_reloc (asection * section ATTRIBUTE_UNUSED,
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
@ -13843,6 +13868,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;
@ -13898,8 +13928,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 == '('
@ -13913,9 +13947,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);
}

View File

@ -1,3 +1,8 @@
2005-03-29 Daniel Jacobowitz <dan@codesourcery.com>
* gas/arm/tls.s, gas/arm/tls.d: New files.
* gas/arm/arm.exp: Run TLS test.
2005-03-28 H.J. Lu <hongjiu.lu@intel.com>
PR 803

View File

@ -72,6 +72,8 @@ if {[istarget *arm*-*-*] || [istarget "xscale-*-*"]} then {
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 {

View File

@ -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

View File

@ -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)

View File

@ -1,3 +1,8 @@
2005-03-29 Daniel Jacobowitz <dan@codesourcery.com>
Phil Blundell <philb@gnu.org>
* arm.h: Add TLS relocations.
2005-03-23 Ben Elliston <bje@au.ibm.com>
* dwarf.h: Merge with GCC's dwarf.h.

View File

@ -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 */

View File

@ -1,3 +1,11 @@
2005-03-29 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.
2005-03-28 H.J. Lu <hongjiu.lu@intel.com>
PR 803

View File

@ -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.*) }

View File

@ -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

View File

@ -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.*) }

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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