* elfxx-mips.c (mips_elf_obj_tdata): Add a got field.
	(mips_elf_bfd_got, mips_elf_record_got_entry): New functions.
	(mips_elf_record_global_got_symbol): Update the hash entry before
	adding the mips_got_entry.  Use mips_elf_record_got_entry to do
	the latter.
	(mips_elf_record_local_got_symbol): Use mips_elf_record_got_entry.
	(mips_elf_record_got_page_entry): Record the entry in both the
	master and bfd GOTs.
This commit is contained in:
Richard Sandiford 2013-02-11 18:01:58 +00:00
parent 72e7511a70
commit ee227692d7
2 changed files with 112 additions and 56 deletions

View File

@ -1,3 +1,14 @@
2013-02-11 Richard Sandiford <rdsandiford@googlemail.com>
* elfxx-mips.c (mips_elf_obj_tdata): Add a got field.
(mips_elf_bfd_got, mips_elf_record_got_entry): New functions.
(mips_elf_record_global_got_symbol): Update the hash entry before
adding the mips_got_entry. Use mips_elf_record_got_entry to do
the latter.
(mips_elf_record_local_got_symbol): Use mips_elf_record_got_entry.
(mips_elf_record_got_page_entry): Record the entry in both the
master and bfd GOTs.
2013-02-11 Richard Sandiford <rdsandiford@googlemail.com>
* elfxx-mips.c (mips_elf_recreate_got): Don't change the entry;

View File

