* 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->symndx >= 0 ? e1->d.addend == e2->d.addend
&& (! e1->abfd ? e1->d.address == e2->d.address : e1->d.h == e2->d.h));
: e1->symndx >= 0 ? e1->d.addend == e2->d.addend
: 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);
} }
break;
got_offset += 2 * MIPS_ELF_GOT_SIZE (abfd); 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,51 +3203,45 @@ 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);
if (tls_gottprel_reloc_p (r_type))
{
BFD_ASSERT (*tls_type & GOT_TLS_IE);
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))
{
BFD_ASSERT (*tls_type & GOT_TLS_GD);
return got_index;
}
if (tls_ldm_reloc_p (r_type))
{
BFD_ASSERT (*tls_type & GOT_TLS_LDM);
return got_index;
}
return got_index; 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))
return mips_tls_got_index (abfd, h->tls_ie_got_offset, &h->tls_ie_type,
info, h, symbol);
if (tls_gd_reloc_p (r_type))
return mips_tls_got_index (abfd, h->tls_gd_got_offset, &h->tls_gd_type,
info, h, symbol);
abort ();
}
/* Return the offset from _GLOBAL_OFFSET_TABLE_ of the .got.plt entry /* Return the offset from _GLOBAL_OFFSET_TABLE_ of the .got.plt entry
for global symbol H. .got.plt comes before the GOT, so the offset for global symbol H. .got.plt comes before the GOT, so the offset
will be negative. */ will be negative. */
@ -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)
{ return TRUE;
(*loc)->tls_type |= tls_flag;
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)
{ return TRUE;
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;
}
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)
return 1; {
entry->d.h->tls_type |= GOT_TLS_OFFSET_DONE; if (entry->d.h->tls_ie_type & GOT_TLS_OFFSET_DONE)
entry->d.h->tls_got_offset = next_index; return 1;
tls_type = entry->d.h->tls_type; entry->d.h->tls_ie_type |= GOT_TLS_OFFSET_DONE;
entry->d.h->tls_ie_got_offset = next_index;
}
else
{
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 else
{ {
if (entry->tls_type & GOT_TLS_LDM) 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. */
{ if (h != NULL)
unsigned char flag; {
if (!mips_elf_record_global_got_symbol (h, abfd, info,
flag = (tls_gd_reloc_p (r_type) FALSE, r_type))
? GOT_TLS_GD return FALSE;
: tls_ldm_reloc_p (r_type) ? GOT_TLS_LDM : GOT_TLS_IE); }
if (h != NULL) else
{ {
struct mips_elf_link_hash_entry *hmips = if (!mips_elf_record_local_got_symbol (abfd, r_symndx,
(struct mips_elf_link_hash_entry *) h; rel->r_addend,
hmips->tls_type |= flag; info, r_type))
return FALSE;
if (h && !mips_elf_record_global_got_symbol (h, abfd, info, }
FALSE, flag))
return FALSE;
}
else
{
BFD_ASSERT (flag == GOT_TLS_LDM || r_symndx != STN_UNDEF);
if (!mips_elf_record_local_got_symbol (abfd, r_symndx,
rel->r_addend,
info, flag))
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