* elfxx-mips.c (mips_got_entry): Update comment above tls_type entry
	to say that each structure represents only one type of TLS reference.
	(GOT_TLS_TYPE): New define.
	(mips_elf_link_hash_entry): Temporarily split tls_type and
	tls_got_offset into two variables each.
	(mips_elf_link_hash_newfunc): Update accordingly.
	(mips_elf_got_entry_eq, mips_elf_got_entry_hash)
	(mips_elf_multi_got_entry_eq): Require the tls_type to be the same.
	(mips_elf_reloc_tls_type, mips_tls_got_entries): New functions.
	(mips_tls_got_relocs): Use a switch statement.
	(mips_elf_count_global_tls_entries): Handle the new hash entry fields.
	(mips_elf_initialize_tls_slots): Use a switch statement.  Avoid
	local "offset" variable.
	(mips_tls_got_index): Remove r_type argument and assert.  Remove
	code that handled entries with two TLS types; always use the
	original got_index instead.
	(mips_tls_single_got_index): New function.
	(mips_elf_local_got_index): Use entry->tls_type to check for
	TLS entries.  Use mips_tls_single_got_index.  Update call to
	mips_tls_got_index.
	(mips_elf_global_got_index): Use mips_elf_reloc_tls_type.
	Use p->tls_type to check for TLS entries.  Update call to
	mips_tls_got_index.  Use mips_tls_single_got_index.
	(mips_elf_create_local_got_entry): Use mips_elf_reloc_tls_type.
	Use entry.tls_type to check for TLS entries.
	(mips_elf_record_global_got_symbol): Replace tls_flag argument
	with r_type argument.  Use mips_elf_reloc_tls_type.
	Set up the new hash entry fields.
	(mips_elf_record_local_got_symbol): Replace tls_flag argument
	with r_type argument.  Use mips_elf_reloc_tls_type and
	mips_tls_got_entries.  Remove code that handled entries
	with multiple TLS types.
	(mips_elf_make_got_per_bfd): Use mips_tls_got_entries.
	(mips_elf_initialize_tls_index): Handle new hash entry fields.
	Use equality rather than masks when checking for specific TLS types.
	Use mips_tls_got_entries.  Remove code that handled entries
	with multiple TLS types.
	(mips_elf_calculate_relocation): Use TLS_RELOC_P instead of
	testing the hash table entry.
	(_bfd_mips_elf_check_relocs): Update calls to
	mips_elf_record_global_got_symbol and mips_elf_record_local_got_symbol.
	(_bfd_mips_elf_finish_dynamic_symbol): Don't check h->type.
	(_bfd_mips_elf_copy_indirect_symbol): Handle new hash entry fields.
This commit is contained in:
Richard Sandiford
2013-02-11 17:54:16 +00:00
parent d9bf376d09
commit e641e783fb
2 changed files with 251 additions and 224 deletions

View File

@ -1,3 +1,49 @@
2013-02-11 Richard Sandiford <rdsandiford@googlemail.com>
* elfxx-mips.c (mips_got_entry): Update comment above tls_type entry
to say that each structure represents only one type of TLS reference.
(GOT_TLS_TYPE): New define.
(mips_elf_link_hash_entry): Temporarily split tls_type and
tls_got_offset into two variables each.
(mips_elf_link_hash_newfunc): Update accordingly.
(mips_elf_got_entry_eq, mips_elf_got_entry_hash)
(mips_elf_multi_got_entry_eq): Require the tls_type to be the same.
(mips_elf_reloc_tls_type, mips_tls_got_entries): New functions.
(mips_tls_got_relocs): Use a switch statement.
(mips_elf_count_global_tls_entries): Handle the new hash entry fields.
(mips_elf_initialize_tls_slots): Use a switch statement. Avoid
local "offset" variable.
(mips_tls_got_index): Remove r_type argument and assert. Remove
code that handled entries with two TLS types; always use the
original got_index instead.
(mips_tls_single_got_index): New function.
(mips_elf_local_got_index): Use entry->tls_type to check for
TLS entries. Use mips_tls_single_got_index. Update call to
mips_tls_got_index.
(mips_elf_global_got_index): Use mips_elf_reloc_tls_type.
Use p->tls_type to check for TLS entries. Update call to
mips_tls_got_index. Use mips_tls_single_got_index.
(mips_elf_create_local_got_entry): Use mips_elf_reloc_tls_type.
Use entry.tls_type to check for TLS entries.
(mips_elf_record_global_got_symbol): Replace tls_flag argument
with r_type argument. Use mips_elf_reloc_tls_type.
Set up the new hash entry fields.
(mips_elf_record_local_got_symbol): Replace tls_flag argument
with r_type argument. Use mips_elf_reloc_tls_type and
mips_tls_got_entries. Remove code that handled entries
with multiple TLS types.
(mips_elf_make_got_per_bfd): Use mips_tls_got_entries.
(mips_elf_initialize_tls_index): Handle new hash entry fields.
Use equality rather than masks when checking for specific TLS types.
Use mips_tls_got_entries. Remove code that handled entries
with multiple TLS types.
(mips_elf_calculate_relocation): Use TLS_RELOC_P instead of
testing the hash table entry.
(_bfd_mips_elf_check_relocs): Update calls to
mips_elf_record_global_got_symbol and mips_elf_record_local_got_symbol.
(_bfd_mips_elf_finish_dynamic_symbol): Don't check h->type.
(_bfd_mips_elf_copy_indirect_symbol): Handle new hash entry fields.
2013-02-11 Richard Sandiford <rdsandiford@googlemail.com> 2013-02-11 Richard Sandiford <rdsandiford@googlemail.com>
* elfxx-mips.c (mips_elf_multi_got_entry_hash): Rename to... * elfxx-mips.c (mips_elf_multi_got_entry_hash): Rename to...

