bfd/
* 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:
parent
d9bf376d09
commit
e641e783fb
@ -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>
|
||||
|
||||
* elfxx-mips.c (mips_elf_multi_got_entry_hash): Rename to...
|
||||
|
429
bfd/elfxx-mips.c
429
bfd/elfxx-mips.c
@ -101,11 +101,9 @@ struct mips_got_entry
|
||||
struct mips_elf_link_hash_entry *h;
|
||||
} d;
|
||||
|
||||
/* The TLS types included in this GOT entry (specifically, GD and
|
||||
IE). The GD and IE flags can be added as we encounter new
|
||||
relocations. LDM can also be set; it will always be alone, not
|
||||
combined with any GD or IE flags. An LDM GOT entry will be
|
||||
a local symbol entry with r_symndx == 0. */
|
||||
/* The TLS type of this GOT entry: GOT_NORMAL, GOT_TLS_IE, GOT_TLS_GD
|
||||
or GOT_TLS_LDM. An LDM GOT entry will be a local symbol entry with
|
||||
r_symndx == 0. */
|
||||
unsigned char tls_type;
|
||||
|
||||
/* 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_LDM 2
|
||||
#define GOT_TLS_IE 4
|
||||
#define GOT_TLS_TYPE 7
|
||||
#define GOT_TLS_OFFSET_DONE 0x40
|
||||
#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
|
||||
there. In single-GOT mode there may be many mips_got_entry
|
||||
structures all referring to the same GOT slot. It might be
|
||||
possible to use root.got.offset instead, but that field is
|
||||
overloaded already. */
|
||||
bfd_vma tls_got_offset;
|
||||
structures all referring to the same GOT slot. */
|
||||
bfd_vma tls_ie_got_offset;
|
||||
bfd_vma tls_gd_got_offset;
|
||||
|
||||
/* The highest GGA_* value that satisfies all references to this symbol. */
|
||||
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->call_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->got_only_for_calls = TRUE;
|
||||
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 *e2 = (struct mips_got_entry *)entry2;
|
||||
|
||||
/* An LDM entry can only match another LDM entry. */
|
||||
if ((e1->tls_type ^ e2->tls_type) & GOT_TLS_LDM)
|
||||
return 0;
|
||||
|
||||
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->d.h == e2->d.h);
|
||||
return (e1->abfd == e2->abfd
|
||||
&& e1->symndx == e2->symndx
|
||||
&& (e1->tls_type & GOT_TLS_TYPE) == (e2->tls_type & GOT_TLS_TYPE)
|
||||
&& (!e1->abfd ? e1->d.address == e2->d.address
|
||||
: 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,
|
||||
@ -2819,15 +2817,13 @@ mips_elf_got_entry_hash (const void *entry_)
|
||||
{
|
||||
const struct mips_got_entry *entry = (struct mips_got_entry *)entry_;
|
||||
|
||||
return entry->symndx
|
||||
+ (! entry->abfd
|
||||
? mips_elf_hash_bfd_vma (entry->d.address)
|
||||
: entry->symndx >= 0
|
||||
? ((entry->tls_type & GOT_TLS_LDM)
|
||||
? (GOT_TLS_LDM << 17)
|
||||
: (entry->abfd->id
|
||||
+ mips_elf_hash_bfd_vma (entry->d.addend)))
|
||||
: entry->d.h->root.root.root.hash);
|
||||
return (entry->symndx
|
||||
+ (((entry->tls_type & GOT_TLS_TYPE) == GOT_TLS_LDM) << 18)
|
||||
+ ((entry->tls_type & GOT_TLS_TYPE) == GOT_TLS_LDM ? 0
|
||||
: !entry->abfd ? mips_elf_hash_bfd_vma (entry->d.address)
|
||||
: entry->symndx >= 0 ? (entry->abfd->id
|
||||
+ mips_elf_hash_bfd_vma (entry->d.addend))
|
||||
: entry->d.h->root.root.root.hash));
|
||||
}
|
||||
|
||||
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 *e2 = (struct mips_got_entry *)entry2;
|
||||
|
||||
/* Any two LDM entries match. */
|
||||
if (e1->tls_type & e2->tls_type & GOT_TLS_LDM)
|
||||
return 1;
|
||||
|
||||
/* Nothing else matches an LDM entry. */
|
||||
if ((e1->tls_type ^ e2->tls_type) & GOT_TLS_LDM)
|
||||
return 0;
|
||||
|
||||
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);
|
||||
return (e1->symndx == e2->symndx
|
||||
&& (e1->tls_type & GOT_TLS_TYPE) == (e2->tls_type & GOT_TLS_TYPE)
|
||||
&& ((e1->tls_type & GOT_TLS_TYPE) == GOT_TLS_LDM ? TRUE
|
||||
: !e1->abfd ? !e2->abfd && e1->d.address == e2->d.address
|
||||
: e1->symndx >= 0 ? (e1->abfd == e2->abfd
|
||||
&& e1->d.addend == e2->d.addend)
|
||||
: e2->abfd && e1->d.h == e2->d.h));
|
||||
}
|
||||
|
||||
static hashval_t
|
||||
@ -2931,6 +2921,43 @@ mips_elf_rel_dyn_section (struct bfd_link_info *info, bfd_boolean create_p)
|
||||
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
|
||||
access types from TLS_TYPE, and symbol H (or a local symbol if H
|
||||
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)
|
||||
{
|
||||
int indx = 0;
|
||||
int ret = 0;
|
||||
bfd_boolean need_relocs = FALSE;
|
||||
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;
|
||||
|
||||
if (!need_relocs)
|
||||
return FALSE;
|
||||
return 0;
|
||||
|
||||
if (tls_type & GOT_TLS_GD)
|
||||
switch (tls_type & GOT_TLS_TYPE)
|
||||
{
|
||||
ret++;
|
||||
if (indx != 0)
|
||||
ret++;
|
||||
case GOT_TLS_GD:
|
||||
return indx != 0 ? 2 : 1;
|
||||
|
||||
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
|
||||
@ -3002,9 +3028,9 @@ mips_elf_count_global_tls_entries (void *arg1, void *arg2)
|
||||
|| hm->root.root.type == bfd_link_hash_warning)
|
||||
return 1;
|
||||
|
||||
if (hm->tls_type & GOT_TLS_GD)
|
||||
if (hm->tls_gd_type)
|
||||
arg->needed += 2;
|
||||
if (hm->tls_type & GOT_TLS_IE)
|
||||
if (hm->tls_ie_type)
|
||||
arg->needed += 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)
|
||||
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;
|
||||
}
|
||||
@ -3072,7 +3099,7 @@ mips_elf_initialize_tls_slots (bfd *abfd, bfd_vma got_offset,
|
||||
struct mips_elf_link_hash_table *htab;
|
||||
int indx;
|
||||
asection *sreloc, *sgot;
|
||||
bfd_vma offset, offset2;
|
||||
bfd_vma got_offset2;
|
||||
bfd_boolean need_relocs = FALSE;
|
||||
|
||||
htab = mips_elf_hash_table (info);
|
||||
@ -3109,65 +3136,59 @@ mips_elf_initialize_tls_slots (bfd *abfd, bfd_vma got_offset,
|
||||
/* Emit necessary relocations. */
|
||||
sreloc = mips_elf_rel_dyn_section (info, FALSE);
|
||||
|
||||
/* General Dynamic. */
|
||||
if (*tls_type_p & GOT_TLS_GD)
|
||||
switch (*tls_type_p & GOT_TLS_TYPE)
|
||||
{
|
||||
offset = got_offset;
|
||||
offset2 = offset + MIPS_ELF_GOT_SIZE (abfd);
|
||||
case GOT_TLS_GD:
|
||||
/* General Dynamic. */
|
||||
got_offset2 = got_offset + MIPS_ELF_GOT_SIZE (abfd);
|
||||
|
||||
if (need_relocs)
|
||||
{
|
||||
mips_elf_output_dynamic_relocation
|
||||
(abfd, sreloc, sreloc->reloc_count++, indx,
|
||||
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)
|
||||
mips_elf_output_dynamic_relocation
|
||||
(abfd, sreloc, sreloc->reloc_count++, indx,
|
||||
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
|
||||
MIPS_ELF_PUT_WORD (abfd, value - dtprel_base (info),
|
||||
sgot->contents + offset2);
|
||||
sgot->contents + got_offset2);
|
||||
}
|
||||
else
|
||||
{
|
||||
MIPS_ELF_PUT_WORD (abfd, 1,
|
||||
sgot->contents + offset);
|
||||
sgot->contents + got_offset);
|
||||
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);
|
||||
}
|
||||
|
||||
/* Initial Exec model. */
|
||||
if (*tls_type_p & GOT_TLS_IE)
|
||||
{
|
||||
offset = got_offset;
|
||||
|
||||
case GOT_TLS_IE:
|
||||
/* Initial Exec model. */
|
||||
if (need_relocs)
|
||||
{
|
||||
if (indx == 0)
|
||||
MIPS_ELF_PUT_WORD (abfd, value - elf_hash_table (info)->tls_sec->vma,
|
||||
sgot->contents + offset);
|
||||
sgot->contents + got_offset);
|
||||
else
|
||||
MIPS_ELF_PUT_WORD (abfd, 0,
|
||||
sgot->contents + offset);
|
||||
sgot->contents + got_offset);
|
||||
|
||||
mips_elf_output_dynamic_relocation
|
||||
(abfd, sreloc, sreloc->reloc_count++, indx,
|
||||
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
|
||||
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
|
||||
bias by DTP_OFFSET. */
|
||||
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,
|
||||
ABI_64_P (abfd) ? R_MIPS_TLS_DTPMOD64 : R_MIPS_TLS_DTPMOD32,
|
||||
sgot->output_offset + sgot->output_section->vma + got_offset);
|
||||
break;
|
||||
|
||||
default:
|
||||
abort ();
|
||||
}
|
||||
|
||||
*tls_type_p |= GOT_TLS_DONE;
|
||||
}
|
||||
|
||||
/* Return the GOT index to use for a relocation of type R_TYPE against
|
||||
a symbol accessed using TLS_TYPE models. The GOT entries for this
|
||||
symbol in this GOT start at GOT_INDEX. This function initializes the
|
||||
GOT entries and corresponding relocations. */
|
||||
/* Return the GOT index to use for a relocation against H using the
|
||||
TLS model in *TLS_TYPE. The GOT entries for this symbol/model
|
||||
combination start at GOT_INDEX into ABFD's GOT. This function
|
||||
initializes the GOT entries and corresponding relocations. */
|
||||
|
||||
static bfd_vma
|
||||
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)
|
||||
{
|
||||
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);
|
||||
|
||||
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 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
|
||||
for global symbol H. .got.plt comes before the GOT, so the offset
|
||||
will be negative. */
|
||||
@ -3284,16 +3299,15 @@ mips_elf_local_got_index (bfd *abfd, bfd *ibfd, struct bfd_link_info *info,
|
||||
if (!entry)
|
||||
return MINUS_ONE;
|
||||
|
||||
if (TLS_RELOC_P (r_type))
|
||||
if (entry->tls_type)
|
||||
{
|
||||
if (entry->symndx == -1 && htab->got_info->next == NULL)
|
||||
/* A type (3) entry in the single-GOT case. We use the symbol's
|
||||
hash table entry to track the index. */
|
||||
return mips_tls_got_index (abfd, h->tls_got_offset, &h->tls_type,
|
||||
r_type, info, h, value);
|
||||
return mips_tls_single_got_index (abfd, r_type, info, h, value);
|
||||
else
|
||||
return mips_tls_got_index (abfd, entry->gotidx, &entry->tls_type,
|
||||
r_type, info, h, value);
|
||||
info, h, value);
|
||||
}
|
||||
else
|
||||
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.symndx = -1;
|
||||
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);
|
||||
|
||||
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;
|
||||
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_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);
|
||||
}
|
||||
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_section->vma);
|
||||
|
||||
got_index = mips_tls_got_index (abfd, hm->tls_got_offset, &hm->tls_type,
|
||||
r_type, info, hm, value);
|
||||
got_index = mips_tls_single_got_index (abfd, r_type, info, hm, value);
|
||||
}
|
||||
else
|
||||
{
|
||||
@ -3483,7 +3496,7 @@ mips_elf_create_local_got_entry (bfd *abfd, struct bfd_link_info *info,
|
||||
entry.abfd = NULL;
|
||||
entry.symndx = -1;
|
||||
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);
|
||||
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
|
||||
area of the GOT. */
|
||||
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;
|
||||
|
||||
entry.abfd = ibfd;
|
||||
if (tls_ldm_reloc_p (r_type))
|
||||
{
|
||||
entry.tls_type = GOT_TLS_LDM;
|
||||
entry.symndx = 0;
|
||||
entry.d.addend = 0;
|
||||
}
|
||||
@ -3527,7 +3539,6 @@ mips_elf_create_local_got_entry (bfd *abfd, struct bfd_link_info *info,
|
||||
return *loc;
|
||||
|
||||
entry.gotidx = MIPS_ELF_GOT_SIZE (abfd) * g->assigned_gotno++;
|
||||
entry.tls_type = 0;
|
||||
|
||||
*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;
|
||||
}
|
||||
|
||||
/* If H is a symbol that needs a global GOT entry, but has a dynamic
|
||||
symbol table index lower than any we've seen to date, record it for
|
||||
posterity. FOR_CALL is true if the caller is only interested in
|
||||
/* ABFD has a GOT relocation of type R_TYPE against H. Reserve a GOT
|
||||
entry for it. FOR_CALL is true if the caller is only interested in
|
||||
using the GOT entry for calls. */
|
||||
|
||||
static bfd_boolean
|
||||
mips_elf_record_global_got_symbol (struct elf_link_hash_entry *h,
|
||||
bfd *abfd, struct bfd_link_info *info,
|
||||
bfd_boolean for_call,
|
||||
unsigned char tls_flag)
|
||||
bfd_boolean for_call, int r_type)
|
||||
{
|
||||
struct mips_elf_link_hash_table *htab;
|
||||
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.symndx = -1;
|
||||
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,
|
||||
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
|
||||
need to do it again. */
|
||||
if (*loc)
|
||||
{
|
||||
(*loc)->tls_type |= tls_flag;
|
||||
return TRUE;
|
||||
}
|
||||
return TRUE;
|
||||
|
||||
*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;
|
||||
|
||||
entry.gotidx = -1;
|
||||
entry.tls_type = tls_flag;
|
||||
|
||||
memcpy (*loc, &entry, sizeof entry);
|
||||
|
||||
if (tls_flag == 0)
|
||||
if (entry.tls_type == GOT_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;
|
||||
}
|
||||
|
||||
/* Reserve space in G for a GOT entry containing the value of symbol
|
||||
SYMNDX in input bfd ABDF, plus ADDEND. */
|
||||
/* ABFD has a GOT relocation of type R_TYPE against symbol SYMNDX + ADDEND,
|
||||
where SYMNDX is a local symbol. Reserve a GOT entry for it. */
|
||||
|
||||
static bfd_boolean
|
||||
mips_elf_record_local_got_symbol (bfd *abfd, long symndx, bfd_vma addend,
|
||||
struct bfd_link_info *info,
|
||||
unsigned char tls_flag)
|
||||
struct bfd_link_info *info, int r_type)
|
||||
{
|
||||
struct mips_elf_link_hash_table *htab;
|
||||
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.symndx = symndx;
|
||||
entry.d.addend = addend;
|
||||
entry.tls_type = tls_flag;
|
||||
entry.tls_type = mips_elf_reloc_tls_type (r_type);
|
||||
loc = (struct mips_got_entry **)
|
||||
htab_find_slot (g->got_entries, &entry, INSERT);
|
||||
|
||||
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;
|
||||
if (tls_flag != 0)
|
||||
if (entry.tls_type)
|
||||
{
|
||||
entry.tls_type = tls_flag;
|
||||
if (tls_flag == GOT_TLS_IE)
|
||||
g->tls_gotno += 1;
|
||||
else if (tls_flag == GOT_TLS_GD)
|
||||
g->tls_gotno += 2;
|
||||
if (entry.tls_type != GOT_TLS_LDM)
|
||||
g->tls_gotno += mips_tls_got_entries (entry.tls_type);
|
||||
else if (g->tls_ldm_offset == MINUS_ONE)
|
||||
{
|
||||
g->tls_ldm_offset = MINUS_TWO;
|
||||
g->tls_gotno += 2;
|
||||
g->tls_gotno += mips_tls_got_entries (entry.tls_type);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
g->local_gotno += 1;
|
||||
entry.tls_type = 0;
|
||||
}
|
||||
g->local_gotno += 1;
|
||||
|
||||
*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;
|
||||
|
||||
if (entry->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;
|
||||
}
|
||||
g->tls_gotno += mips_tls_got_entries (entry->tls_type & GOT_TLS_TYPE);
|
||||
else if (entry->symndx >= 0 || entry->d.h->global_got_area == GGA_NONE)
|
||||
++g->local_gotno;
|
||||
g->local_gotno += 1;
|
||||
else
|
||||
++g->global_gotno;
|
||||
g->global_gotno += 1;
|
||||
|
||||
return 1;
|
||||
}
|
||||
@ -4377,7 +4362,8 @@ mips_elf_initialize_tls_index (void **entryp, void *p)
|
||||
unsigned char tls_type;
|
||||
|
||||
/* 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;
|
||||
|
||||
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
|
||||
hash table entry to track its index. */
|
||||
if (entry->d.h->tls_type & GOT_TLS_OFFSET_DONE)
|
||||
return 1;
|
||||
entry->d.h->tls_type |= GOT_TLS_OFFSET_DONE;
|
||||
entry->d.h->tls_got_offset = next_index;
|
||||
tls_type = entry->d.h->tls_type;
|
||||
if (tls_type == GOT_TLS_IE)
|
||||
{
|
||||
if (entry->d.h->tls_ie_type & GOT_TLS_OFFSET_DONE)
|
||||
return 1;
|
||||
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
|
||||
{
|
||||
if (entry->tls_type & GOT_TLS_LDM)
|
||||
if (tls_type == GOT_TLS_LDM)
|
||||
{
|
||||
/* There are separate mips_got_entry objects for each input bfd
|
||||
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;
|
||||
}
|
||||
entry->gotidx = next_index;
|
||||
tls_type = entry->tls_type;
|
||||
}
|
||||
|
||||
/* Account for the entries we've just allocated. */
|
||||
if (tls_type & (GOT_TLS_GD | GOT_TLS_LDM))
|
||||
g->tls_assigned_gotno += 2;
|
||||
if (tls_type & GOT_TLS_IE)
|
||||
g->tls_assigned_gotno += 1;
|
||||
|
||||
g->tls_assigned_gotno += mips_tls_got_entries (tls_type);
|
||||
return 1;
|
||||
}
|
||||
|
||||
@ -5395,7 +5386,7 @@ mips_elf_calculate_relocation (bfd *abfd, bfd *input_bfd,
|
||||
BFD_ASSERT (addend == 0);
|
||||
g = mips_elf_global_got_index (dynobj, input_bfd,
|
||||
&h->root, r_type, info);
|
||||
if (h->tls_type == GOT_NORMAL
|
||||
if (!TLS_RELOC_P (r_type)
|
||||
&& !elf_hash_table (info)->dynamic_sections_created)
|
||||
/* This is a static link. We must initialize the GOT entry. */
|
||||
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_GOT_LO16 or R_MIPS_CALL_LO16. */
|
||||
if (!mips_elf_record_local_got_symbol (abfd, r_symndx,
|
||||
rel->r_addend, info, 0))
|
||||
rel->r_addend, info, r_type))
|
||||
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
|
||||
function's address. We may eliminate it in favour of
|
||||
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;
|
||||
|
||||
/* 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_MICROMIPS_GOT_DISP:
|
||||
if (h && !mips_elf_record_global_got_symbol (h, abfd, info,
|
||||
FALSE, 0))
|
||||
FALSE, r_type))
|
||||
return FALSE;
|
||||
break;
|
||||
|
||||
@ -8107,32 +8099,19 @@ _bfd_mips_elf_check_relocs (bfd *abfd, struct bfd_link_info *info,
|
||||
case R_MICROMIPS_TLS_GD:
|
||||
/* This symbol requires a global offset table entry, or two
|
||||
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)
|
||||
{
|
||||
struct mips_elf_link_hash_entry *hmips =
|
||||
(struct mips_elf_link_hash_entry *) h;
|
||||
hmips->tls_type |= flag;
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
if (h != NULL)
|
||||
{
|
||||
if (!mips_elf_record_global_got_symbol (h, abfd, info,
|
||||
FALSE, r_type))
|
||||
return FALSE;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!mips_elf_record_local_got_symbol (abfd, r_symndx,
|
||||
rel->r_addend,
|
||||
info, r_type))
|
||||
return FALSE;
|
||||
}
|
||||
break;
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
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;
|
||||
bfd_vma entry;
|
||||
@ -11551,8 +11530,10 @@ _bfd_mips_elf_copy_indirect_symbol (struct bfd_link_info *info,
|
||||
if (indmips->has_nonpic_branches)
|
||||
dirmips->has_nonpic_branches = TRUE;
|
||||
|
||||
if (dirmips->tls_type == 0)
|
||||
dirmips->tls_type = indmips->tls_type;
|
||||
if (dirmips->tls_ie_type == 0)
|
||||
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
|
||||
|
Loading…
Reference in New Issue
Block a user