summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRichard Sandiford <rdsandiford@googlemail.com>2013-02-11 18:01:58 +0000
committerRichard Sandiford <rdsandiford@googlemail.com>2013-02-11 18:01:58 +0000
commitee227692d767127ac01b420d35c064d4ac03a6a2 (patch)
treec77c1fc4a0d0021b2fe4799261f4f57db002754b
parent72e7511a70174adcf2a63b243020e3488077bcc4 (diff)
downloadbinutils-gdb-ee227692d767127ac01b420d35c064d4ac03a6a2.tar.gz
bfd/
* 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.
-rw-r--r--bfd/ChangeLog11
-rw-r--r--bfd/elfxx-mips.c157
2 files changed, 112 insertions, 56 deletions
diff --git a/bfd/ChangeLog b/bfd/ChangeLog
index 08cad1d310e..dbfff43cfdd 100644
--- a/bfd/ChangeLog
+++ b/bfd/ChangeLog
@@ -1,5 +1,16 @@
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;
create another one if necessary.
(mips_elf_set_gotidx): New function.
diff --git a/bfd/elfxx-mips.c b/bfd/elfxx-mips.c
index 36726b6c4c3..43026390fb3 100644
--- a/bfd/elfxx-mips.c
+++ b/bfd/elfxx-mips.c
@@ -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;