@ -512,6 +512,9 @@ struct mips_elf_obj_tdata
/* Input BFD providing Tag_GNU_MIPS_ABI_FP attribute for output. */
bfd *abi_fp_bfd;
/* The GOT requirements of input bfds. */
struct mips_got_info *got;
};
/* Get MIPS ELF private object data from BFD's tdata. */
@ -2883,6 +2886,23 @@ mips_elf_create_got_info (bfd *abfd, bfd_boolean master_got_p)
return g;
}
/* Return the GOT info for input bfd ABFD, trying to create a new one if
CREATE_P and if ABFD doesn't already have a GOT. */
static struct mips_got_info *
mips_elf_bfd_got (bfd *abfd, bfd_boolean create_p)
{
struct mips_elf_obj_tdata *tdata;
if (!is_mips_elf (abfd))
return NULL;
tdata = mips_elf_tdata (abfd);
if (!tdata->got && create_p)
tdata->got = mips_elf_create_got_info (abfd, FALSE);
return tdata->got;
}
/* 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. */
@ -3706,6 +3726,53 @@ mips_elf_sort_hash_table_f (struct mips_elf_link_hash_entry *h, void *data)
return TRUE;
}
/* Record that input bfd ABFD requires a GOT entry like *LOOKUP
(which is owned by the caller and shouldn't be added to the
hash table directly). */
static bfd_boolean
mips_elf_record_got_entry (struct bfd_link_info *info, bfd *abfd,
struct mips_got_entry *lookup)
{
struct mips_elf_link_hash_table *htab;
struct mips_got_entry *entry;
struct mips_got_info *g;
void **loc, **bfd_loc;
/* Make sure there's a slot for this entry in the master GOT. */
htab = mips_elf_hash_table (info);
g = htab->got_info;
loc = htab_find_slot (g->got_entries, lookup, INSERT);
if (!loc)
return FALSE;
/* Populate the entry if it isn't already. */
entry = (struct mips_got_entry *) *loc;
if (!entry)
{
entry = (struct mips_got_entry *) bfd_alloc (abfd, sizeof (*entry));
if (!entry)
return FALSE;
lookup->gotidx = -1;
*entry = *lookup;
*loc = entry;
}
/* Reuse the same GOT entry for the BFD's GOT. */
g = mips_elf_bfd_got (abfd, TRUE);
if (!g)
return FALSE;
bfd_loc = htab_find_slot (g->got_entries, lookup, INSERT);
if (!bfd_loc)
return FALSE;
if (!*bfd_loc)
*bfd_loc = entry;
return TRUE;
}
/* 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. */
@ -3717,8 +3784,8 @@ mips_elf_record_global_got_symbol (struct elf_link_hash_entry *h,
{
struct mips_elf_link_hash_table *htab;
struct mips_elf_link_hash_entry *hmips;
struct mips_got_entry entry, **loc;
struct mips_got_info *g;
struct mips_got_entry entry;
unsigned char tls_type;
htab = mips_elf_hash_table (info);
BFD_ASSERT (htab != NULL);
@ -3742,40 +3809,19 @@ mips_elf_record_global_got_symbol (struct elf_link_hash_entry *h,
return FALSE;
}
/* Make sure we have a GOT to put this entry into. */
g = htab->got_info;
BFD_ASSERT (g != NULL);
tls_type = mips_elf_reloc_tls_type (r_type);
if (tls_type == GOT_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.symndx = -1;
entry.d.h = (struct mips_elf_link_hash_entry *) h;
entry.tls_type = mips_elf_reloc_tls_type (r_type);
loc = (struct mips_got_entry **) htab_find_slot (g->got_entries, &entry,
INSERT);
/* If we've already marked this entry as needing GOT space, we don't
need to do it again. */
if (*loc)
return TRUE;
*loc = (struct mips_got_entry *)bfd_alloc (abfd, sizeof entry);
if (! *loc)
return FALSE;
entry.gotidx = -1;
memcpy (*loc, &entry, sizeof entry);
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;
entry.tls_type = tls_type;
return mips_elf_record_got_entry (info, abfd, &entry);
}
/* ABFD has a GOT relocation of type R_TYPE against symbol SYMNDX + ADDEND,
@ -3787,7 +3833,7 @@ mips_elf_record_local_got_symbol (bfd *abfd, long symndx, bfd_vma addend,
{
struct mips_elf_link_hash_table *htab;
struct mips_got_info *g;
struct mips_got_entry entry, **loc;
struct mips_got_entry entry;
htab = mips_elf_hash_table (info);
BFD_ASSERT (htab != NULL);
@ -3799,22 +3845,7 @@ mips_elf_record_local_got_symbol (bfd *abfd, long symndx, bfd_vma addend,
entry.symndx = symndx;
entry.d.addend = addend;
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)
return TRUE;
entry.gotidx = -1;
*loc = (struct mips_got_entry *)bfd_alloc (abfd, sizeof entry);
if (! *loc)
return FALSE;
memcpy (*loc, &entry, sizeof entry);
return TRUE;
return mips_elf_record_got_entry (info, abfd, &entry);
}
/* Return the maximum number of GOT page entries required for RANGE. */
@ -3837,22 +3868,22 @@ mips_elf_record_got_page_entry (struct bfd_link_info *info, bfd *abfd,
long symndx, bfd_signed_vma addend)
{
struct mips_elf_link_hash_table *htab;
struct mips_got_info *g;
struct mips_got_info *g1, *g2;
struct mips_got_page_entry lookup, *entry;
struct mips_got_page_range **range_ptr, *range;
bfd_vma old_pages, new_pages;
void **loc;
void **loc, **bfd_loc;
htab = mips_elf_hash_table (info);
BFD_ASSERT (htab != NULL);
g = htab->got_info;
BFD_ASSERT (g != NULL);
g1 = htab->got_info;
BFD_ASSERT (g1 != NULL);
/* Find the mips_got_page_entry hash table entry for this symbol. */
lookup.abfd = abfd;
lookup.symndx = symndx;
loc = htab_find_slot (g->got_page_entries, &lookup, INSERT);
loc = htab_find_slot (g1->got_page_entries, &lookup, INSERT);
if (loc == NULL)
return FALSE;
@ -3872,6 +3903,18 @@ mips_elf_record_got_page_entry (struct bfd_link_info *info, bfd *abfd,
*loc = entry;
}
/* Add the same entry to the BFD's GOT. */
g2 = mips_elf_bfd_got (abfd, TRUE);
if (!g2)
return FALSE;
bfd_loc = htab_find_slot (g2->got_page_entries, &lookup, INSERT);
if (!bfd_loc)
return FALSE;
if (!*bfd_loc)
*bfd_loc = entry;
/* Skip over ranges whose maximum extent cannot share a page entry
with ADDEND. */
range_ptr = &entry->ranges;
@ -3894,7 +3937,8 @@ mips_elf_record_got_page_entry (struct bfd_link_info *info, bfd *abfd,
*range_ptr = range;
entry->num_pages++;
g->page_gotno++;
g1->page_gotno++;
g2->page_gotno++;
return TRUE;
}
@ -3921,7 +3965,8 @@ mips_elf_record_got_page_entry (struct bfd_link_info *info, bfd *abfd,
if (old_pages != new_pages)
{
entry->num_pages += new_pages - old_pages;
g->page_gotno += new_pages - old_pages;
g1->page_gotno += new_pages - old_pages;
g2->page_gotno += new_pages - old_pages;
}
return TRUE;