* elfxx-mips.c (mips_got_entry): Remove tls_ldm_offset.
	(mips_elf_link_hash_entry): Remove tls_ie_type, tls_gd_type,
	tls_ie_got_offset and tls_gd_got_offset.
	(mips_elf_link_hash_newfunc): Remove initialization.
	(mips_elf_create_got_info): Likewise.
	(mips_elf_count_local_got_entries, mips_elf_count_global_tls_entries)
	(mips_tls_single_got_index): Delete.
	(mips_elf_local_got_index): Always use the GOT entry to track
	GOT indices.
	(mips_elf_global_got_index): Likewise.
	(mips_elf_create_local_got_entry): Assert that TLS entries have
	already been allocated.
	(mips_elf_record_global_got_symbol): Don't initialize
	tls_ie_type or tls_gd_type.
	(mips_elf_count_got_symbols): Only count reloc-only GOT entries here.
	(mips_elf_initialize_tls_index): Allocate a GOT index for every TLS
	entry.
	(mips_elf_lay_out_got): Use mips_elf_count_got_entries to count
	the GOT entries.
	(_bfd_mips_elf_finish_dynamic_symbol): Assert that TLS GOT offsets
	have been allocated.
	(_bfd_mips_elf_copy_indirect_symbol): Remove handling of
	tls_ie_type and tls_gd_type.
This commit is contained in:
Richard Sandiford 2013-02-11 18:15:47 +00:00
parent ebc53538f7
commit 6c42ddb92b
2 changed files with 81 additions and 233 deletions

View File

@ -1,3 +1,29 @@
2013-02-11 Richard Sandiford <rdsandiford@googlemail.com>
* elfxx-mips.c (mips_got_entry): Remove tls_ldm_offset.
(mips_elf_link_hash_entry): Remove tls_ie_type, tls_gd_type,
tls_ie_got_offset and tls_gd_got_offset.
(mips_elf_link_hash_newfunc): Remove initialization.
(mips_elf_create_got_info): Likewise.
(mips_elf_count_local_got_entries, mips_elf_count_global_tls_entries)
(mips_tls_single_got_index): Delete.
(mips_elf_local_got_index): Always use the GOT entry to track
GOT indices.
(mips_elf_global_got_index): Likewise.
(mips_elf_create_local_got_entry): Assert that TLS entries have
already been allocated.
(mips_elf_record_global_got_symbol): Don't initialize
tls_ie_type or tls_gd_type.
(mips_elf_count_got_symbols): Only count reloc-only GOT entries here.
(mips_elf_initialize_tls_index): Allocate a GOT index for every TLS
entry.
(mips_elf_lay_out_got): Use mips_elf_count_got_entries to count
the GOT entries.
(_bfd_mips_elf_finish_dynamic_symbol): Assert that TLS GOT offsets
have been allocated.
(_bfd_mips_elf_copy_indirect_symbol): Remove handling of
tls_ie_type and tls_gd_type.
2013-02-11 Richard Sandiford <rdsandiford@googlemail.com> 2013-02-11 Richard Sandiford <rdsandiford@googlemail.com>
* elfxx-mips.c (mips_elf_create_local_got_entry): Tidy. Avoid * elfxx-mips.c (mips_elf_create_local_got_entry): Tidy. Avoid

View File