View File

@ -101,11 +101,9 @@ struct mips_got_entry
struct mips_elf_link_hash_entry *h; struct mips_elf_link_hash_entry *h;
} d; } d;
/* The TLS types included in this GOT entry (specifically, GD and /* The TLS type of this GOT entry: GOT_NORMAL, GOT_TLS_IE, GOT_TLS_GD
IE). The GD and IE flags can be added as we encounter new or GOT_TLS_LDM. An LDM GOT entry will be a local symbol entry with
relocations. LDM can also be set; it will always be alone, not r_symndx == 0. */
combined with any GD or IE flags. An LDM GOT entry will be
a local symbol entry with r_symndx == 0. */
unsigned char tls_type; unsigned char tls_type;
/* The offset from the beginning of the .got section to the entry /* The offset from the beginning of the .got section to the entry
@ -363,17 +361,18 @@ struct mips_elf_link_hash_entry
#define GOT_TLS_GD 1 #define GOT_TLS_GD 1
#define GOT_TLS_LDM 2 #define GOT_TLS_LDM 2
#define GOT_TLS_IE 4 #define GOT_TLS_IE 4
#define GOT_TLS_TYPE 7
#define GOT_TLS_OFFSET_DONE 0x40 #define GOT_TLS_OFFSET_DONE 0x40
#define GOT_TLS_DONE 0x80 #define GOT_TLS_DONE 0x80
unsigned char tls_type; unsigned char tls_ie_type;
unsigned char tls_gd_type;
/* This is only used in single-GOT mode; in multi-GOT mode there /* These fields are only used in single-GOT mode; in multi-GOT mode there
is one mips_got_entry per GOT entry, so the offset is stored is one mips_got_entry per GOT entry, so the offset is stored
there. In single-GOT mode there may be many mips_got_entry there. In single-GOT mode there may be many mips_got_entry
structures all referring to the same GOT slot. It might be structures all referring to the same GOT slot. */
possible to use root.got.offset instead, but that field is bfd_vma tls_ie_got_offset;
overloaded already. */ bfd_vma tls_gd_got_offset;
bfd_vma tls_got_offset;
/* The highest GGA_* value that satisfies all references to this symbol. */ /* The highest GGA_* value that satisfies all references to this symbol. */
unsigned int global_got_area : 2; unsigned int global_got_area : 2;
@ -1111,7 +1110,8 @@ mips_elf_link_hash_newfunc (struct bfd_hash_entry *entry,
ret->fn_stub = NULL; ret->fn_stub = NULL;
ret->call_stub = NULL; ret->call_stub = NULL;
ret->call_fp_stub = NULL; ret->call_fp_stub = NULL;
ret->tls_type = GOT_NORMAL; ret->tls_ie_type = GOT_NORMAL;
ret->tls_gd_type = GOT_NORMAL;
ret->global_got_area = GGA_NONE; ret->global_got_area = GGA_NONE;
ret->got_only_for_calls = TRUE; ret->got_only_for_calls = TRUE;
ret->readonly_reloc = FALSE; ret->readonly_reloc = FALSE;
@ -2799,14 +2799,12 @@ mips_elf_got_entry_eq (const void *entry1, const void *entry2)
const struct mips_got_entry *e1 = (struct mips_got_entry *)entry1; const struct mips_got_entry *e1 = (struct mips_got_entry *)entry1;
const struct mips_got_entry *e2 = (struct mips_got_entry *)entry2; const struct mips_got_entry *e2 = (struct mips_got_entry *)entry2;
/* An LDM entry can only match another LDM entry. */ return (e1->abfd == e2->abfd
if ((e1->tls_type ^ e2->tls_type) & GOT_TLS_LDM) && e1->symndx == e2->symndx
return 0; && (e1->tls_type & GOT_TLS_TYPE) == (e2->tls_type & GOT_TLS_TYPE)
&& (!e1->abfd ? e1->d.address == e2->d.address
return e1->abfd == e2->abfd && e1->symndx == e2->symndx
&& (! e1->abfd ? e1->d.address == e2->d.address
: e1->symndx >= 0 ? e1->d.addend == e2->d.addend : e1->symndx >= 0 ? e1->d.addend == e2->d.addend
: e1->d.h == e2->d.h); : e1->d.h == e2->d.h));
} }
/* multi_got_entries are still a match in the case of global objects, /* multi_got_entries are still a match in the case of global objects,
@ -2819,15 +2817,13 @@ mips_elf_got_entry_hash (const void *entry_)
{ {
const struct mips_got_entry *entry = (struct mips_got_entry *)entry_; const struct mips_got_entry *entry = (struct mips_got_entry *)entry_;
return entry->symndx return (entry->symndx
+ (! entry->abfd + (((entry->tls_type & GOT_TLS_TYPE) == GOT_TLS_LDM) << 18)
? mips_elf_hash_bfd_vma (entry->d.address) + ((entry->tls_type & GOT_TLS_TYPE) == GOT_TLS_LDM ? 0
: entry->symndx >= 0 : !entry->abfd ? mips_elf_hash_bfd_vma (entry->d.address)
? ((entry->tls_type & GOT_TLS_LDM) : entry->symndx >= 0 ? (entry->abfd->id
? (GOT_TLS_LDM << 17) + mips_elf_hash_bfd_vma (entry->d.addend))
: (entry->abfd->id : entry->d.h->root.root.root.hash));
+ mips_elf_hash_bfd_vma (entry->d.addend)))
: entry->d.h->root.root.root.hash);
} }
static int static int
@ -2836,19 +2832,13 @@ mips_elf_multi_got_entry_eq (const void *entry1, const void *entry2)
const struct mips_got_entry *e1 = (struct mips_got_entry *)entry1; const struct mips_got_entry *e1 = (struct mips_got_entry *)entry1;
const struct mips_got_entry *e2 = (struct mips_got_entry *)entry2; const struct mips_got_entry *e2 = (struct mips_got_entry *)entry2;
/* Any two LDM entries match. */ return (e1->symndx == e2->symndx
if (e1->tls_type & e2->tls_type & GOT_TLS_LDM) && (e1->tls_type & GOT_TLS_TYPE) == (e2->tls_type & GOT_TLS_TYPE)
return 1; && ((e1->tls_type & GOT_TLS_TYPE) == GOT_TLS_LDM ? TRUE
: !e1->abfd ? !e2->abfd && e1->d.address == e2->d.address
/* Nothing else matches an LDM entry. */ : e1->symndx >= 0 ? (e1->abfd == e2->abfd
if ((e1->tls_type ^ e2->tls_type) & GOT_TLS_LDM) && e1->d.addend == e2->d.addend)
return 0; : e2->abfd && e1->d.h == e2->d.h));
return e1->symndx == e2->symndx
&& (e1->symndx >= 0 ? e1->abfd == e2->abfd && e1->d.addend == e2->d.addend
: e1->abfd == NULL || e2->abfd == NULL
? e1->abfd == e2->abfd && e1->d.address == e2->d.address
: e1->d.h == e2->d.h);
} }
static hashval_t static hashval_t
@ -2931,6 +2921,43 @@ mips_elf_rel_dyn_section (struct bfd_link_info *info, bfd_boolean create_p)
return sreloc; return sreloc;
} }
/* Return the GOT_TLS_* type required by relocation type R_TYPE. */
static int
mips_elf_reloc_tls_type (unsigned int r_type)
{
if (tls_gd_reloc_p (r_type))
return GOT_TLS_GD;
if (tls_ldm_reloc_p (r_type))
return GOT_TLS_LDM;
if (tls_gottprel_reloc_p (r_type))
return GOT_TLS_IE;
return GOT_NORMAL;
}
/* Return the number of GOT slots needed for GOT TLS type TYPE. */
static int
mips_tls_got_entries (unsigned int type)
{
switch (type)
{
case GOT_TLS_GD:
case GOT_TLS_LDM:
return 2;
case GOT_TLS_IE:
return 1;
case GOT_NORMAL:
return 0;
}
abort ();
}
/* Count the number of relocations needed for a TLS GOT entry, with /* Count the number of relocations needed for a TLS GOT entry, with
access types from TLS_TYPE, and symbol H (or a local symbol if H access types from TLS_TYPE, and symbol H (or a local symbol if H
is NULL). */ is NULL). */
@ -2940,7 +2967,6 @@ mips_tls_got_relocs (struct bfd_link_info *info, unsigned char tls_type,
struct elf_link_hash_entry *h) struct elf_link_hash_entry *h)
{ {
int indx = 0; int indx = 0;
int ret = 0;
bfd_boolean need_relocs = FALSE; bfd_boolean need_relocs = FALSE;
bfd_boolean dyn = elf_hash_table (info)->dynamic_sections_created; bfd_boolean dyn = elf_hash_table (info)->dynamic_sections_created;
@ -2955,22 +2981,22 @@ mips_tls_got_relocs (struct bfd_link_info *info, unsigned char tls_type,
need_relocs = TRUE; need_relocs = TRUE;
if (!need_relocs) if (!need_relocs)
return FALSE; return 0;
if (tls_type & GOT_TLS_GD) switch (tls_type & GOT_TLS_TYPE)
{ {
ret++; case GOT_TLS_GD:
if (indx != 0) return indx != 0 ? 2 : 1;
ret++;
case GOT_TLS_IE:
return 1;
case GOT_TLS_LDM:
return info->shared ? 1 : 0;
default:
return 0;
} }
if (tls_type & GOT_TLS_IE)
ret++;
if ((tls_type & GOT_TLS_LDM) && info->shared)
ret++;
return ret;
} }
/* Count the number of TLS relocations required for the GOT entry in /* Count the number of TLS relocations required for the GOT entry in
@ -3002,9 +3028,9 @@ mips_elf_count_global_tls_entries (void *arg1, void *arg2)
|| hm->root.root.type == bfd_link_hash_warning) || hm->root.root.type == bfd_link_hash_warning)
return 1; return 1;
if (hm->tls_type & GOT_TLS_GD) if (hm->tls_gd_type)
arg->needed += 2; arg->needed += 2;
if (hm->tls_type & GOT_TLS_IE) if (hm->tls_ie_type)
arg->needed += 1; arg->needed += 1;
return 1; return 1;
@ -3024,7 +3050,8 @@ mips_elf_count_global_tls_relocs (void *arg1, void *arg2)
|| hm->root.root.type == bfd_link_hash_warning) || hm->root.root.type == bfd_link_hash_warning)
return 1; return 1;
arg->needed += mips_tls_got_relocs (arg->info, hm->tls_type, &hm->root); arg->needed += mips_tls_got_relocs (arg->info, hm->tls_ie_type, &hm->root);
arg->needed += mips_tls_got_relocs (arg->info, hm->tls_gd_type, &hm->root);
return 1; return 1;
} }
@ -3072,7 +3099,7 @@ mips_elf_initialize_tls_slots (bfd *abfd, bfd_vma got_offset,
struct mips_elf_link_hash_table *htab; struct mips_elf_link_hash_table *htab;
int indx; int indx;
asection *sreloc, *sgot; asection *sreloc, *sgot;
bfd_vma offset, offset2; bfd_vma got_offset2;
bfd_boolean need_relocs = FALSE; bfd_boolean need_relocs = FALSE;
htab = mips_elf_hash_table (info); htab = mips_elf_hash_table (info);
@ -3109,65 +3136,59 @@ mips_elf_initialize_tls_slots (bfd *abfd, bfd_vma got_offset,
/* Emit necessary relocations. */ /* Emit necessary relocations. */
sreloc = mips_elf_rel_dyn_section (info, FALSE); sreloc = mips_elf_rel_dyn_section (info, FALSE);
/* General Dynamic. */ switch (*tls_type_p & GOT_TLS_TYPE)
if (*tls_type_p & GOT_TLS_GD)
{ {
offset = got_offset; case GOT_TLS_GD:
offset2 = offset + MIPS_ELF_GOT_SIZE (abfd); /* General Dynamic. */
got_offset2 = got_offset + MIPS_ELF_GOT_SIZE (abfd);
if (need_relocs) if (need_relocs)
{ {
mips_elf_output_dynamic_relocation mips_elf_output_dynamic_relocation
(abfd, sreloc, sreloc->reloc_count++, indx, (abfd, sreloc, sreloc->reloc_count++, indx,
ABI_64_P (abfd) ? R_MIPS_TLS_DTPMOD64 : R_MIPS_TLS_DTPMOD32, ABI_64_P (abfd) ? R_MIPS_TLS_DTPMOD64 : R_MIPS_TLS_DTPMOD32,
sgot->output_offset + sgot->output_section->vma + offset); sgot->output_offset + sgot->output_section->vma + got_offset);
if (indx) if (indx)
mips_elf_output_dynamic_relocation mips_elf_output_dynamic_relocation
(abfd, sreloc, sreloc->reloc_count++, indx, (abfd, sreloc, sreloc->reloc_count++, indx,
ABI_64_P (abfd) ? R_MIPS_TLS_DTPREL64 : R_MIPS_TLS_DTPREL32, ABI_64_P (abfd) ? R_MIPS_TLS_DTPREL64 : R_MIPS_TLS_DTPREL32,
sgot->output_offset + sgot->output_section->vma + offset2); sgot->output_offset + sgot->output_section->vma + got_offset2);
else else
MIPS_ELF_PUT_WORD (abfd, value - dtprel_base (info), MIPS_ELF_PUT_WORD (abfd, value - dtprel_base (info),
sgot->contents + offset2); sgot->contents + got_offset2);
} }
else else
{ {
MIPS_ELF_PUT_WORD (abfd, 1, MIPS_ELF_PUT_WORD (abfd, 1,
sgot->contents + offset); sgot->contents + got_offset);
MIPS_ELF_PUT_WORD (abfd, value - dtprel_base (info), MIPS_ELF_PUT_WORD (abfd, value - dtprel_base (info),
sgot->contents + offset2); sgot->contents + got_offset2);
}
got_offset += 2 * MIPS_ELF_GOT_SIZE (abfd);
} }
break;
case GOT_TLS_IE:
/* Initial Exec model. */ /* Initial Exec model. */
if (*tls_type_p & GOT_TLS_IE)
{
offset = got_offset;
if (need_relocs) if (need_relocs)
{ {
if (indx == 0) if (indx == 0)
MIPS_ELF_PUT_WORD (abfd, value - elf_hash_table (info)->tls_sec->vma, MIPS_ELF_PUT_WORD (abfd, value - elf_hash_table (info)->tls_sec->vma,
sgot->contents + offset); sgot->contents + got_offset);
else else
MIPS_ELF_PUT_WORD (abfd, 0, MIPS_ELF_PUT_WORD (abfd, 0,
sgot->contents + offset); sgot->contents + got_offset);
mips_elf_output_dynamic_relocation mips_elf_output_dynamic_relocation
(abfd, sreloc, sreloc->reloc_count++, indx, (abfd, sreloc, sreloc->reloc_count++, indx,
ABI_64_P (abfd) ? R_MIPS_TLS_TPREL64 : R_MIPS_TLS_TPREL32, ABI_64_P (abfd) ? R_MIPS_TLS_TPREL64 : R_MIPS_TLS_TPREL32,
sgot->output_offset + sgot->output_section->vma + offset); sgot->output_offset + sgot->output_section->vma + got_offset);
} }
else else
MIPS_ELF_PUT_WORD (abfd, value - tprel_base (info), MIPS_ELF_PUT_WORD (abfd, value - tprel_base (info),
sgot->contents + offset); sgot->contents + got_offset);
} break;
if (*tls_type_p & GOT_TLS_LDM) case GOT_TLS_LDM:
{
/* The initial offset is zero, and the LD offsets will include the /* The initial offset is zero, and the LD offsets will include the
bias by DTP_OFFSET. */ bias by DTP_OFFSET. */
MIPS_ELF_PUT_WORD (abfd, 0, MIPS_ELF_PUT_WORD (abfd, 0,
@ -3182,49 +3203,43 @@ mips_elf_initialize_tls_slots (bfd *abfd, bfd_vma got_offset,
(abfd, sreloc, sreloc->reloc_count++, indx, (abfd, sreloc, sreloc->reloc_count++, indx,
ABI_64_P (abfd) ? R_MIPS_TLS_DTPMOD64 : R_MIPS_TLS_DTPMOD32, ABI_64_P (abfd) ? R_MIPS_TLS_DTPMOD64 : R_MIPS_TLS_DTPMOD32,
sgot->output_offset + sgot->output_section->vma + got_offset); sgot->output_offset + sgot->output_section->vma + got_offset);
break;
default:
abort ();
} }
*tls_type_p |= GOT_TLS_DONE; *tls_type_p |= GOT_TLS_DONE;
} }
/* Return the GOT index to use for a relocation of type R_TYPE against /* Return the GOT index to use for a relocation against H using the
a symbol accessed using TLS_TYPE models. The GOT entries for this TLS model in *TLS_TYPE. The GOT entries for this symbol/model
symbol in this GOT start at GOT_INDEX. This function initializes the combination start at GOT_INDEX into ABFD's GOT. This function
GOT entries and corresponding relocations. */ initializes the GOT entries and corresponding relocations. */
static bfd_vma static bfd_vma
mips_tls_got_index (bfd *abfd, bfd_vma got_index, unsigned char *tls_type, mips_tls_got_index (bfd *abfd, bfd_vma got_index, unsigned char *tls_type,
int r_type, struct bfd_link_info *info, struct bfd_link_info *info,
struct mips_elf_link_hash_entry *h, bfd_vma symbol) struct mips_elf_link_hash_entry *h, bfd_vma symbol)
{ {
BFD_ASSERT (tls_gottprel_reloc_p (r_type)
|| tls_gd_reloc_p (r_type)
|| tls_ldm_reloc_p (r_type));
mips_elf_initialize_tls_slots (abfd, got_index, tls_type, info, h, symbol); mips_elf_initialize_tls_slots (abfd, got_index, tls_type, info, h, symbol);
return got_index;
}
/* Return the GOT index to use for a relocation of type R_TYPE against H
in ABFD. */
static bfd_vma
mips_tls_single_got_index (bfd *abfd, int r_type, struct bfd_link_info *info,
struct mips_elf_link_hash_entry *h, bfd_vma symbol)
{
if (tls_gottprel_reloc_p (r_type)) if (tls_gottprel_reloc_p (r_type))
{ return mips_tls_got_index (abfd, h->tls_ie_got_offset, &h->tls_ie_type,
BFD_ASSERT (*tls_type & GOT_TLS_IE); info, h, symbol);
if (*tls_type & GOT_TLS_GD)
return got_index + 2 * MIPS_ELF_GOT_SIZE (abfd);
else
return got_index;
}
if (tls_gd_reloc_p (r_type)) if (tls_gd_reloc_p (r_type))
{ return mips_tls_got_index (abfd, h->tls_gd_got_offset, &h->tls_gd_type,
BFD_ASSERT (*tls_type & GOT_TLS_GD); info, h, symbol);
return got_index; abort ();
}
if (tls_ldm_reloc_p (r_type))
{
BFD_ASSERT (*tls_type & GOT_TLS_LDM);
return got_index;
}
return got_index;
} }
/* Return the offset from _GLOBAL_OFFSET_TABLE_ of the .got.plt entry /* Return the offset from _GLOBAL_OFFSET_TABLE_ of the .got.plt entry
@ -3284,16 +3299,15 @@ mips_elf_local_got_index (bfd *abfd, bfd *ibfd, struct bfd_link_info *info,
if (!entry) if (!entry)
return MINUS_ONE; return MINUS_ONE;
if (TLS_RELOC_P (r_type)) if (entry->tls_type)
{ {
if (entry->symndx == -1 && htab->got_info->next == NULL) if (entry->symndx == -1 && htab->got_info->next == NULL)
/* A type (3) entry in the single-GOT case. We use the symbol's /* A type (3) entry in the single-GOT case. We use the symbol's
hash table entry to track the index. */ hash table entry to track the index. */
return mips_tls_got_index (abfd, h->tls_got_offset, &h->tls_type, return mips_tls_single_got_index (abfd, r_type, info, h, value);
r_type, info, h, value);
else else
return mips_tls_got_index (abfd, entry->gotidx, &entry->tls_type, return mips_tls_got_index (abfd, entry->gotidx, &entry->tls_type,
r_type, info, h, value); info, h, value);
} }
else else
return entry->gotidx; return entry->gotidx;
@ -3326,13 +3340,13 @@ mips_elf_global_got_index (bfd *abfd, bfd *ibfd, struct elf_link_hash_entry *h,
e.abfd = ibfd; e.abfd = ibfd;
e.symndx = -1; e.symndx = -1;
e.d.h = (struct mips_elf_link_hash_entry *)h; e.d.h = (struct mips_elf_link_hash_entry *)h;
e.tls_type = 0; e.tls_type = mips_elf_reloc_tls_type (r_type);
p = htab_find (g->got_entries, &e); p = htab_find (g->got_entries, &e);
BFD_ASSERT (p->gotidx > 0); BFD_ASSERT (p && p->gotidx > 0);
if (TLS_RELOC_P (r_type)) if (p->tls_type)
{ {
bfd_vma value = MINUS_ONE; bfd_vma value = MINUS_ONE;
if ((h->root.type == bfd_link_hash_defined if ((h->root.type == bfd_link_hash_defined
@ -3342,7 +3356,7 @@ mips_elf_global_got_index (bfd *abfd, bfd *ibfd, struct elf_link_hash_entry *h,
+ h->root.u.def.section->output_offset + h->root.u.def.section->output_offset
+ h->root.u.def.section->output_section->vma); + h->root.u.def.section->output_section->vma);
return mips_tls_got_index (abfd, p->gotidx, &p->tls_type, r_type, return mips_tls_got_index (abfd, p->gotidx, &p->tls_type,
info, e.d.h, value); info, e.d.h, value);
} }
else else
@ -3366,8 +3380,7 @@ mips_elf_global_got_index (bfd *abfd, bfd *ibfd, struct elf_link_hash_entry *h,
+ h->root.u.def.section->output_offset + h->root.u.def.section->output_offset
+ h->root.u.def.section->output_section->vma); + h->root.u.def.section->output_section->vma);
got_index = mips_tls_got_index (abfd, hm->tls_got_offset, &hm->tls_type, got_index = mips_tls_single_got_index (abfd, r_type, info, hm, value);
r_type, info, hm, value);
} }
else else
{ {
@ -3483,7 +3496,7 @@ mips_elf_create_local_got_entry (bfd *abfd, struct bfd_link_info *info,
entry.abfd = NULL; entry.abfd = NULL;
entry.symndx = -1; entry.symndx = -1;
entry.d.address = value; entry.d.address = value;
entry.tls_type = 0; entry.tls_type = mips_elf_reloc_tls_type (r_type);
g = mips_elf_got_for_ibfd (htab->got_info, ibfd); g = mips_elf_got_for_ibfd (htab->got_info, ibfd);
if (g == NULL) if (g == NULL)
@ -3495,14 +3508,13 @@ mips_elf_create_local_got_entry (bfd *abfd, struct bfd_link_info *info,
/* This function shouldn't be called for symbols that live in the global /* This function shouldn't be called for symbols that live in the global
area of the GOT. */ area of the GOT. */
BFD_ASSERT (h == NULL || h->global_got_area == GGA_NONE); BFD_ASSERT (h == NULL || h->global_got_area == GGA_NONE);
if (TLS_RELOC_P (r_type)) if (entry.tls_type)
{ {
struct mips_got_entry *p; struct mips_got_entry *p;
entry.abfd = ibfd; entry.abfd = ibfd;
if (tls_ldm_reloc_p (r_type)) if (tls_ldm_reloc_p (r_type))
{ {
entry.tls_type = GOT_TLS_LDM;
entry.symndx = 0; entry.symndx = 0;
entry.d.addend = 0; entry.d.addend = 0;
} }
@ -3527,7 +3539,6 @@ mips_elf_create_local_got_entry (bfd *abfd, struct bfd_link_info *info,
return *loc; return *loc;
entry.gotidx = MIPS_ELF_GOT_SIZE (abfd) * g->assigned_gotno++; entry.gotidx = MIPS_ELF_GOT_SIZE (abfd) * g->assigned_gotno++;
entry.tls_type = 0;
*loc = (struct mips_got_entry *)bfd_alloc (abfd, sizeof entry); *loc = (struct mips_got_entry *)bfd_alloc (abfd, sizeof entry);
@ -3678,16 +3689,14 @@ mips_elf_sort_hash_table_f (struct mips_elf_link_hash_entry *h, void *data)
return TRUE; return TRUE;
} }
/* If H is a symbol that needs a global GOT entry, but has a dynamic /* ABFD has a GOT relocation of type R_TYPE against H. Reserve a GOT
symbol table index lower than any we've seen to date, record it for entry for it. FOR_CALL is true if the caller is only interested in
posterity. FOR_CALL is true if the caller is only interested in
using the GOT entry for calls. */ using the GOT entry for calls. */
static bfd_boolean static bfd_boolean
mips_elf_record_global_got_symbol (struct elf_link_hash_entry *h, mips_elf_record_global_got_symbol (struct elf_link_hash_entry *h,
bfd *abfd, struct bfd_link_info *info, bfd *abfd, struct bfd_link_info *info,
bfd_boolean for_call, bfd_boolean for_call, int r_type)
unsigned char tls_flag)
{ {
struct mips_elf_link_hash_table *htab; struct mips_elf_link_hash_table *htab;
struct mips_elf_link_hash_entry *hmips; struct mips_elf_link_hash_entry *hmips;
@ -3723,7 +3732,7 @@ mips_elf_record_global_got_symbol (struct elf_link_hash_entry *h,
entry.abfd = abfd; entry.abfd = abfd;
entry.symndx = -1; entry.symndx = -1;
entry.d.h = (struct mips_elf_link_hash_entry *) h; entry.d.h = (struct mips_elf_link_hash_entry *) h;
entry.tls_type = 0; entry.tls_type = mips_elf_reloc_tls_type (r_type);
loc = (struct mips_got_entry **) htab_find_slot (g->got_entries, &entry, loc = (struct mips_got_entry **) htab_find_slot (g->got_entries, &entry,
INSERT); INSERT);
@ -3731,10 +3740,7 @@ mips_elf_record_global_got_symbol (struct elf_link_hash_entry *h,
/* If we've already marked this entry as needing GOT space, we don't /* If we've already marked this entry as needing GOT space, we don't
need to do it again. */ need to do it again. */
if (*loc) if (*loc)
{
(*loc)->tls_type |= tls_flag;
return TRUE; return TRUE;
}
*loc = (struct mips_got_entry *)bfd_alloc (abfd, sizeof entry); *loc = (struct mips_got_entry *)bfd_alloc (abfd, sizeof entry);
@ -3742,23 +3748,25 @@ mips_elf_record_global_got_symbol (struct elf_link_hash_entry *h,
return FALSE; return FALSE;
entry.gotidx = -1; entry.gotidx = -1;
entry.tls_type = tls_flag;
memcpy (*loc, &entry, sizeof entry); memcpy (*loc, &entry, sizeof entry);
if (tls_flag == 0) if (entry.tls_type == GOT_NORMAL)
hmips->global_got_area = GGA_NORMAL; hmips->global_got_area = GGA_NORMAL;
else if (entry.tls_type == GOT_TLS_IE)
hmips->tls_ie_type = entry.tls_type;
else if (entry.tls_type == GOT_TLS_GD)
hmips->tls_gd_type = entry.tls_type;
return TRUE; return TRUE;
} }
/* Reserve space in G for a GOT entry containing the value of symbol /* ABFD has a GOT relocation of type R_TYPE against symbol SYMNDX + ADDEND,
SYMNDX in input bfd ABDF, plus ADDEND. */ where SYMNDX is a local symbol. Reserve a GOT entry for it. */
static bfd_boolean static bfd_boolean
mips_elf_record_local_got_symbol (bfd *abfd, long symndx, bfd_vma addend, mips_elf_record_local_got_symbol (bfd *abfd, long symndx, bfd_vma addend,
struct bfd_link_info *info, struct bfd_link_info *info, int r_type)
unsigned char tls_flag)
{ {
struct mips_elf_link_hash_table *htab; struct mips_elf_link_hash_table *htab;
struct mips_got_info *g; struct mips_got_info *g;
@ -3773,44 +3781,26 @@ mips_elf_record_local_got_symbol (bfd *abfd, long symndx, bfd_vma addend,
entry.abfd = abfd; entry.abfd = abfd;
entry.symndx = symndx; entry.symndx = symndx;
entry.d.addend = addend; entry.d.addend = addend;
entry.tls_type = tls_flag; entry.tls_type = mips_elf_reloc_tls_type (r_type);
loc = (struct mips_got_entry **) loc = (struct mips_got_entry **)
htab_find_slot (g->got_entries, &entry, INSERT); htab_find_slot (g->got_entries, &entry, INSERT);
if (*loc) if (*loc)
{
if (tls_flag == GOT_TLS_GD && !((*loc)->tls_type & GOT_TLS_GD))
{
g->tls_gotno += 2;
(*loc)->tls_type |= tls_flag;
}
else if (tls_flag == GOT_TLS_IE && !((*loc)->tls_type & GOT_TLS_IE))
{
g->tls_gotno += 1;
(*loc)->tls_type |= tls_flag;
}
return TRUE; return TRUE;
}
entry.gotidx = -1; entry.gotidx = -1;
if (tls_flag != 0) if (entry.tls_type)
{ {
entry.tls_type = tls_flag; if (entry.tls_type != GOT_TLS_LDM)
if (tls_flag == GOT_TLS_IE) g->tls_gotno += mips_tls_got_entries (entry.tls_type);
g->tls_gotno += 1;
else if (tls_flag == GOT_TLS_GD)
g->tls_gotno += 2;
else if (g->tls_ldm_offset == MINUS_ONE) else if (g->tls_ldm_offset == MINUS_ONE)
{ {
g->tls_ldm_offset = MINUS_TWO; g->tls_ldm_offset = MINUS_TWO;
g->tls_gotno += 2; g->tls_gotno += mips_tls_got_entries (entry.tls_type);
} }
} }
else else
{
g->local_gotno += 1; g->local_gotno += 1;
entry.tls_type = 0;
}
*loc = (struct mips_got_entry *)bfd_alloc (abfd, sizeof entry); *loc = (struct mips_got_entry *)bfd_alloc (abfd, sizeof entry);
@ -4204,16 +4194,11 @@ mips_elf_make_got_per_bfd (void **entryp, void *p)
*entryp = entry; *entryp = entry;
if (entry->tls_type) if (entry->tls_type)
{ g->tls_gotno += mips_tls_got_entries (entry->tls_type & GOT_TLS_TYPE);
if (entry->tls_type & (GOT_TLS_GD | GOT_TLS_LDM))
g->tls_gotno += 2;
if (entry->tls_type & GOT_TLS_IE)
g->tls_gotno += 1;
}
else if (entry->symndx >= 0 || entry->d.h->global_got_area == GGA_NONE) else if (entry->symndx >= 0 || entry->d.h->global_got_area == GGA_NONE)
++g->local_gotno; g->local_gotno += 1;
else else
++g->global_gotno; g->global_gotno += 1;
return 1; return 1;
} }
@ -4377,7 +4362,8 @@ mips_elf_initialize_tls_index (void **entryp, void *p)
unsigned char tls_type; unsigned char tls_type;
/* We're only interested in TLS symbols. */ /* We're only interested in TLS symbols. */
if (entry->tls_type == 0) tls_type = (entry->tls_type & GOT_TLS_TYPE);
if (tls_type == 0)
return 1; return 1;
next_index = MIPS_ELF_GOT_SIZE (entry->abfd) * (long) g->tls_assigned_gotno; next_index = MIPS_ELF_GOT_SIZE (entry->abfd) * (long) g->tls_assigned_gotno;
@ -4386,15 +4372,25 @@ mips_elf_initialize_tls_index (void **entryp, void *p)
{ {
/* A type (3) got entry in the single-GOT case. We use the symbol's /* A type (3) got entry in the single-GOT case. We use the symbol's
hash table entry to track its index. */ hash table entry to track its index. */
if (entry->d.h->tls_type & GOT_TLS_OFFSET_DONE) if (tls_type == GOT_TLS_IE)
{
if (entry->d.h->tls_ie_type & GOT_TLS_OFFSET_DONE)
return 1; return 1;
entry->d.h->tls_type |= GOT_TLS_OFFSET_DONE; entry->d.h->tls_ie_type |= GOT_TLS_OFFSET_DONE;
entry->d.h->tls_got_offset = next_index; entry->d.h->tls_ie_got_offset = next_index;
tls_type = entry->d.h->tls_type;
} }
else else
{ {
if (entry->tls_type & GOT_TLS_LDM) BFD_ASSERT (tls_type == GOT_TLS_GD);
if (entry->d.h->tls_gd_type & GOT_TLS_OFFSET_DONE)
return 1;
entry->d.h->tls_gd_type |= GOT_TLS_OFFSET_DONE;
entry->d.h->tls_gd_got_offset = next_index;
}
}
else
{
if (tls_type == GOT_TLS_LDM)
{ {
/* There are separate mips_got_entry objects for each input bfd /* There are separate mips_got_entry objects for each input bfd
that requires an LDM entry. Make sure that all LDM entries in that requires an LDM entry. Make sure that all LDM entries in
@ -4407,15 +4403,10 @@ mips_elf_initialize_tls_index (void **entryp, void *p)
g->tls_ldm_offset = next_index; g->tls_ldm_offset = next_index;
} }
entry->gotidx = next_index; entry->gotidx = next_index;
tls_type = entry->tls_type;
} }
/* Account for the entries we've just allocated. */ /* Account for the entries we've just allocated. */
if (tls_type & (GOT_TLS_GD | GOT_TLS_LDM)) g->tls_assigned_gotno += mips_tls_got_entries (tls_type);
g->tls_assigned_gotno += 2;
if (tls_type & GOT_TLS_IE)
g->tls_assigned_gotno += 1;
return 1; return 1;
} }
@ -5395,7 +5386,7 @@ mips_elf_calculate_relocation (bfd *abfd, bfd *input_bfd,
BFD_ASSERT (addend == 0); BFD_ASSERT (addend == 0);
g = mips_elf_global_got_index (dynobj, input_bfd, g = mips_elf_global_got_index (dynobj, input_bfd,
&h->root, r_type, info); &h->root, r_type, info);
if (h->tls_type == GOT_NORMAL if (!TLS_RELOC_P (r_type)
&& !elf_hash_table (info)->dynamic_sections_created) && !elf_hash_table (info)->dynamic_sections_created)
/* This is a static link. We must initialize the GOT entry. */ /* This is a static link. We must initialize the GOT entry. */
MIPS_ELF_PUT_WORD (dynobj, symbol, htab->sgot->contents + g); MIPS_ELF_PUT_WORD (dynobj, symbol, htab->sgot->contents + g);
@ -7983,7 +7974,7 @@ _bfd_mips_elf_check_relocs (bfd *abfd, struct bfd_link_info *info,
R_MIPS_CALL_HI16 because these are always followed by an R_MIPS_CALL_HI16 because these are always followed by an
R_MIPS_GOT_LO16 or R_MIPS_CALL_LO16. */ R_MIPS_GOT_LO16 or R_MIPS_CALL_LO16. */
if (!mips_elf_record_local_got_symbol (abfd, r_symndx, if (!mips_elf_record_local_got_symbol (abfd, r_symndx,
rel->r_addend, info, 0)) rel->r_addend, info, r_type))
return FALSE; return FALSE;
} }
@ -8016,7 +8007,8 @@ _bfd_mips_elf_check_relocs (bfd *abfd, struct bfd_link_info *info,
/* Make sure there is room in the regular GOT to hold the /* Make sure there is room in the regular GOT to hold the
function's address. We may eliminate it in favour of function's address. We may eliminate it in favour of
a .got.plt entry later; see mips_elf_count_got_symbols. */ a .got.plt entry later; see mips_elf_count_got_symbols. */
if (!mips_elf_record_global_got_symbol (h, abfd, info, TRUE, 0)) if (!mips_elf_record_global_got_symbol (h, abfd, info, TRUE,
r_type))
return FALSE; return FALSE;
/* We need a stub, not a plt entry for the undefined /* We need a stub, not a plt entry for the undefined
@ -8081,7 +8073,7 @@ _bfd_mips_elf_check_relocs (bfd *abfd, struct bfd_link_info *info,
case R_MIPS_GOT_DISP: case R_MIPS_GOT_DISP:
case R_MICROMIPS_GOT_DISP: case R_MICROMIPS_GOT_DISP:
if (h && !mips_elf_record_global_got_symbol (h, abfd, info, if (h && !mips_elf_record_global_got_symbol (h, abfd, info,
FALSE, 0)) FALSE, r_type))
return FALSE; return FALSE;
break; break;
@ -8107,32 +8099,19 @@ _bfd_mips_elf_check_relocs (bfd *abfd, struct bfd_link_info *info,
case R_MICROMIPS_TLS_GD: case R_MICROMIPS_TLS_GD:
/* This symbol requires a global offset table entry, or two /* This symbol requires a global offset table entry, or two
for TLS GD relocations. */ for TLS GD relocations. */
{
unsigned char flag;
flag = (tls_gd_reloc_p (r_type)
? GOT_TLS_GD
: tls_ldm_reloc_p (r_type) ? GOT_TLS_LDM : GOT_TLS_IE);
if (h != NULL) if (h != NULL)
{ {
struct mips_elf_link_hash_entry *hmips = if (!mips_elf_record_global_got_symbol (h, abfd, info,
(struct mips_elf_link_hash_entry *) h; FALSE, r_type))
hmips->tls_type |= flag;
if (h && !mips_elf_record_global_got_symbol (h, abfd, info,
FALSE, flag))
return FALSE; return FALSE;
} }
else else
{ {
BFD_ASSERT (flag == GOT_TLS_LDM || r_symndx != STN_UNDEF);
if (!mips_elf_record_local_got_symbol (abfd, r_symndx, if (!mips_elf_record_local_got_symbol (abfd, r_symndx,
rel->r_addend, rel->r_addend,
info, flag)) info, r_type))
return FALSE; return FALSE;
} }
}
break; break;
case R_MIPS_32: case R_MIPS_32:
@ -10036,7 +10015,7 @@ _bfd_mips_elf_finish_dynamic_symbol (bfd *output_bfd,
MIPS_ELF_PUT_WORD (output_bfd, value, sgot->contents + offset); MIPS_ELF_PUT_WORD (output_bfd, value, sgot->contents + offset);
} }
if (hmips->global_got_area != GGA_NONE && g->next && h->type != STT_TLS) if (hmips->global_got_area != GGA_NONE && g->next)
{ {
struct mips_got_entry e, *p; struct mips_got_entry e, *p;
bfd_vma entry; bfd_vma entry;
@ -11551,8 +11530,10 @@ _bfd_mips_elf_copy_indirect_symbol (struct bfd_link_info *info,
if (indmips->has_nonpic_branches) if (indmips->has_nonpic_branches)
dirmips->has_nonpic_branches = TRUE; dirmips->has_nonpic_branches = TRUE;
if (dirmips->tls_type == 0) if (dirmips->tls_ie_type == 0)
dirmips->tls_type = indmips->tls_type; dirmips->tls_ie_type = indmips->tls_ie_type;
if (dirmips->tls_gd_type == 0)
dirmips->tls_gd_type = indmips->tls_gd_type;
} }
#define PDR_SIZE 32 #define PDR_SIZE 32