bfd/
* elfxx-mips.c (mips_got_info): Remove bfd2got. (mips_elf_bfd2got_hash): Delete. (mips_elf_got_per_bfd_arg): Remove bfd2got. (mips_elf_replace_bfd_got, mips_elf_count_got_entries): New functions. (mips_elf_global_got_index, mips_elf_create_local_got_entry): Use g->next to test for the multigot case. Use mips_elf_bfd_got rather than mips_elf_got_for_ibfd. (mips_elf_bfd2got_entry_hash, mips_elf_bfd2got_entry_eq) (mips_elf_got_for_ibfd, mips_elf_get_got_for_bfd): Delete. (mips_elf_make_got_per_bfd): Replace with... (mips_elf_add_got_entry): ...this new function. (mips_elf_make_got_pages_per_bfd): Replace with... (mips_elf_add_got_page_entry): ...this new function. (mips_elf_merge_got_with): Replace bfd2got argument with separate bfd and GOT arguments. Use mips_elf_add_got_entry and mips_elf_add_got_page_entry instead of mips_elf_make_got_per_bfd and mips_elf_make_got_pages_per_bfd. Use mips_elf_replace_bfd_got to set the BFD's GOT and free the old table. (mips_elf_merge_got): Replace bfd2got argument with separate bfd and GOT arguments. Apply mips_elf_resolve_final_got_entries. Use mips_elf_count_got_entries to count the number of entries in each GOT. Update the calls to mips_elf_merge_got_with. (mips_elf_adjust_gp): Use g->next to test for the multigot case. Use mips_elf_bfd_got rather than mips_elf_got_for_ibfd. (mips_elf_multi_got): Don't create the bfd2got hash table. Replace hash table traversal with a walk over the input bfds, updating the call to mips_elf_merge_got. Use mips_elf_replace_bfd_got to set the output bfd's GOT. (mips_elf_lay_out_got): Rename "sub" to "ibfd". Record that all bfds use the master GOT in the single-GOT case. (_bfd_mips_elf_finish_dynamic_sections): Use mips_elf_bfd_got rather than mips_elf_got_for_ibfd. ld/testsuite/ * ld-mips-elf/tls-hidden4.got, ld-mips-elf/tls-multi-got-1.d, ld-mips-elf/tls-multi-got-1.got: Update for changes in the order that symbols are added to per-bfd GOTs.
This commit is contained in:
parent
d9e983823a
commit
d720656991
@ -1,3 +1,38 @@
|
||||
2013-02-11 Richard Sandiford <rdsandiford@googlemail.com>
|
||||
|
||||
* elfxx-mips.c (mips_got_info): Remove bfd2got.
|
||||
(mips_elf_bfd2got_hash): Delete.
|
||||
(mips_elf_got_per_bfd_arg): Remove bfd2got.
|
||||
(mips_elf_replace_bfd_got, mips_elf_count_got_entries): New functions.
|
||||
(mips_elf_global_got_index, mips_elf_create_local_got_entry): Use
|
||||
g->next to test for the multigot case. Use mips_elf_bfd_got rather
|
||||
than mips_elf_got_for_ibfd.
|
||||
(mips_elf_bfd2got_entry_hash, mips_elf_bfd2got_entry_eq)
|
||||
(mips_elf_got_for_ibfd, mips_elf_get_got_for_bfd): Delete.
|
||||
(mips_elf_make_got_per_bfd): Replace with...
|
||||
(mips_elf_add_got_entry): ...this new function.
|
||||
(mips_elf_make_got_pages_per_bfd): Replace with...
|
||||
(mips_elf_add_got_page_entry): ...this new function.
|
||||
(mips_elf_merge_got_with): Replace bfd2got argument with separate
|
||||
bfd and GOT arguments. Use mips_elf_add_got_entry and
|
||||
mips_elf_add_got_page_entry instead of mips_elf_make_got_per_bfd
|
||||
and mips_elf_make_got_pages_per_bfd. Use mips_elf_replace_bfd_got
|
||||
to set the BFD's GOT and free the old table.
|
||||
(mips_elf_merge_got): Replace bfd2got argument with separate
|
||||
bfd and GOT arguments. Apply mips_elf_resolve_final_got_entries.
|
||||
Use mips_elf_count_got_entries to count the number of entries in
|
||||
each GOT. Update the calls to mips_elf_merge_got_with.
|
||||
(mips_elf_adjust_gp): Use g->next to test for the multigot case.
|
||||
Use mips_elf_bfd_got rather than mips_elf_got_for_ibfd.
|
||||
(mips_elf_multi_got): Don't create the bfd2got hash table.
|
||||
Replace hash table traversal with a walk over the input bfds,
|
||||
updating the call to mips_elf_merge_got. Use mips_elf_replace_bfd_got
|
||||
to set the output bfd's GOT.
|
||||
(mips_elf_lay_out_got): Rename "sub" to "ibfd". Record that all
|
||||
bfds use the master GOT in the single-GOT case.
|
||||
(_bfd_mips_elf_finish_dynamic_sections): Use mips_elf_bfd_got
|
||||
rather than mips_elf_got_for_ibfd.
|
||||
|
||||
2013-02-11 Richard Sandiford <rdsandiford@googlemail.com>
|
||||
|
||||
* elfxx-mips.c (mips_elf_obj_tdata): Add a got field.
|
||||
|
||||
332
bfd/elfxx-mips.c
332
bfd/elfxx-mips.c
@ -161,9 +161,6 @@ struct mips_got_info
|
||||
struct htab *got_entries;
|
||||
/* A hash table of mips_got_page_entry structures. */
|
||||
struct htab *got_page_entries;
|
||||
/* A hash table mapping input bfds to other mips_got_info. NULL
|
||||
unless multi-got was necessary. */
|
||||
struct htab *bfd2got;
|
||||
/* In multi-got links, a pointer to the next got (err, rather, most
|
||||
of the time, it points to the previous got). */
|
||||
struct mips_got_info *next;
|
||||
@ -174,21 +171,10 @@ struct mips_got_info
|
||||
bfd_vma tls_ldm_offset;
|
||||
};
|
||||
|
||||
/* Map an input bfd to a got in a multi-got link. */
|
||||
|
||||
struct mips_elf_bfd2got_hash
|
||||
{
|
||||
bfd *bfd;
|
||||
struct mips_got_info *g;
|
||||
};
|
||||
|
||||
/* Structure passed when traversing the bfd2got hash table, used to
|
||||
create and merge bfd's gots. */
|
||||
/* Structure passed when merging bfds' gots. */
|
||||
|
||||
struct mips_elf_got_per_bfd_arg
|
||||
{
|
||||
/* A hashtable that maps bfds to gots. */
|
||||
htab_t bfd2got;
|
||||
/* The output bfd. */
|
||||
bfd *obfd;
|
||||
/* The link information. */
|
||||
@ -696,8 +682,6 @@ static bfd_boolean mips_elf_create_dynamic_relocation
|
||||
bfd_vma *, asection *);
|
||||
static bfd_vma mips_elf_adjust_gp
|
||||
(bfd *, struct mips_got_info *, bfd *);
|
||||
static struct mips_got_info *mips_elf_got_for_ibfd
|
||||
(struct mips_got_info *, bfd *);
|
||||
|
||||
/* This will be used when we sort the dynamic relocation records. */
|
||||
static bfd *reldyn_sorting_bfd;
|
||||
@ -2903,6 +2887,25 @@ mips_elf_bfd_got (bfd *abfd, bfd_boolean create_p)
|
||||
return tdata->got;
|
||||
}
|
||||
|
||||
/* Record that ABFD should use output GOT G. */
|
||||
|
||||
static void
|
||||
mips_elf_replace_bfd_got (bfd *abfd, struct mips_got_info *g)
|
||||
{
|
||||
struct mips_elf_obj_tdata *tdata;
|
||||
|
||||
BFD_ASSERT (is_mips_elf (abfd));
|
||||
tdata = mips_elf_tdata (abfd);
|
||||
if (tdata->got)
|
||||
{
|
||||
/* The GOT structure itself and the hash table entries are
|
||||
allocated to a bfd, but the hash tables aren't. */
|
||||
htab_delete (tdata->got->got_entries);
|
||||
htab_delete (tdata->got->got_page_entries);
|
||||
}
|
||||
tdata->got = g;
|
||||
}
|
||||
|
||||
/* Return the dynamic relocation section. If it doesn't exist, try to
|
||||
create a new it if CREATE_P, otherwise return NULL. Also return NULL
|
||||
if creation fails. */
|
||||
@ -3036,6 +3039,23 @@ mips_elf_count_got_entry (struct bfd_link_info *info,
|
||||
g->global_gotno += 1;
|
||||
}
|
||||
|
||||
/* A htab_traverse callback. Count the number of GOT entries and
|
||||
TLS relocations required for the GOT entry in *ENTRYP. DATA points
|
||||
to a mips_elf_traverse_got_arg structure. */
|
||||
|
||||
static int
|
||||
mips_elf_count_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;
|
||||
mips_elf_count_got_entry (arg->info, arg->g, entry);
|
||||
|
||||
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. */
|
||||
@ -3365,13 +3385,14 @@ mips_elf_global_got_index (bfd *abfd, bfd *ibfd, struct elf_link_hash_entry *h,
|
||||
BFD_ASSERT (htab != NULL);
|
||||
|
||||
gg = g = htab->got_info;
|
||||
if (g->bfd2got && ibfd)
|
||||
if (g->next && ibfd)
|
||||
{
|
||||
struct mips_got_entry e, *p;
|
||||
|
||||
BFD_ASSERT (h->dynindx >= 0);
|
||||
|
||||
g = mips_elf_got_for_ibfd (g, ibfd);
|
||||
g = mips_elf_bfd_got (ibfd, FALSE);
|
||||
BFD_ASSERT (g);
|
||||
if (g->next != gg || TLS_RELOC_P (r_type))
|
||||
{
|
||||
e.abfd = ibfd;
|
||||
@ -3535,10 +3556,10 @@ mips_elf_create_local_got_entry (bfd *abfd, struct bfd_link_info *info,
|
||||
entry.d.address = value;
|
||||
entry.tls_type = mips_elf_reloc_tls_type (r_type);
|
||||
|
||||
g = mips_elf_got_for_ibfd (htab->got_info, ibfd);
|
||||
g = mips_elf_bfd_got (ibfd, FALSE);
|
||||
if (g == NULL)
|
||||
{
|
||||
g = mips_elf_got_for_ibfd (htab->got_info, abfd);
|
||||
g = mips_elf_bfd_got (abfd, FALSE);
|
||||
BFD_ASSERT (g != NULL);
|
||||
}
|
||||
|
||||
@ -4163,147 +4184,70 @@ mips_elf_count_got_symbols (struct mips_elf_link_hash_entry *h, void *data)
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* Compute the hash value of the bfd in a bfd2got hash entry. */
|
||||
|
||||
static hashval_t
|
||||
mips_elf_bfd2got_entry_hash (const void *entry_)
|
||||
{
|
||||
const struct mips_elf_bfd2got_hash *entry
|
||||
= (struct mips_elf_bfd2got_hash *)entry_;
|
||||
|
||||
return entry->bfd->id;
|
||||
}
|
||||
|
||||
/* Check whether two hash entries have the same bfd. */
|
||||
/* A htab_traverse callback for GOT entries. Add each one to the GOT
|
||||
given in mips_elf_traverse_got_arg DATA. Clear DATA->G on error. */
|
||||
|
||||
static int
|
||||
mips_elf_bfd2got_entry_eq (const void *entry1, const void *entry2)
|
||||
mips_elf_add_got_entry (void **entryp, void *data)
|
||||
{
|
||||
const struct mips_elf_bfd2got_hash *e1
|
||||
= (const struct mips_elf_bfd2got_hash *)entry1;
|
||||
const struct mips_elf_bfd2got_hash *e2
|
||||
= (const struct mips_elf_bfd2got_hash *)entry2;
|
||||
struct mips_got_entry *entry;
|
||||
struct mips_elf_traverse_got_arg *arg;
|
||||
void **slot;
|
||||
|
||||
return e1->bfd == e2->bfd;
|
||||
}
|
||||
|
||||
/* In a multi-got link, determine the GOT to be used for IBFD. G must
|
||||
be the master GOT data. */
|
||||
|
||||
static struct mips_got_info *
|
||||
mips_elf_got_for_ibfd (struct mips_got_info *g, bfd *ibfd)
|
||||
{
|
||||
struct mips_elf_bfd2got_hash e, *p;
|
||||
|
||||
if (! g->bfd2got)
|
||||
return g;
|
||||
|
||||
e.bfd = ibfd;
|
||||
p = htab_find (g->bfd2got, &e);
|
||||
return p ? p->g : NULL;
|
||||
}
|
||||
|
||||
/* Use BFD2GOT to find ABFD's got entry, creating one if none exists.
|
||||
Return NULL if an error occured. */
|
||||
|
||||
static struct mips_got_info *
|
||||
mips_elf_get_got_for_bfd (struct htab *bfd2got, bfd *output_bfd,
|
||||
bfd *input_bfd)
|
||||
{
|
||||
struct mips_elf_bfd2got_hash bfdgot_entry, *bfdgot;
|
||||
void **bfdgotp;
|
||||
|
||||
bfdgot_entry.bfd = input_bfd;
|
||||
bfdgotp = htab_find_slot (bfd2got, &bfdgot_entry, INSERT);
|
||||
bfdgot = (struct mips_elf_bfd2got_hash *) *bfdgotp;
|
||||
|
||||
if (bfdgot == NULL)
|
||||
entry = (struct mips_got_entry *) *entryp;
|
||||
arg = (struct mips_elf_traverse_got_arg *) data;
|
||||
slot = htab_find_slot (arg->g->got_entries, entry, INSERT);
|
||||
if (!slot)
|
||||
{
|
||||
bfdgot = ((struct mips_elf_bfd2got_hash *)
|
||||
bfd_alloc (output_bfd, sizeof (struct mips_elf_bfd2got_hash)));
|
||||
if (bfdgot == NULL)
|
||||
return NULL;
|
||||
|
||||
*bfdgotp = bfdgot;
|
||||
|
||||
bfdgot->bfd = input_bfd;
|
||||
bfdgot->g = mips_elf_create_got_info (input_bfd, FALSE);
|
||||
if (bfdgot->g == NULL)
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return bfdgot->g;
|
||||
}
|
||||
|
||||
/* A htab_traverse callback for the entries in the master got.
|
||||
Create one separate got for each bfd that has entries in the global
|
||||
got, such that we can tell how many local and global entries each
|
||||
bfd requires. */
|
||||
|
||||
static int
|
||||
mips_elf_make_got_per_bfd (void **entryp, void *p)
|
||||
{
|
||||
struct mips_got_entry *entry = (struct mips_got_entry *)*entryp;
|
||||
struct mips_elf_got_per_bfd_arg *arg = (struct mips_elf_got_per_bfd_arg *)p;
|
||||
struct mips_got_info *g;
|
||||
|
||||
g = mips_elf_get_got_for_bfd (arg->bfd2got, arg->obfd, entry->abfd);
|
||||
if (g == NULL)
|
||||
{
|
||||
arg->obfd = NULL;
|
||||
arg->g = NULL;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Insert the GOT entry in the bfd's got entry hash table. */
|
||||
entryp = htab_find_slot (g->got_entries, entry, INSERT);
|
||||
if (*entryp != NULL)
|
||||
return 1;
|
||||
|
||||
*entryp = entry;
|
||||
mips_elf_count_got_entry (arg->info, g, entry);
|
||||
|
||||
if (!*slot)
|
||||
{
|
||||
*slot = entry;
|
||||
mips_elf_count_got_entry (arg->info, arg->g, entry);
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* A htab_traverse callback for the page entries in the master got.
|
||||
Associate each page entry with the bfd's got. */
|
||||
/* A htab_traverse callback for GOT page entries. Add each one to the GOT
|
||||
given in mips_elf_traverse_got_arg DATA. Clear DATA->G on error. */
|
||||
|
||||
static int
|
||||
mips_elf_make_got_pages_per_bfd (void **entryp, void *p)
|
||||
mips_elf_add_got_page_entry (void **entryp, void *data)
|
||||
{
|
||||
struct mips_got_page_entry *entry = (struct mips_got_page_entry *) *entryp;
|
||||
struct mips_elf_got_per_bfd_arg *arg = (struct mips_elf_got_per_bfd_arg *) p;
|
||||
struct mips_got_info *g;
|
||||
struct mips_got_page_entry *entry;
|
||||
struct mips_elf_traverse_got_arg *arg;
|
||||
void **slot;
|
||||
|
||||
g = mips_elf_get_got_for_bfd (arg->bfd2got, arg->obfd, entry->abfd);
|
||||
if (g == NULL)
|
||||
entry = (struct mips_got_page_entry *) *entryp;
|
||||
arg = (struct mips_elf_traverse_got_arg *) data;
|
||||
slot = htab_find_slot (arg->g->got_page_entries, entry, INSERT);
|
||||
if (!slot)
|
||||
{
|
||||
arg->obfd = NULL;
|
||||
arg->g = NULL;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Insert the GOT entry in the bfd's got entry hash table. */
|
||||
entryp = htab_find_slot (g->got_page_entries, entry, INSERT);
|
||||
if (*entryp != NULL)
|
||||
return 1;
|
||||
|
||||
*entryp = entry;
|
||||
g->page_gotno += entry->num_pages;
|
||||
if (!*slot)
|
||||
{
|
||||
*slot = entry;
|
||||
arg->g->page_gotno += entry->num_pages;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* Consider merging the got described by BFD2GOT with TO, using the
|
||||
information given by ARG. Return -1 if this would lead to overflow,
|
||||
1 if they were merged successfully, and 0 if a merge failed due to
|
||||
lack of memory. (These values are chosen so that nonnegative return
|
||||
values can be returned by a htab_traverse callback.) */
|
||||
/* Consider merging FROM, which is ABFD's GOT, into TO. Return -1 if
|
||||
this would lead to overflow, 1 if they were merged successfully,
|
||||
and 0 if a merge failed due to lack of memory. (These values are chosen
|
||||
so that nonnegative return values can be returned by a htab_traverse
|
||||
callback.) */
|
||||
|
||||
static int
|
||||
mips_elf_merge_got_with (struct mips_elf_bfd2got_hash *bfd2got,
|
||||
mips_elf_merge_got_with (bfd *abfd, struct mips_got_info *from,
|
||||
struct mips_got_info *to,
|
||||
struct mips_elf_got_per_bfd_arg *arg)
|
||||
{
|
||||
struct mips_got_info *from = bfd2got->g;
|
||||
struct mips_elf_traverse_got_arg tga;
|
||||
unsigned int estimate;
|
||||
|
||||
/* Work out how many page entries we would need for the combined GOT. */
|
||||
@ -4328,44 +4272,42 @@ mips_elf_merge_got_with (struct mips_elf_bfd2got_hash *bfd2got,
|
||||
if (estimate > arg->max_count)
|
||||
return -1;
|
||||
|
||||
/* Commit to the merge. Record that TO is now the bfd for this got. */
|
||||
bfd2got->g = to;
|
||||
|
||||
/* Transfer the bfd's got information from FROM to TO. */
|
||||
htab_traverse (from->got_entries, mips_elf_make_got_per_bfd, arg);
|
||||
if (arg->obfd == NULL)
|
||||
tga.info = arg->info;
|
||||
tga.g = to;
|
||||
htab_traverse (from->got_entries, mips_elf_add_got_entry, &tga);
|
||||
if (!tga.g)
|
||||
return 0;
|
||||
|
||||
htab_traverse (from->got_page_entries, mips_elf_make_got_pages_per_bfd, arg);
|
||||
if (arg->obfd == NULL)
|
||||
htab_traverse (from->got_page_entries, mips_elf_add_got_page_entry, &tga);
|
||||
if (!tga.g)
|
||||
return 0;
|
||||
|
||||
/* We don't have to worry about releasing memory of the actual
|
||||
got entries, since they're all in the master got_entries hash
|
||||
table anyway. */
|
||||
htab_delete (from->got_entries);
|
||||
htab_delete (from->got_page_entries);
|
||||
mips_elf_replace_bfd_got (abfd, to);
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* Attempt to merge gots of different input bfds. Try to use as much
|
||||
/* Attempt to merge GOT G, which belongs to ABFD. Try to use as much
|
||||
as possible of the primary got, since it doesn't require explicit
|
||||
dynamic relocations, but don't use bfds that would reference global
|
||||
symbols out of the addressable range. Failing the primary got,
|
||||
attempt to merge with the current got, or finish the current got
|
||||
and then make make the new got current. */
|
||||
|
||||
static int
|
||||
mips_elf_merge_gots (void **bfd2got_, void *p)
|
||||
static bfd_boolean
|
||||
mips_elf_merge_got (bfd *abfd, struct mips_got_info *g,
|
||||
struct mips_elf_got_per_bfd_arg *arg)
|
||||
{
|
||||
struct mips_elf_bfd2got_hash *bfd2got
|
||||
= (struct mips_elf_bfd2got_hash *)*bfd2got_;
|
||||
struct mips_elf_got_per_bfd_arg *arg = (struct mips_elf_got_per_bfd_arg *)p;
|
||||
struct mips_got_info *g;
|
||||
struct mips_elf_traverse_got_arg tga;
|
||||
unsigned int estimate;
|
||||
int result;
|
||||
|
||||
g = bfd2got->g;
|
||||
if (!mips_elf_resolve_final_got_entries (g))
|
||||
return FALSE;
|
||||
|
||||
tga.info = arg->info;
|
||||
tga.g = g;
|
||||
htab_traverse (g->got_entries, mips_elf_count_got_entries, &tga);
|
||||
|
||||
/* Work out the number of page, local and TLS entries. */
|
||||
estimate = arg->max_pages;
|
||||
@ -4385,12 +4327,12 @@ mips_elf_merge_gots (void **bfd2got_, void *p)
|
||||
a starting point for the primary GOT. */
|
||||
if (!arg->primary)
|
||||
{
|
||||
arg->primary = bfd2got->g;
|
||||
return 1;
|
||||
arg->primary = g;
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/* Try merging with the primary GOT. */
|
||||
result = mips_elf_merge_got_with (bfd2got, arg->primary, arg);
|
||||
result = mips_elf_merge_got_with (abfd, g, arg->primary, arg);
|
||||
if (result >= 0)
|
||||
return result;
|
||||
}
|
||||
@ -4398,7 +4340,7 @@ mips_elf_merge_gots (void **bfd2got_, void *p)
|
||||
/* If we can merge with the last-created got, do it. */
|
||||
if (arg->current)
|
||||
{
|
||||
result = mips_elf_merge_got_with (bfd2got, arg->current, arg);
|
||||
result = mips_elf_merge_got_with (abfd, g, arg->current, arg);
|
||||
if (result >= 0)
|
||||
return result;
|
||||
}
|
||||
@ -4409,7 +4351,7 @@ mips_elf_merge_gots (void **bfd2got_, void *p)
|
||||
g->next = arg->current;
|
||||
arg->current = g;
|
||||
|
||||
return 1;
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/* ENTRYP is a hash table entry for a mips_got_entry. Set its gotidx
|
||||
@ -4592,10 +4534,10 @@ mips_elf_forbid_lazy_stubs (void **entryp, void *data)
|
||||
static bfd_vma
|
||||
mips_elf_adjust_gp (bfd *abfd, struct mips_got_info *g, bfd *ibfd)
|
||||
{
|
||||
if (g->bfd2got == NULL)
|
||||
if (!g->next)
|
||||
return 0;
|
||||
|
||||
g = mips_elf_got_for_ibfd (g, ibfd);
|
||||
g = mips_elf_bfd_got (ibfd, FALSE);
|
||||
if (! g)
|
||||
return 0;
|
||||
|
||||
@ -4619,34 +4561,16 @@ mips_elf_multi_got (bfd *abfd, struct bfd_link_info *info,
|
||||
struct mips_elf_traverse_got_arg tga;
|
||||
struct mips_got_info *g, *gg;
|
||||
unsigned int assign, needed_relocs;
|
||||
bfd *dynobj;
|
||||
bfd *dynobj, *ibfd;
|
||||
|
||||
dynobj = elf_hash_table (info)->dynobj;
|
||||
htab = mips_elf_hash_table (info);
|
||||
BFD_ASSERT (htab != NULL);
|
||||
|
||||
g = htab->got_info;
|
||||
g->bfd2got = htab_try_create (1, mips_elf_bfd2got_entry_hash,
|
||||
mips_elf_bfd2got_entry_eq, NULL);
|
||||
if (g->bfd2got == NULL)
|
||||
return FALSE;
|
||||
|
||||
got_per_bfd_arg.bfd2got = g->bfd2got;
|
||||
got_per_bfd_arg.obfd = abfd;
|
||||
got_per_bfd_arg.info = info;
|
||||
|
||||
/* Count how many GOT entries each input bfd requires, creating a
|
||||
map from bfd to got info while at that. */
|
||||
htab_traverse (g->got_entries, mips_elf_make_got_per_bfd, &got_per_bfd_arg);
|
||||
if (got_per_bfd_arg.obfd == NULL)
|
||||
return FALSE;
|
||||
|
||||
/* Also count how many page entries each input bfd requires. */
|
||||
htab_traverse (g->got_page_entries, mips_elf_make_got_pages_per_bfd,
|
||||
&got_per_bfd_arg);
|
||||
if (got_per_bfd_arg.obfd == NULL)
|
||||
return FALSE;
|
||||
|
||||
got_per_bfd_arg.current = NULL;
|
||||
got_per_bfd_arg.primary = NULL;
|
||||
got_per_bfd_arg.max_count = ((MIPS_ELF_GOT_MAX_SIZE (info)
|
||||
@ -4661,9 +4585,12 @@ mips_elf_multi_got (bfd *abfd, struct bfd_link_info *info,
|
||||
/* Try to merge the GOTs of input bfds together, as long as they
|
||||
don't seem to exceed the maximum GOT size, choosing one of them
|
||||
to be the primary GOT. */
|
||||
htab_traverse (g->bfd2got, mips_elf_merge_gots, &got_per_bfd_arg);
|
||||
if (got_per_bfd_arg.obfd == NULL)
|
||||
return FALSE;
|
||||
for (ibfd = info->input_bfds; ibfd; ibfd = ibfd->link_next)
|
||||
{
|
||||
gg = mips_elf_bfd_got (ibfd, FALSE);
|
||||
if (gg && !mips_elf_merge_got (ibfd, gg, &got_per_bfd_arg))
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
/* If we do not find any suitable primary GOT, create an empty one. */
|
||||
if (got_per_bfd_arg.primary == NULL)
|
||||
@ -4681,23 +4608,7 @@ mips_elf_multi_got (bfd *abfd, struct bfd_link_info *info,
|
||||
didn't mark in check_relocs, and we want a quick way to find it.
|
||||
We can't just use gg->next because we're going to reverse the
|
||||
list. */
|
||||
{
|
||||
struct mips_elf_bfd2got_hash *bfdgot;
|
||||
void **bfdgotp;
|
||||
|
||||
bfdgot = (struct mips_elf_bfd2got_hash *)bfd_alloc
|
||||
(abfd, sizeof (struct mips_elf_bfd2got_hash));
|
||||
|
||||
if (bfdgot == NULL)
|
||||
return FALSE;
|
||||
|
||||
bfdgot->bfd = abfd;
|
||||
bfdgot->g = g;
|
||||
bfdgotp = htab_find_slot (gg->bfd2got, bfdgot, INSERT);
|
||||
|
||||
BFD_ASSERT (*bfdgotp == NULL);
|
||||
*bfdgotp = bfdgot;
|
||||
}
|
||||
mips_elf_replace_bfd_got (abfd, g);
|
||||
|
||||
/* Every symbol that is referenced in a dynamic relocation must be
|
||||
present in the primary GOT, so arrange for them to appear after
|
||||
@ -8879,7 +8790,7 @@ mips_elf_lay_out_got (bfd *output_bfd, struct bfd_link_info *info)
|
||||
struct mips_got_info *g;
|
||||
bfd_size_type loadable_size = 0;
|
||||
bfd_size_type page_gotno;
|
||||
bfd *sub;
|
||||
bfd *ibfd;
|
||||
struct mips_elf_traverse_got_arg tga;
|
||||
struct mips_elf_link_hash_table *htab;
|
||||
|
||||
@ -8914,11 +8825,11 @@ mips_elf_lay_out_got (bfd *output_bfd, struct bfd_link_info *info)
|
||||
/* Calculate the total loadable size of the output. That
|
||||
will give us the maximum number of GOT_PAGE entries
|
||||
required. */
|
||||
for (sub = info->input_bfds; sub; sub = sub->link_next)
|
||||
for (ibfd = info->input_bfds; ibfd; ibfd = ibfd->link_next)
|
||||
{
|
||||
asection *subsection;
|
||||
|
||||
for (subsection = sub->sections;
|
||||
for (subsection = ibfd->sections;
|
||||
subsection;
|
||||
subsection = subsection->next)
|
||||
{
|
||||
@ -8985,6 +8896,13 @@ mips_elf_lay_out_got (bfd *output_bfd, struct bfd_link_info *info)
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Record that all bfds use G. This also has the effect of freeing
|
||||
the per-bfd GOTs, which we no longer need. */
|
||||
for (ibfd = info->input_bfds; ibfd; ibfd = ibfd->link_next)
|
||||
if (mips_elf_bfd_got (ibfd, FALSE))
|
||||
mips_elf_replace_bfd_got (ibfd, g);
|
||||
mips_elf_replace_bfd_got (output_bfd, g);
|
||||
|
||||
/* Set up TLS entries. */
|
||||
g->tls_assigned_gotno = g->global_gotno + g->local_gotno;
|
||||
tga.info = info;
|
||||
@ -10589,7 +10507,7 @@ _bfd_mips_elf_finish_dynamic_sections (bfd *output_bfd,
|
||||
BFD_ASSERT (sdyn != NULL);
|
||||
BFD_ASSERT (gg != NULL);
|
||||
|
||||
g = mips_elf_got_for_ibfd (gg, output_bfd);
|
||||
g = mips_elf_bfd_got (output_bfd, FALSE);
|
||||
BFD_ASSERT (g != NULL);
|
||||
|
||||
for (b = sdyn->contents;
|
||||
|
||||
@ -1,3 +1,9 @@
|
||||
2013-02-11 Richard Sandiford <rdsandiford@googlemail.com>
|
||||
|
||||
* ld-mips-elf/tls-hidden4.got, ld-mips-elf/tls-multi-got-1.d,
|
||||
ld-mips-elf/tls-multi-got-1.got: Update for changes in the order
|
||||
that symbols are added to per-bfd GOTs.
|
||||
|
||||
2013-02-11 Richard Sandiford <rdsandiford@googlemail.com>
|
||||
|
||||
* ld-mips-elf/tls-hidden3.d, ld-mips-elf/tls-hidden3.got,
|
||||
|
||||
@ -21,9 +21,9 @@ Contents of section \.got:
|
||||
# Likewise, but the order of the entries in this GOT is:
|
||||
#
|
||||
# foo3
|
||||
# foo2
|
||||
# foo0
|
||||
# foo2
|
||||
# foo1
|
||||
#...
|
||||
1d0020 00000000 00000000 00000000 0000abcc .*
|
||||
1d0030 0000abc8 0000abc0 0000abc4 .*
|
||||
1d0030 0000abc0 0000abc8 0000abc4 .*
|
||||
|
||||
@ -13,8 +13,8 @@ Disassembly of section .text:
|
||||
[0-9a-f]+ <sym_2_0000>:
|
||||
#...
|
||||
[0-9a-f]+ <tls_bits_2>:
|
||||
[0-9a-f]+: 27841c64 addiu a0,gp,7268
|
||||
[0-9a-f]+: 27841c60 addiu a0,gp,7264
|
||||
[0-9a-f]+: 27841c58 addiu a0,gp,7256
|
||||
[0-9a-f]+: 24441c60 addiu a0,v0,7264
|
||||
[0-9a-f]+: 24441c68 addiu a0,v0,7272
|
||||
[0-9a-f]+: 00000000 nop
|
||||
#pass
|
||||
|
||||
@ -6,15 +6,15 @@ OFFSET TYPE VALUE
|
||||
00000000 R_MIPS_NONE \*ABS\*
|
||||
0013f820 R_MIPS_TLS_DTPMOD32 \*ABS\*
|
||||
0014947c R_MIPS_TLS_DTPMOD32 \*ABS\*
|
||||
0013f82c R_MIPS_TLS_DTPMOD32 tlsvar_gd
|
||||
0013f830 R_MIPS_TLS_DTPREL32 tlsvar_gd
|
||||
0013f828 R_MIPS_TLS_DTPMOD32 tlsvar_gd
|
||||
0013f82c R_MIPS_TLS_DTPREL32 tlsvar_gd
|
||||
00149488 R_MIPS_TLS_DTPMOD32 tlsvar_gd
|
||||
0014948c R_MIPS_TLS_DTPREL32 tlsvar_gd
|
||||
0013f828 R_MIPS_TLS_TPREL32 tlsvar_ie
|
||||
0013f830 R_MIPS_TLS_TPREL32 tlsvar_ie
|
||||
00149484 R_MIPS_TLS_TPREL32 tlsvar_ie
|
||||
00143e3c R_MIPS_REL32 sym_1_9526
|
||||
00143ea8 R_MIPS_REL32 sym_1_9526
|
||||
#...
|
||||
0013a8f8 R_MIPS_REL32 sym_2_8654
|
||||
00139a84 R_MIPS_REL32 sym_2_8654
|
||||
|
||||
|
||||
Contents of section .got:
|
||||
|
||||
Loading…
Reference in New Issue
Block a user