@ -89,6 +89,12 @@ struct mips_got_entry
/* The TLS type of this GOT entry: GOT_NORMAL, GOT_TLS_IE, GOT_TLS_GD /* 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 or GOT_TLS_LDM. An LDM GOT entry will be a local symbol entry with
r_symndx == 0. */ r_symndx == 0. */
#define GOT_NORMAL 0
#define GOT_TLS_GD 1
#define GOT_TLS_LDM 2
#define GOT_TLS_IE 4
#define GOT_TLS_TYPE 7
#define GOT_TLS_DONE 0x80
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
@ -149,11 +155,6 @@ struct mips_got_info
/* In multi-got links, a pointer to the next got (err, rather, most /* In multi-got links, a pointer to the next got (err, rather, most
of the time, it points to the previous got). */ of the time, it points to the previous got). */
struct mips_got_info *next; struct mips_got_info *next;
/* This is the GOT index of the TLS LDM entry for the GOT, MINUS_ONE
for none, or MINUS_TWO for not yet assigned. This is needed
because a single-GOT link may have multiple hash table entries
for the LDM. It does not get initialized in multi-GOT mode. */
bfd_vma tls_ldm_offset;
}; };
/* Structure passed when merging bfds' gots. */ /* Structure passed when merging bfds' gots. */
@ -321,23 +322,6 @@ struct mips_elf_link_hash_entry
being called returns a floating point value. */ being called returns a floating point value. */
asection *call_fp_stub; asection *call_fp_stub;
#define GOT_NORMAL 0
#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_ie_type;
unsigned char tls_gd_type;
/* 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. */
bfd_vma tls_ie_got_offset;
bfd_vma tls_gd_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;
@ -1075,8 +1059,6 @@ 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_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;
@ -2813,7 +2795,6 @@ mips_elf_create_got_info (bfd *abfd)
if (g == NULL) if (g == NULL)
return NULL; return NULL;
g->tls_ldm_offset = MINUS_ONE;
g->got_entries = htab_try_create (1, mips_elf_got_entry_hash, g->got_entries = htab_try_create (1, mips_elf_got_entry_hash,
mips_elf_got_entry_eq, NULL); mips_elf_got_entry_eq, NULL);
if (g->got_entries == NULL) if (g->got_entries == NULL)
@ -3013,63 +2994,6 @@ mips_elf_count_got_entries (void **entryp, void *data)
return 1; return 1;
} }
/* A htab_traverse callback. If *SLOT describes a GOT entry for a local
symbol, count the number of GOT entries and TLS relocations that it
requires. DATA points to a mips_elf_traverse_got_arg structure. */
static int
mips_elf_count_local_got_entries (void **entryp, void *data)
{
struct mips_got_entry *entry;
struct mips_elf_traverse_got_arg *arg;
entry = (struct mips_got_entry *) *entryp;
arg = (struct mips_elf_traverse_got_arg *) data;
if (entry->abfd != NULL && entry->symndx != -1)
{
if ((entry->tls_type & GOT_TLS_TYPE) == GOT_TLS_LDM)
{
if (arg->g->tls_ldm_offset == MINUS_TWO)
return 1;
arg->g->tls_ldm_offset = MINUS_TWO;
}
mips_elf_count_got_entry (arg->info, arg->g, entry);
}
return 1;
}
/* Count the number of TLS GOT entries and relocationss required for the
global (or forced-local) symbol in ARG1. */
static int
mips_elf_count_global_tls_entries (void *entry, void *data)
{
struct mips_elf_link_hash_entry *hm;
struct mips_elf_traverse_got_arg *arg;
hm = (struct mips_elf_link_hash_entry *) entry;
if (hm->root.root.type == bfd_link_hash_indirect
|| hm->root.root.type == bfd_link_hash_warning)
return 1;
arg = (struct mips_elf_traverse_got_arg *) data;
if (hm->tls_gd_type)
{
arg->g->tls_gotno += 2;
arg->g->relocs += mips_tls_got_relocs (arg->info, hm->tls_gd_type,
&hm->root);
}
if (hm->tls_ie_type)
{
arg->g->tls_gotno += 1;
arg->g->relocs += mips_tls_got_relocs (arg->info, hm->tls_ie_type,
&hm->root);
}
return 1;
}
/* Output a simple dynamic relocation into SRELOC. */ /* Output a simple dynamic relocation into SRELOC. */
static void static void
@ -3240,22 +3164,6 @@ mips_tls_got_index (bfd *abfd, bfd_vma got_index, unsigned char *tls_type,
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. */
@ -3314,15 +3222,8 @@ mips_elf_local_got_index (bfd *abfd, bfd *ibfd, struct bfd_link_info *info,
return MINUS_ONE; return MINUS_ONE;
if (entry->tls_type) if (entry->tls_type)
{ return mips_tls_got_index (abfd, entry->gotidx, &entry->tls_type,
if (entry->symndx == -1 && htab->got_info->next == NULL) info, h, value);
/* A type (3) entry in the single-GOT case. We use the symbol's
hash table entry to track the index. */
return mips_tls_single_got_index (abfd, r_type, info, h, value);
else
return mips_tls_got_index (abfd, entry->gotidx, &entry->tls_type,
info, h, value);
}
else else
return entry->gotidx; return entry->gotidx;
} }
@ -3366,54 +3267,31 @@ mips_elf_global_got_index (bfd *obfd, struct bfd_link_info *info, bfd *ibfd,
struct elf_link_hash_entry *h, int r_type) struct elf_link_hash_entry *h, int r_type)
{ {
struct mips_elf_link_hash_table *htab; struct mips_elf_link_hash_table *htab;
bfd_vma got_index; struct mips_got_info *g;
struct mips_got_info *g, *gg; struct mips_got_entry lookup, *entry;
bfd_vma gotidx;
htab = mips_elf_hash_table (info); htab = mips_elf_hash_table (info);
BFD_ASSERT (htab != NULL); BFD_ASSERT (htab != NULL);
gg = g = htab->got_info; g = mips_elf_bfd_got (ibfd, FALSE);
if (g->next && ibfd) BFD_ASSERT (g);
lookup.tls_type = mips_elf_reloc_tls_type (r_type);
if (!lookup.tls_type && g == mips_elf_bfd_got (obfd, FALSE))
return mips_elf_primary_global_got_index (obfd, info, h);
lookup.abfd = ibfd;
lookup.symndx = -1;
lookup.d.h = (struct mips_elf_link_hash_entry *) h;
entry = htab_find (g->got_entries, &lookup);
BFD_ASSERT (entry);
gotidx = entry->gotidx;
BFD_ASSERT (gotidx > 0 && gotidx < htab->sgot->size);
if (lookup.tls_type)
{ {
struct mips_got_entry e, *p;
BFD_ASSERT (h->dynindx >= 0);
g = mips_elf_bfd_got (ibfd, FALSE);
BFD_ASSERT (g);
if (g->next != gg || TLS_RELOC_P (r_type))
{
e.abfd = ibfd;
e.symndx = -1;
e.d.h = (struct mips_elf_link_hash_entry *)h;
e.tls_type = mips_elf_reloc_tls_type (r_type);
p = htab_find (g->got_entries, &e);
BFD_ASSERT (p && p->gotidx > 0);
if (p->tls_type)
{
bfd_vma value = MINUS_ONE;
if ((h->root.type == bfd_link_hash_defined
|| h->root.type == bfd_link_hash_defweak)
&& h->root.u.def.section->output_section)
value = (h->root.u.def.value
+ h->root.u.def.section->output_offset
+ h->root.u.def.section->output_section->vma);
return mips_tls_got_index (obfd, p->gotidx, &p->tls_type,
info, e.d.h, value);
}
else
return p->gotidx;
}
}
if (TLS_RELOC_P (r_type))
{
struct mips_elf_link_hash_entry *hm
= (struct mips_elf_link_hash_entry *) h;
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
@ -3423,13 +3301,10 @@ mips_elf_global_got_index (bfd *obfd, struct bfd_link_info *info, bfd *ibfd,
+ 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_single_got_index (obfd, r_type, info, hm, value); return mips_tls_got_index (obfd, gotidx, &entry->tls_type,
info, lookup.d.h, value);
} }
else return gotidx;
got_index = mips_elf_primary_global_got_index (obfd, info, h);
BFD_ASSERT (got_index < htab->sgot->size);
return got_index;
} }
/* Find a GOT page entry that points to within 32KB of VALUE. These /* Find a GOT page entry that points to within 32KB of VALUE. These
@ -3525,6 +3400,7 @@ mips_elf_create_local_got_entry (bfd *abfd, struct bfd_link_info *info,
void **loc; void **loc;
struct mips_got_info *g; struct mips_got_info *g;
struct mips_elf_link_hash_table *htab; struct mips_elf_link_hash_table *htab;
bfd_vma gotidx;
htab = mips_elf_hash_table (info); htab = mips_elf_hash_table (info);
BFD_ASSERT (htab != NULL); BFD_ASSERT (htab != NULL);
@ -3563,6 +3439,9 @@ mips_elf_create_local_got_entry (bfd *abfd, struct bfd_link_info *info,
entry = (struct mips_got_entry *) htab_find (g->got_entries, &lookup); entry = (struct mips_got_entry *) htab_find (g->got_entries, &lookup);
BFD_ASSERT (entry); BFD_ASSERT (entry);
gotidx = entry->gotidx;
BFD_ASSERT (gotidx > 0 && gotidx < htab->sgot->size);
return entry; return entry;
} }
@ -3811,10 +3690,6 @@ mips_elf_record_global_got_symbol (struct elf_link_hash_entry *h,
tls_type = mips_elf_reloc_tls_type (r_type); tls_type = mips_elf_reloc_tls_type (r_type);
if (tls_type == GOT_NORMAL && hmips->global_got_area > GGA_NORMAL) if (tls_type == GOT_NORMAL && hmips->global_got_area > GGA_NORMAL)
hmips->global_got_area = GGA_NORMAL; hmips->global_got_area = GGA_NORMAL;
else if (tls_type == GOT_TLS_IE && hmips->tls_ie_type == 0)
hmips->tls_ie_type = tls_type;
else if (tls_type == GOT_TLS_GD && hmips->tls_gd_type == 0)
hmips->tls_gd_type = tls_type;
entry.abfd = abfd; entry.abfd = abfd;
entry.symndx = -1; entry.symndx = -1;
@ -4108,9 +3983,11 @@ mips_elf_resolve_final_got_entries (struct mips_got_info *g)
return TRUE; return TRUE;
} }
/* A mips_elf_link_hash_traverse callback for which DATA points /* A mips_elf_link_hash_traverse callback for which DATA points to the
to the link_info structure. Count the number of type (3) entries link_info structure. Decide whether the hash entry needs an entry in
in the master GOT. */ the global part of the primary GOT, setting global_got_area accordingly.
Count the number of global symbols that are in the primary GOT only
because they have relocations against them (reloc_only_gotno). */
static int static int
mips_elf_count_got_symbols (struct mips_elf_link_hash_entry *h, void *data) mips_elf_count_got_symbols (struct mips_elf_link_hash_entry *h, void *data)
@ -4137,14 +4014,10 @@ mips_elf_count_got_symbols (struct mips_elf_link_hash_entry *h, void *data)
|| (h->got_only_for_calls || (h->got_only_for_calls
? SYMBOL_CALLS_LOCAL (info, &h->root) ? SYMBOL_CALLS_LOCAL (info, &h->root)
: SYMBOL_REFERENCES_LOCAL (info, &h->root))) : SYMBOL_REFERENCES_LOCAL (info, &h->root)))
{ /* The symbol belongs in the local GOT. We no longer need this
/* The symbol belongs in the local GOT. We no longer need this entry if it was only used for relocations; those relocations
entry if it was only used for relocations; those relocations will be against the null or section symbol instead of H. */
will be against the null or section symbol instead of H. */ h->global_got_area = GGA_NONE;
if (h->global_got_area != GGA_RELOC_ONLY)
g->local_gotno++;
h->global_got_area = GGA_NONE;
}
else if (htab->is_vxworks else if (htab->is_vxworks
&& h->got_only_for_calls && h->got_only_for_calls
&& h->root.plt.offset != MINUS_ONE) && h->root.plt.offset != MINUS_ONE)
@ -4152,11 +4025,10 @@ mips_elf_count_got_symbols (struct mips_elf_link_hash_entry *h, void *data)
they don't need entries in the regular GOT. .got.plt entries they don't need entries in the regular GOT. .got.plt entries
will be allocated by _bfd_mips_elf_adjust_dynamic_symbol. */ will be allocated by _bfd_mips_elf_adjust_dynamic_symbol. */
h->global_got_area = GGA_NONE; h->global_got_area = GGA_NONE;
else else if (h->global_got_area == GGA_RELOC_ONLY)
{ {
g->reloc_only_gotno++;
g->global_gotno++; g->global_gotno++;
if (h->global_got_area == GGA_RELOC_ONLY)
g->reloc_only_gotno++;
} }
} }
return 1; return 1;
@ -4367,8 +4239,6 @@ mips_elf_initialize_tls_index (void **entryp, void *data)
{ {
struct mips_got_entry *entry; struct mips_got_entry *entry;
struct mips_elf_traverse_got_arg *arg; struct mips_elf_traverse_got_arg *arg;
struct mips_got_info *g;
bfd_vma next_index;
unsigned char tls_type; unsigned char tls_type;
/* We're only interested in TLS symbols. */ /* We're only interested in TLS symbols. */
@ -4378,52 +4248,14 @@ mips_elf_initialize_tls_index (void **entryp, void *data)
return 1; return 1;
arg = (struct mips_elf_traverse_got_arg *) data; arg = (struct mips_elf_traverse_got_arg *) data;
g = arg->g; if (!mips_elf_set_gotidx (entryp, arg->value * arg->g->tls_assigned_gotno))
next_index = arg->value * g->tls_assigned_gotno;
if (entry->symndx == -1 && g->next == NULL)
{ {
/* A type (3) got entry in the single-GOT case. We use the symbol's arg->g = NULL;
hash table entry to track its index. */ return 0;
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 (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
a GOT resolve to the same index. */
if (g->tls_ldm_offset != MINUS_TWO && g->tls_ldm_offset != MINUS_ONE)
{
entry->gotidx = g->tls_ldm_offset;
return 1;
}
g->tls_ldm_offset = next_index;
}
if (!mips_elf_set_gotidx (entryp, next_index))
{
arg->g = NULL;
return 0;
}
} }
/* Account for the entries we've just allocated. */ /* Account for the entries we've just allocated. */
g->tls_assigned_gotno += mips_tls_got_entries (tls_type); arg->g->tls_assigned_gotno += mips_tls_got_entries (tls_type);
return 1; return 1;
} }
@ -8797,7 +8629,8 @@ mips_elf_lay_out_got (bfd *output_bfd, struct bfd_link_info *info)
if (!mips_elf_resolve_final_got_entries (g)) if (!mips_elf_resolve_final_got_entries (g))
return FALSE; return FALSE;
/* Count the number of GOT symbols. */ /* Decide which symbols need to go in the global part of the GOT and
count the number of reloc-only GOT symbols. */
mips_elf_link_hash_traverse (htab, mips_elf_count_got_symbols, info); mips_elf_link_hash_traverse (htab, mips_elf_count_got_symbols, info);
/* Calculate the total loadable size of the output. That /* Calculate the total loadable size of the output. That
@ -8835,17 +8668,10 @@ mips_elf_lay_out_got (bfd *output_bfd, struct bfd_link_info *info)
g->local_gotno += page_gotno; g->local_gotno += page_gotno;
/* Count the number of local GOT entries and TLS relocs. */ /* Count the number of GOT entries and TLS relocs. */
tga.info = info; tga.info = info;
tga.g = g; tga.g = g;
htab_traverse (g->got_entries, mips_elf_count_local_got_entries, &tga); htab_traverse (g->got_entries, mips_elf_count_got_entries, &tga);
/* We need to calculate tls_gotno for global symbols at this point
instead of building it up earlier, to avoid doublecounting
entries for one global symbol from multiple input files. */
elf_link_hash_traverse (elf_hash_table (info),
mips_elf_count_global_tls_entries,
&tga);
s->size += g->local_gotno * MIPS_ELF_GOT_SIZE (output_bfd); s->size += g->local_gotno * MIPS_ELF_GOT_SIZE (output_bfd);
s->size += g->global_gotno * MIPS_ELF_GOT_SIZE (output_bfd); s->size += g->global_gotno * MIPS_ELF_GOT_SIZE (output_bfd);
@ -10037,6 +9863,7 @@ _bfd_mips_elf_finish_dynamic_symbol (bfd *output_bfd,
&e))) &e)))
{ {
offset = p->gotidx; offset = p->gotidx;
BFD_ASSERT (offset > 0 && offset < htab->sgot->size);
if (info->shared if (info->shared
|| (elf_hash_table (info)->dynamic_sections_created || (elf_hash_table (info)->dynamic_sections_created
&& p->d.h != NULL && p->d.h != NULL
@ -11530,11 +11357,6 @@ _bfd_mips_elf_copy_indirect_symbol (struct bfd_link_info *info,
indmips->global_got_area = GGA_NONE; indmips->global_got_area = GGA_NONE;
if (indmips->has_nonpic_branches) if (indmips->has_nonpic_branches)
dirmips->has_nonpic_branches = TRUE; dirmips->has_nonpic_branches = TRUE;
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 #define PDR_SIZE 32