aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRichard Sandiford <rdsandiford@googlemail.com>2013-02-13 14:08:58 +0000
committerRichard Sandiford <rdsandiford@googlemail.com>2013-02-13 14:08:58 +0000
commit13db6b44eaf75fce5624b518185d98f81a48e603 (patch)
treeaff93f9b46f4f6ebbc51459271510e53bc3b9f46
parent1d3ffd6bfef1e9c7ceabba65a1d4cb0e7000c3aa (diff)
downloadgdb-13db6b44eaf75fce5624b518185d98f81a48e603.zip
gdb-13db6b44eaf75fce5624b518185d98f81a48e603.tar.gz
gdb-13db6b44eaf75fce5624b518185d98f81a48e603.tar.bz2
bfd/
* elfxx-mips.c (mips_got_page_ref): New structure. (mips_got_page_entry): Use a section rather than a (bfd, symndx) pair to represent the anchor point. (mips_got_info): Add a got_page_refs field. (mips_elf_link_hash_table): Add a sym_cache field. (mips_got_page_ref_hash, mips_got_page_ref_eq): New functions. (mips_got_page_entry_hash, mips_got_page_entry_eq): Update for new anchor representation. (mips_elf_create_got_info): Create got_page_refs rather than got_page_entries. (mips_elf_record_got_page_ref): New function. (mips_elf_pages_for_range): Move further down file. (mips_elf_record_got_page_entry): Likewise. Take a got as argument. Use a section rather than a (bfd, symndx) pair to represent the anchor point. (mips_elf_resolve_got_page_ref): New function. (mips_elf_resolve_final_got_entries): Use it to populate got_page_entries. (_bfd_mips_elf_check_relocs): Call mips_elf_record_got_page_ref rather than mips_elf_record_got_page_entry. Only nullify h afterwards. (mips_elf_lay_out_got): Call mips_elf_resolve_final_got_entries earlier. ld/testsuite/ * ld-mips-elf/mips16-pic-2.dd, ld-mips-elf/mips16-pic-2.gd: Remove 3 unused local GOT entries. * ld-mips-elf/got-page-4a.s, ld-mips-elf/got-page-4b.s, ld-mips-elf/got-page-4a.d, ld-mips-elf/got-page-4a.got, ld-mips-elf/got-page-4b.d, ld-mips-elf/got-page-4b.got, ld-mips-elf/got-page-5.s, ld-mips-elf/got-page-5.d, ld-mips-elf/got-page-5.got, ld-mips-elf/got-page-6.s, ld-mips-elf/got-page-6.d, ld-mips-elf/got-page-6.got, ld-mips-elf/got-page-7a.s, ld-mips-elf/got-page-7b.s, ld-mips-elf/got-page-7c.s, ld-mips-elf/got-page-7d.s, ld-mips-elf/got-page-7e.s, ld-mips-elf/got-page-7.d, ld-mips-elf/got-page-7.got: New tests. * ld-mips-elf/mips-elf.exp: Run them.
-rw-r--r--bfd/ChangeLog26
-rw-r--r--bfd/elfxx-mips.c416
-rw-r--r--ld/testsuite/ChangeLog16
-rw-r--r--ld/testsuite/ld-mips-elf/got-page-4a.d35
-rw-r--r--ld/testsuite/ld-mips-elf/got-page-4a.got7
-rw-r--r--ld/testsuite/ld-mips-elf/got-page-4a.s14
-rw-r--r--ld/testsuite/ld-mips-elf/got-page-4b.d36
-rw-r--r--ld/testsuite/ld-mips-elf/got-page-4b.got21
-rw-r--r--ld/testsuite/ld-mips-elf/got-page-4b.s21
-rw-r--r--ld/testsuite/ld-mips-elf/got-page-5.d10
-rw-r--r--ld/testsuite/ld-mips-elf/got-page-5.got8
-rw-r--r--ld/testsuite/ld-mips-elf/got-page-5.s31
-rw-r--r--ld/testsuite/ld-mips-elf/got-page-6.d10
-rw-r--r--ld/testsuite/ld-mips-elf/got-page-6.got6
-rw-r--r--ld/testsuite/ld-mips-elf/got-page-6.s27
-rw-r--r--ld/testsuite/ld-mips-elf/got-page-7.d17
-rw-r--r--ld/testsuite/ld-mips-elf/got-page-7.got7
-rw-r--r--ld/testsuite/ld-mips-elf/got-page-7a.s6
-rw-r--r--ld/testsuite/ld-mips-elf/got-page-7b.s6
-rw-r--r--ld/testsuite/ld-mips-elf/got-page-7c.s6
-rw-r--r--ld/testsuite/ld-mips-elf/got-page-7d.s6
-rw-r--r--ld/testsuite/ld-mips-elf/got-page-7e.s6
-rw-r--r--ld/testsuite/ld-mips-elf/mips-elf.exp40
-rw-r--r--ld/testsuite/ld-mips-elf/mips16-pic-2.dd4
-rw-r--r--ld/testsuite/ld-mips-elf/mips16-pic-2.gd11
25 files changed, 664 insertions, 129 deletions
diff --git a/bfd/ChangeLog b/bfd/ChangeLog
index 6c28481..21c9396 100644
--- a/bfd/ChangeLog
+++ b/bfd/ChangeLog
@@ -1,3 +1,29 @@
+2013-02-13 Richard Sandiford <rdsandiford@googlemail.com>
+
+ * elfxx-mips.c (mips_got_page_ref): New structure.
+ (mips_got_page_entry): Use a section rather than a (bfd, symndx)
+ pair to represent the anchor point.
+ (mips_got_info): Add a got_page_refs field.
+ (mips_elf_link_hash_table): Add a sym_cache field.
+ (mips_got_page_ref_hash, mips_got_page_ref_eq): New functions.
+ (mips_got_page_entry_hash, mips_got_page_entry_eq): Update for
+ new anchor representation.
+ (mips_elf_create_got_info): Create got_page_refs rather than
+ got_page_entries.
+ (mips_elf_record_got_page_ref): New function.
+ (mips_elf_pages_for_range): Move further down file.
+ (mips_elf_record_got_page_entry): Likewise. Take a got as argument.
+ Use a section rather than a (bfd, symndx) pair to represent the
+ anchor point.
+ (mips_elf_resolve_got_page_ref): New function.
+ (mips_elf_resolve_final_got_entries): Use it to populate
+ got_page_entries.
+ (_bfd_mips_elf_check_relocs): Call mips_elf_record_got_page_ref
+ rather than mips_elf_record_got_page_entry. Only nullify h
+ afterwards.
+ (mips_elf_lay_out_got): Call mips_elf_resolve_final_got_entries
+ earlier.
+
2013-02-12 Richard Sandiford <rdsandiford@googlemail.com>
* elfxx-mips.c (mips_elf_lay_out_got): Count VxWorks GOT relocs
diff --git a/bfd/elfxx-mips.c b/bfd/elfxx-mips.c
index 1d4586f..282a464 100644
--- a/bfd/elfxx-mips.c
+++ b/bfd/elfxx-mips.c
@@ -108,6 +108,27 @@ struct mips_got_entry
long gotidx;
};
+/* This structure represents a GOT page reference from an input bfd.
+ Each instance represents a symbol + ADDEND, where the representation
+ of the symbol depends on whether it is local to the input bfd.
+ If it is, then SYMNDX >= 0, and the symbol has index SYMNDX in U.ABFD.
+ Otherwise, SYMNDX < 0 and U.H points to the symbol's hash table entry.
+
+ Page references with SYMNDX >= 0 always become page references
+ in the output. Page references with SYMNDX < 0 only become page
+ references if the symbol binds locally; in other cases, the page
+ reference decays to a global GOT reference. */
+struct mips_got_page_ref
+{
+ long symndx;
+ union
+ {
+ struct mips_elf_link_hash_entry *h;
+ bfd *abfd;
+ } u;
+ bfd_vma addend;
+};
+
/* This structure describes a range of addends: [MIN_ADDEND, MAX_ADDEND].
The structures form a non-overlapping list that is sorted by increasing
MIN_ADDEND. */
@@ -119,13 +140,11 @@ struct mips_got_page_range
};
/* This structure describes the range of addends that are applied to page
- relocations against a given symbol. */
+ relocations against a given section. */
struct mips_got_page_entry
{
- /* The input bfd in which the symbol is defined. */
- bfd *abfd;
- /* The index of the symbol, as stored in the relocation r_info. */
- long symndx;
+ /* The section that these entries are based on. */
+ asection *sec;
/* The ranges for this page entry. */
struct mips_got_page_range *ranges;
/* The maximum number of page entries needed for RANGES. */
@@ -155,6 +174,8 @@ struct mips_got_info
unsigned int assigned_gotno;
/* A hash table holding members of the got. */
struct htab *got_entries;
+ /* A hash table holding mips_got_page_ref structures. */
+ struct htab *got_page_refs;
/* A hash table of mips_got_page_entry structures. */
struct htab *got_page_entries;
/* In multi-got links, a pointer to the next got (err, rather, most
@@ -444,6 +465,9 @@ struct mips_elf_link_hash_table
The function returns the new section on success, otherwise it
returns null. */
asection *(*add_stub_section) (const char *, asection *, asection *);
+
+ /* Small local sym cache. */
+ struct sym_cache sym_cache;
};
/* Get the MIPS ELF linker hash table from a link_info structure. */
@@ -2771,12 +2795,38 @@ mips_elf_got_entry_eq (const void *entry1, const void *entry2)
}
static hashval_t
+mips_got_page_ref_hash (const void *ref_)
+{
+ const struct mips_got_page_ref *ref;
+
+ ref = (const struct mips_got_page_ref *) ref_;
+ return ((ref->symndx >= 0
+ ? (hashval_t) (ref->u.abfd->id + ref->symndx)
+ : ref->u.h->root.root.root.hash)
+ + mips_elf_hash_bfd_vma (ref->addend));
+}
+
+static int
+mips_got_page_ref_eq (const void *ref1_, const void *ref2_)
+{
+ const struct mips_got_page_ref *ref1, *ref2;
+
+ ref1 = (const struct mips_got_page_ref *) ref1_;
+ ref2 = (const struct mips_got_page_ref *) ref2_;
+ return (ref1->symndx == ref2->symndx
+ && (ref1->symndx < 0
+ ? ref1->u.h == ref2->u.h
+ : ref1->u.abfd == ref2->u.abfd)
+ && ref1->addend == ref2->addend);
+}
+
+static hashval_t
mips_got_page_entry_hash (const void *entry_)
{
const struct mips_got_page_entry *entry;
entry = (const struct mips_got_page_entry *) entry_;
- return entry->abfd->id + entry->symndx;
+ return entry->sec->id;
}
static int
@@ -2786,7 +2836,7 @@ mips_got_page_entry_eq (const void *entry1_, const void *entry2_)
entry1 = (const struct mips_got_page_entry *) entry1_;
entry2 = (const struct mips_got_page_entry *) entry2_;
- return entry1->abfd == entry2->abfd && entry1->symndx == entry2->symndx;
+ return entry1->sec == entry2->sec;
}
/* Create and return a new mips_got_info structure. */
@@ -2805,9 +2855,9 @@ mips_elf_create_got_info (bfd *abfd)
if (g->got_entries == NULL)
return NULL;
- g->got_page_entries = htab_try_create (1, mips_got_page_entry_hash,
- mips_got_page_entry_eq, NULL);
- if (g->got_page_entries == NULL)
+ g->got_page_refs = htab_try_create (1, mips_got_page_ref_hash,
+ mips_got_page_ref_eq, NULL);
+ if (g->got_page_refs == NULL)
return NULL;
return g;
@@ -2844,7 +2894,9 @@ mips_elf_replace_bfd_got (bfd *abfd, struct mips_got_info *g)
/* 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);
+ htab_delete (tdata->got->got_page_refs);
+ if (tdata->got->got_page_entries)
+ htab_delete (tdata->got->got_page_entries);
}
tdata->got = g;
}
@@ -3691,30 +3743,18 @@ mips_elf_record_local_got_symbol (bfd *abfd, long symndx, bfd_vma addend,
return mips_elf_record_got_entry (info, abfd, &entry);
}
-/* Return the maximum number of GOT page entries required for RANGE. */
-
-static bfd_vma
-mips_elf_pages_for_range (const struct mips_got_page_range *range)
-{
- return (range->max_addend - range->min_addend + 0x1ffff) >> 16;
-}
-
-/* Record that ABFD has a page relocation against symbol SYMNDX and
- that ADDEND is the addend for that relocation.
-
- This function creates an upper bound on the number of GOT slots
- required; no attempt is made to combine references to non-overridable
- global symbols across multiple input files. */
+/* Record that ABFD has a page relocation against SYMNDX + ADDEND.
+ H is the symbol's hash table entry, or null if SYMNDX is local
+ to ABFD. */
static bfd_boolean
-mips_elf_record_got_page_entry (struct bfd_link_info *info, bfd *abfd,
- long symndx, bfd_signed_vma addend)
+mips_elf_record_got_page_ref (struct bfd_link_info *info, bfd *abfd,
+ long symndx, struct elf_link_hash_entry *h,
+ bfd_signed_vma addend)
{
struct mips_elf_link_hash_table *htab;
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;
+ struct mips_got_page_ref lookup, *entry;
void **loc, **bfd_loc;
htab = mips_elf_hash_table (info);
@@ -3723,26 +3763,29 @@ mips_elf_record_got_page_entry (struct bfd_link_info *info, bfd *abfd,
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 (g1->got_page_entries, &lookup, INSERT);
+ if (h)
+ {
+ lookup.symndx = -1;
+ lookup.u.h = (struct mips_elf_link_hash_entry *) h;
+ }
+ else
+ {
+ lookup.symndx = symndx;
+ lookup.u.abfd = abfd;
+ }
+ lookup.addend = addend;
+ loc = htab_find_slot (g1->got_page_refs, &lookup, INSERT);
if (loc == NULL)
return FALSE;
- /* Create a mips_got_page_entry if this is the first time we've
- seen the symbol. */
- entry = (struct mips_got_page_entry *) *loc;
+ entry = (struct mips_got_page_ref *) *loc;
if (!entry)
{
entry = bfd_alloc (abfd, sizeof (*entry));
if (!entry)
return FALSE;
- entry->abfd = abfd;
- entry->symndx = symndx;
- entry->ranges = NULL;
- entry->num_pages = 0;
+ *entry = lookup;
*loc = entry;
}
@@ -3751,67 +3794,13 @@ mips_elf_record_got_page_entry (struct bfd_link_info *info, bfd *abfd,
if (!g2)
return FALSE;
- bfd_loc = htab_find_slot (g2->got_page_entries, &lookup, INSERT);
+ bfd_loc = htab_find_slot (g2->got_page_refs, &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;
- while (*range_ptr && addend > (*range_ptr)->max_addend + 0xffff)
- range_ptr = &(*range_ptr)->next;
-
- /* If we scanned to the end of the list, or found a range whose
- minimum extent cannot share a page entry with ADDEND, create
- a new singleton range. */
- range = *range_ptr;
- if (!range || addend < range->min_addend - 0xffff)
- {
- range = bfd_alloc (abfd, sizeof (*range));
- if (!range)
- return FALSE;
-
- range->next = *range_ptr;
- range->min_addend = addend;
- range->max_addend = addend;
-
- *range_ptr = range;
- entry->num_pages++;
- g1->page_gotno++;
- g2->page_gotno++;
- return TRUE;
- }
-
- /* Remember how many pages the old range contributed. */
- old_pages = mips_elf_pages_for_range (range);
-
- /* Update the ranges. */
- if (addend < range->min_addend)
- range->min_addend = addend;
- else if (addend > range->max_addend)
- {
- if (range->next && addend >= range->next->min_addend - 0xffff)
- {
- old_pages += mips_elf_pages_for_range (range->next);
- range->max_addend = range->next->max_addend;
- range->next = range->next->next;
- }
- else
- range->max_addend = addend;
- }
-
- /* Record any change in the total estimate. */
- new_pages = mips_elf_pages_for_range (range);
- if (old_pages != new_pages)
- {
- entry->num_pages += new_pages - old_pages;
- g1->page_gotno += new_pages - old_pages;
- g2->page_gotno += new_pages - old_pages;
- }
-
return TRUE;
}
@@ -3930,8 +3919,188 @@ mips_elf_recreate_got (void **entryp, void *data)
return 1;
}
+/* Return the maximum number of GOT page entries required for RANGE. */
+
+static bfd_vma
+mips_elf_pages_for_range (const struct mips_got_page_range *range)
+{
+ return (range->max_addend - range->min_addend + 0x1ffff) >> 16;
+}
+
+/* Record that G requires a page entry that can reach SEC + ADDEND. */
+
+static bfd_boolean
+mips_elf_record_got_page_entry (struct mips_got_info *g,
+ asection *sec, bfd_signed_vma addend)
+{
+ struct mips_got_page_entry lookup, *entry;
+ struct mips_got_page_range **range_ptr, *range;
+ bfd_vma old_pages, new_pages;
+ void **loc;
+
+ /* Find the mips_got_page_entry hash table entry for this section. */
+ lookup.sec = sec;
+ loc = htab_find_slot (g->got_page_entries, &lookup, INSERT);
+ if (loc == NULL)
+ return FALSE;
+
+ /* Create a mips_got_page_entry if this is the first time we've
+ seen the section. */
+ entry = (struct mips_got_page_entry *) *loc;
+ if (!entry)
+ {
+ entry = bfd_zalloc (sec->owner, sizeof (*entry));
+ if (!entry)
+ return FALSE;
+
+ entry->sec = sec;
+ *loc = entry;
+ }
+
+ /* Skip over ranges whose maximum extent cannot share a page entry
+ with ADDEND. */
+ range_ptr = &entry->ranges;
+ while (*range_ptr && addend > (*range_ptr)->max_addend + 0xffff)
+ range_ptr = &(*range_ptr)->next;
+
+ /* If we scanned to the end of the list, or found a range whose
+ minimum extent cannot share a page entry with ADDEND, create
+ a new singleton range. */
+ range = *range_ptr;
+ if (!range || addend < range->min_addend - 0xffff)
+ {
+ range = bfd_zalloc (sec->owner, sizeof (*range));
+ if (!range)
+ return FALSE;
+
+ range->next = *range_ptr;
+ range->min_addend = addend;
+ range->max_addend = addend;
+
+ *range_ptr = range;
+ entry->num_pages++;
+ g->page_gotno++;
+ return TRUE;
+ }
+
+ /* Remember how many pages the old range contributed. */
+ old_pages = mips_elf_pages_for_range (range);
+
+ /* Update the ranges. */
+ if (addend < range->min_addend)
+ range->min_addend = addend;
+ else if (addend > range->max_addend)
+ {
+ if (range->next && addend >= range->next->min_addend - 0xffff)
+ {
+ old_pages += mips_elf_pages_for_range (range->next);
+ range->max_addend = range->next->max_addend;
+ range->next = range->next->next;
+ }
+ else
+ range->max_addend = addend;
+ }
+
+ /* Record any change in the total estimate. */
+ new_pages = mips_elf_pages_for_range (range);
+ if (old_pages != new_pages)
+ {
+ entry->num_pages += new_pages - old_pages;
+ g->page_gotno += new_pages - old_pages;
+ }
+
+ return TRUE;
+}
+
+/* A htab_traverse callback for which *REFP points to a mips_got_page_ref
+ and for which DATA points to a mips_elf_traverse_got_arg. Work out
+ whether the page reference described by *REFP needs a GOT page entry,
+ and record that entry in DATA->g if so. Set DATA->g to null on failure. */
+
+static bfd_boolean
+mips_elf_resolve_got_page_ref (void **refp, void *data)
+{
+ struct mips_got_page_ref *ref;
+ struct mips_elf_traverse_got_arg *arg;
+ struct mips_elf_link_hash_table *htab;
+ asection *sec;
+ bfd_vma addend;
+
+ ref = (struct mips_got_page_ref *) *refp;
+ arg = (struct mips_elf_traverse_got_arg *) data;
+ htab = mips_elf_hash_table (arg->info);
+
+ if (ref->symndx < 0)
+ {
+ struct mips_elf_link_hash_entry *h;
+
+ /* Global GOT_PAGEs decay to GOT_DISP and so don't need page entries. */
+ h = ref->u.h;
+ if (!SYMBOL_REFERENCES_LOCAL (arg->info, &h->root))
+ return 1;
+
+ /* Ignore undefined symbols; we'll issue an error later if
+ appropriate. */
+ if (!((h->root.root.type == bfd_link_hash_defined
+ || h->root.root.type == bfd_link_hash_defweak)
+ && h->root.root.u.def.section))
+ return 1;
+
+ sec = h->root.root.u.def.section;
+ addend = h->root.root.u.def.value + ref->addend;
+ }
+ else
+ {
+ Elf_Internal_Sym *isym;
+
+ /* Read in the symbol. */
+ isym = bfd_sym_from_r_symndx (&htab->sym_cache, ref->u.abfd,
+ ref->symndx);
+ if (isym == NULL)
+ {
+ arg->g = NULL;
+ return 0;
+ }
+
+ /* Get the associated input section. */
+ sec = bfd_section_from_elf_index (ref->u.abfd, isym->st_shndx);
+ if (sec == NULL)
+ {
+ arg->g = NULL;
+ return 0;
+ }
+
+ /* If this is a mergable section, work out the section and offset
+ of the merged data. For section symbols, the addend specifies
+ of the offset _of_ the first byte in the data, otherwise it
+ specifies the offset _from_ the first byte. */
+ if (sec->flags & SEC_MERGE)
+ {
+ void *secinfo;
+
+ secinfo = elf_section_data (sec)->sec_info;
+ if (ELF_ST_TYPE (isym->st_info) == STT_SECTION)
+ addend = _bfd_merged_section_offset (ref->u.abfd, &sec, secinfo,
+ isym->st_value + ref->addend);
+ else
+ addend = _bfd_merged_section_offset (ref->u.abfd, &sec, secinfo,
+ isym->st_value) + ref->addend;
+ }
+ else
+ addend = isym->st_value + ref->addend;
+ }
+ if (!mips_elf_record_got_page_entry (arg->g, sec, addend))
+ {
+ arg->g = NULL;
+ return 0;
+ }
+ return 1;
+}
+
/* If any entries in G->got_entries are for indirect or warning symbols,
- replace them with entries for the target symbol. */
+ replace them with entries for the target symbol. Convert g->got_page_refs
+ into got_page_entry structures and estimate the number of page entries
+ that they require. */
static bfd_boolean
mips_elf_resolve_final_got_entries (struct bfd_link_info *info,
@@ -3961,6 +4130,16 @@ mips_elf_resolve_final_got_entries (struct bfd_link_info *info,
htab_delete (oldg.got_entries);
}
+
+ g->got_page_entries = htab_try_create (1, mips_got_page_entry_hash,
+ mips_got_page_entry_eq, NULL);
+ if (g->got_page_entries == NULL)
+ return FALSE;
+
+ tga.info = info;
+ tga.g = g;
+ htab_traverse (g->got_page_refs, mips_elf_resolve_got_page_ref, &tga);
+
return TRUE;
}
@@ -7823,21 +8002,6 @@ _bfd_mips_elf_check_relocs (bfd *abfd, struct bfd_link_info *info,
case R_MIPS_GOT_PAGE:
case R_MICROMIPS_GOT_PAGE:
- /* If this is a global, overridable symbol, GOT_PAGE will
- decay to GOT_DISP, so we'll need a GOT entry for it. */
- if (h)
- {
- struct mips_elf_link_hash_entry *hmips =
- (struct mips_elf_link_hash_entry *) h;
-
- /* This symbol is definitely not overridable. */
- if (hmips->root.def_regular
- && ! (info->shared && ! info->symbolic
- && ! hmips->root.forced_local))
- h = NULL;
- }
- /* Fall through. */
-
case R_MIPS16_GOT16:
case R_MIPS_GOT16:
case R_MIPS_GOT_HI16:
@@ -7866,10 +8030,24 @@ _bfd_mips_elf_check_relocs (bfd *abfd, struct bfd_link_info *info,
}
else
addend = rel->r_addend;
- if (!mips_elf_record_got_page_entry (info, abfd, r_symndx,
- addend))
+ if (!mips_elf_record_got_page_ref (info, abfd, r_symndx,
+ h, addend))
return FALSE;
+
+ if (h)
+ {
+ struct mips_elf_link_hash_entry *hmips =
+ (struct mips_elf_link_hash_entry *) h;
+
+ /* This symbol is definitely not overridable. */
+ if (hmips->root.def_regular
+ && ! (info->shared && ! info->symbolic
+ && ! hmips->root.forced_local))
+ h = NULL;
+ }
}
+ /* If this is a global, overridable symbol, GOT_PAGE will
+ decay to GOT_DISP, so we'll need a GOT entry for it. */
/* Fall through. */
case R_MIPS_GOT_DISP:
@@ -8602,6 +8780,9 @@ mips_elf_lay_out_got (bfd *output_bfd, struct bfd_link_info *info)
count the number of reloc-only GOT symbols. */
mips_elf_link_hash_traverse (htab, mips_elf_count_got_symbols, info);
+ if (!mips_elf_resolve_final_got_entries (info, g))
+ return FALSE;
+
/* Calculate the total loadable size of the output. That
will give us the maximum number of GOT_PAGE entries
required. */
@@ -8630,18 +8811,13 @@ mips_elf_lay_out_got (bfd *output_bfd, struct bfd_link_info *info)
sections. Is 5 enough? */
page_gotno = (loadable_size >> 16) + 5;
- /* Choose the smaller of the two estimates; both are intended to be
+ /* Choose the smaller of the two page estimates; both are intended to be
conservative. */
if (page_gotno > g->page_gotno)
page_gotno = g->page_gotno;
g->local_gotno += page_gotno;
- /* Replace entries for indirect and warning symbols with entries for
- the target symbol. Count the number of GOT entries and TLS relocs. */
- if (!mips_elf_resolve_final_got_entries (info, g))
- return FALSE;
-
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->tls_gotno * MIPS_ELF_GOT_SIZE (output_bfd);
diff --git a/ld/testsuite/ChangeLog b/ld/testsuite/ChangeLog
index 376b119..e1a7e4a 100644
--- a/ld/testsuite/ChangeLog
+++ b/ld/testsuite/ChangeLog
@@ -1,3 +1,19 @@
+2013-02-13 Richard Sandiford <rdsandiford@googlemail.com>
+
+ * ld-mips-elf/mips16-pic-2.dd,
+ ld-mips-elf/mips16-pic-2.gd: Remove 3 unused local GOT entries.
+ * ld-mips-elf/got-page-4a.s, ld-mips-elf/got-page-4b.s,
+ ld-mips-elf/got-page-4a.d, ld-mips-elf/got-page-4a.got,
+ ld-mips-elf/got-page-4b.d, ld-mips-elf/got-page-4b.got,
+ ld-mips-elf/got-page-5.s, ld-mips-elf/got-page-5.d,
+ ld-mips-elf/got-page-5.got, ld-mips-elf/got-page-6.s,
+ ld-mips-elf/got-page-6.d, ld-mips-elf/got-page-6.got,
+ ld-mips-elf/got-page-7a.s, ld-mips-elf/got-page-7b.s,
+ ld-mips-elf/got-page-7c.s, ld-mips-elf/got-page-7d.s,
+ ld-mips-elf/got-page-7e.s, ld-mips-elf/got-page-7.d,
+ ld-mips-elf/got-page-7.got: New tests.
+ * ld-mips-elf/mips-elf.exp: Run them.
+
2013-02-11 Richard Sandiford <rdsandiford@googlemail.com>
* ld-mips-elf/tlsdyn-o32-1.d, ld-mips-elf/tlsdyn-o32-1.got,
diff --git a/ld/testsuite/ld-mips-elf/got-page-4a.d b/ld/testsuite/ld-mips-elf/got-page-4a.d
new file mode 100644
index 0000000..0ff341e
--- /dev/null
+++ b/ld/testsuite/ld-mips-elf/got-page-4a.d
@@ -0,0 +1,35 @@
+#...
+.* <foo>:
+.* lw a0,-32744\(gp\)
+.* addiu a0,a0,0
+.* lw a0,-32744\(gp\)
+.* addiu a0,a0,4
+.* lw a0,-32744\(gp\)
+.* addiu a0,a0,8
+.* lw a0,-32744\(gp\)
+.* addiu a0,a0,12
+.* lw a0,-32744\(gp\)
+.* addiu a0,a0,16
+.* lw a0,-32744\(gp\)
+.* addiu a0,a0,20
+.* lw a0,-32744\(gp\)
+.* addiu a0,a0,24
+.* lw a0,-32744\(gp\)
+.* addiu a0,a0,28
+.* lw a0,-32744\(gp\)
+.* addiu a0,a0,32
+.* lw a0,-32744\(gp\)
+.* addiu a0,a0,36
+.* lw a0,-32744\(gp\)
+.* addiu a0,a0,40
+.* lw a0,-32744\(gp\)
+.* addiu a0,a0,44
+.* lw a0,-32744\(gp\)
+.* addiu a0,a0,48
+.* lw a0,-32744\(gp\)
+.* addiu a0,a0,52
+.* lw a0,-32744\(gp\)
+.* addiu a0,a0,56
+.* lw a0,-32744\(gp\)
+.* addiu a0,a0,60
+#pass
diff --git a/ld/testsuite/ld-mips-elf/got-page-4a.got b/ld/testsuite/ld-mips-elf/got-page-4a.got
new file mode 100644
index 0000000..9b1308e
--- /dev/null
+++ b/ld/testsuite/ld-mips-elf/got-page-4a.got
@@ -0,0 +1,7 @@
+#...
+ Local entries:
+ Address Access Initial
+ 00090008 -32744\(gp\) 00080000
+ 0009000c -32740\(gp\) 00000000
+
+#pass
diff --git a/ld/testsuite/ld-mips-elf/got-page-4a.s b/ld/testsuite/ld-mips-elf/got-page-4a.s
new file mode 100644
index 0000000..4c8163e
--- /dev/null
+++ b/ld/testsuite/ld-mips-elf/got-page-4a.s
@@ -0,0 +1,14 @@
+ .section .rodata.cst4,"aM",@progbits,4
+ .set x,0x01000000
+ .set y,0x02000000
+ # Add the 16 values that the next input file wants, but in such
+ # a way that each one lives on a separate page.
+ .rept 15
+ .word y
+ .set y,y+1
+ .rept 0x4000
+ .word x
+ .set x,x+1
+ .endr
+ .endr
+ .word y
diff --git a/ld/testsuite/ld-mips-elf/got-page-4b.d b/ld/testsuite/ld-mips-elf/got-page-4b.d
new file mode 100644
index 0000000..2917c33
--- /dev/null
+++ b/ld/testsuite/ld-mips-elf/got-page-4b.d
@@ -0,0 +1,36 @@
+#...
+.* <foo>:
+.* lw a0,-32744\(gp\)
+.* addiu a0,a0,0
+.* lw a0,-32740\(gp\)
+.* addiu a0,a0,4
+.* lw a0,-32736\(gp\)
+.* addiu a0,a0,8
+.* lw a0,-32732\(gp\)
+.* addiu a0,a0,12
+.* lw a0,-32728\(gp\)
+.* addiu a0,a0,16
+.* lw a0,-32724\(gp\)
+.* addiu a0,a0,20
+.* lw a0,-32720\(gp\)
+.* addiu a0,a0,24
+.* lw a0,-32716\(gp\)
+.* addiu a0,a0,28
+.* lw a0,-32712\(gp\)
+.* addiu a0,a0,32
+.* lw a0,-32708\(gp\)
+.* addiu a0,a0,36
+.* lw a0,-32704\(gp\)
+.* addiu a0,a0,40
+.* lw a0,-32700\(gp\)
+.* addiu a0,a0,44
+.* lw a0,-32696\(gp\)
+.* addiu a0,a0,48
+.* lw a0,-32692\(gp\)
+.* addiu a0,a0,52
+.* lw a0,-32688\(gp\)
+.* addiu a0,a0,56
+.* lw a0,-32684\(gp\)
+.* addiu a0,a0,60
+
+#pass
diff --git a/ld/testsuite/ld-mips-elf/got-page-4b.got b/ld/testsuite/ld-mips-elf/got-page-4b.got
new file mode 100644
index 0000000..0e223b5
--- /dev/null
+++ b/ld/testsuite/ld-mips-elf/got-page-4b.got
@@ -0,0 +1,21 @@
+#...
+ Local entries:
+ Address Access Initial
+ 00180008 -32744\(gp\) 00080000
+ 0018000c -32740\(gp\) 00090000
+ 00180010 -32736\(gp\) 000a0000
+ 00180014 -32732\(gp\) 000b0000
+ 00180018 -32728\(gp\) 000c0000
+ 0018001c -32724\(gp\) 000d0000
+ 00180020 -32720\(gp\) 000e0000
+ 00180024 -32716\(gp\) 000f0000
+ 00180028 -32712\(gp\) 00100000
+ 0018002c -32708\(gp\) 00110000
+ 00180030 -32704\(gp\) 00120000
+ 00180034 -32700\(gp\) 00130000
+ 00180038 -32696\(gp\) 00140000
+ 0018003c -32692\(gp\) 00150000
+ 00180040 -32688\(gp\) 00160000
+ 00180044 -32684\(gp\) 00170000
+
+#pass
diff --git a/ld/testsuite/ld-mips-elf/got-page-4b.s b/ld/testsuite/ld-mips-elf/got-page-4b.s
new file mode 100644
index 0000000..eab5277
--- /dev/null
+++ b/ld/testsuite/ld-mips-elf/got-page-4b.s
@@ -0,0 +1,21 @@
+ .globl foo
+ .ent foo
+foo:
+ # Create page references to 16 values. The layout of the values
+ # in this input file requires at most 2 page entries.
+ .set y,0x02000000
+ .rept 16
+ lw $4,%got_page(1f)($gp)
+ addiu $4,$4,%got_ofst(1f)
+ .section .rodata.cst4,"aM",@progbits,4
+1: .word y
+ .set y,y+1
+ .text
+ .endr
+ .end foo
+
+ # Make sure the loadable size of the library is large.
+ .section .bss
+ .globl g
+g:
+ .space 0x800000
diff --git a/ld/testsuite/ld-mips-elf/got-page-5.d b/ld/testsuite/ld-mips-elf/got-page-5.d
new file mode 100644
index 0000000..5706d98
--- /dev/null
+++ b/ld/testsuite/ld-mips-elf/got-page-5.d
@@ -0,0 +1,10 @@
+#...
+.* <foo>:
+.* lw a0,-32744\(gp\)
+.* addiu a0,a0,0
+.* lw a0,-32740\(gp\)
+.* addiu a0,a0,-32768
+.* lw a0,-32740\(gp\)
+.* addiu a0,a0,0
+.* lw a0,-32736\(gp\)
+.* addiu a0,a0,-32768
diff --git a/ld/testsuite/ld-mips-elf/got-page-5.got b/ld/testsuite/ld-mips-elf/got-page-5.got
new file mode 100644
index 0000000..0a76be8
--- /dev/null
+++ b/ld/testsuite/ld-mips-elf/got-page-5.got
@@ -0,0 +1,8 @@
+#...
+ Local entries:
+ Address Access Initial
+ 00090008 -32744\(gp\) 00080000
+ 0009000c -32740\(gp\) 00090000
+ 00090010 -32736\(gp\) 000a0000
+
+#pass
diff --git a/ld/testsuite/ld-mips-elf/got-page-5.s b/ld/testsuite/ld-mips-elf/got-page-5.s
new file mode 100644
index 0000000..5051263
--- /dev/null
+++ b/ld/testsuite/ld-mips-elf/got-page-5.s
@@ -0,0 +1,31 @@
+ # Create a mergeable section full of a single value,
+ # and page references relative to one entry called "data".
+ #
+ # The mergeable entries collapse to one, but the offsets
+ # from "data" must still be retained, and need 3 page entries.
+ #
+ # Technically this isn't valid, because it creates out-of-section
+ # page references. It's still a useful way of making sure that
+ # offsets in mergeable sections are handled correctly.
+ .globl foo
+ .ent foo
+foo:
+ .set y,0
+ .rept 4
+ lw $4,%got_page(data + y)($gp)
+ addiu $4,$4,%got_ofst(data + y)
+ .set y,y+0x8000
+ .endr
+ .end foo
+
+ .section .rodata.cst4,"aM",@progbits,4
+data:
+ .rept 0x8000*4
+ .word 123456
+ .endr
+
+ # Make sure the loadable size of the library is large.
+ .section .bss
+ .globl g
+g:
+ .space 0x800000
diff --git a/ld/testsuite/ld-mips-elf/got-page-6.d b/ld/testsuite/ld-mips-elf/got-page-6.d
new file mode 100644
index 0000000..90d6638
--- /dev/null
+++ b/ld/testsuite/ld-mips-elf/got-page-6.d
@@ -0,0 +1,10 @@
+#...
+.* <foo>:
+.* lw a0,-32744\(gp\)
+.* addiu a0,a0,0
+.* lw a0,-32744\(gp\)
+.* addiu a0,a0,0
+.* lw a0,-32744\(gp\)
+.* addiu a0,a0,0
+.* lw a0,-32744\(gp\)
+.* addiu a0,a0,0
diff --git a/ld/testsuite/ld-mips-elf/got-page-6.got b/ld/testsuite/ld-mips-elf/got-page-6.got
new file mode 100644
index 0000000..e385e8c
--- /dev/null
+++ b/ld/testsuite/ld-mips-elf/got-page-6.got
@@ -0,0 +1,6 @@
+#...
+ Local entries:
+ Address Access Initial
+ 00090008 -32744\(gp\) 00080000
+
+#pass
diff --git a/ld/testsuite/ld-mips-elf/got-page-6.s b/ld/testsuite/ld-mips-elf/got-page-6.s
new file mode 100644
index 0000000..c419e00
--- /dev/null
+++ b/ld/testsuite/ld-mips-elf/got-page-6.s
@@ -0,0 +1,27 @@
+ # Create a mergeable section full of a single value.
+ # Create page references relative to instances of the value
+ # that are large distances apart.
+ #
+ # The mergeable entries collapse to one, so even with the
+ # large distances in the original file, we should end
+ # up with a single page entry.
+ .globl foo
+ .ent foo
+foo:
+ .rept 4
+ lw $4,%got_page(1f)($gp)
+ addiu $4,$4,%got_ofst(1f)
+ .section .rodata.cst4,"aM",@progbits,4
+1:
+ .rept 0x8000
+ .word 123456
+ .endr
+ .text
+ .endr
+ .end foo
+
+ # Make sure the loadable size of the library is large.
+ .section .bss
+ .globl g
+g:
+ .space 0x800000
diff --git a/ld/testsuite/ld-mips-elf/got-page-7.d b/ld/testsuite/ld-mips-elf/got-page-7.d
new file mode 100644
index 0000000..12990b5
--- /dev/null
+++ b/ld/testsuite/ld-mips-elf/got-page-7.d
@@ -0,0 +1,17 @@
+#...
+.* <f1>:
+.* lw a0,-32744\(gp\)
+.* addiu a0,a0,1024
+#...
+.* <f2>:
+.* lw a0,-32744\(gp\)
+.* addiu a0,a0,17408
+#...
+.* <f3>:
+.* lw a0,-32740\(gp\)
+.* addiu a0,a0,-31744
+#...
+.* <f4>:
+.* lw a0,-32740\(gp\)
+.* addiu a0,a0,1024
+#pass
diff --git a/ld/testsuite/ld-mips-elf/got-page-7.got b/ld/testsuite/ld-mips-elf/got-page-7.got
new file mode 100644
index 0000000..0b5df20
--- /dev/null
+++ b/ld/testsuite/ld-mips-elf/got-page-7.got
@@ -0,0 +1,7 @@
+#...
+ Local entries:
+ Address Access Initial
+ 00090008 -32744\(gp\) 00090000
+ 0009000c -32740\(gp\) 000a0000
+
+#pass
diff --git a/ld/testsuite/ld-mips-elf/got-page-7a.s b/ld/testsuite/ld-mips-elf/got-page-7a.s
new file mode 100644
index 0000000..f03220b
--- /dev/null
+++ b/ld/testsuite/ld-mips-elf/got-page-7a.s
@@ -0,0 +1,6 @@
+ .globl f1
+ .ent f1
+f1:
+ lw $4,%got_page(g)($gp)
+ addiu $4,$4,%got_ofst(g)
+ .end f1
diff --git a/ld/testsuite/ld-mips-elf/got-page-7b.s b/ld/testsuite/ld-mips-elf/got-page-7b.s
new file mode 100644
index 0000000..4c9a0df
--- /dev/null
+++ b/ld/testsuite/ld-mips-elf/got-page-7b.s
@@ -0,0 +1,6 @@
+ .globl f2
+ .ent f2
+f2:
+ lw $4,%got_page(g + 0x4000)($gp)
+ addiu $4,$4,%got_ofst(g + 0x4000)
+ .end f2
diff --git a/ld/testsuite/ld-mips-elf/got-page-7c.s b/ld/testsuite/ld-mips-elf/got-page-7c.s
new file mode 100644
index 0000000..b957ecf
--- /dev/null
+++ b/ld/testsuite/ld-mips-elf/got-page-7c.s
@@ -0,0 +1,6 @@
+ .globl f3
+ .ent f3
+f3:
+ lw $4,%got_page(g + 0x8000)($gp)
+ addiu $4,$4,%got_ofst(g + 0x8000)
+ .end f3
diff --git a/ld/testsuite/ld-mips-elf/got-page-7d.s b/ld/testsuite/ld-mips-elf/got-page-7d.s
new file mode 100644
index 0000000..83ddb3a
--- /dev/null
+++ b/ld/testsuite/ld-mips-elf/got-page-7d.s
@@ -0,0 +1,6 @@
+ .globl f4
+ .ent f4
+f4:
+ lw $4,%got_page(g + 0x10000)($gp)
+ addiu $4,$4,%got_ofst(g + 0x10000)
+ .end f4
diff --git a/ld/testsuite/ld-mips-elf/got-page-7e.s b/ld/testsuite/ld-mips-elf/got-page-7e.s
new file mode 100644
index 0000000..c23382e
--- /dev/null
+++ b/ld/testsuite/ld-mips-elf/got-page-7e.s
@@ -0,0 +1,6 @@
+ # Make sure the loadable size of the library is large.
+ .section .bss
+ .globl g
+ .hidden g
+g:
+ .space 0x800000
diff --git a/ld/testsuite/ld-mips-elf/mips-elf.exp b/ld/testsuite/ld-mips-elf/mips-elf.exp
index 62c6cb0..9860488 100644
--- a/ld/testsuite/ld-mips-elf/mips-elf.exp
+++ b/ld/testsuite/ld-mips-elf/mips-elf.exp
@@ -453,6 +453,46 @@ if { $linux_gnu } {
run_dump_test "dyn-sec64"
}
run_dump_test "got-page-3"
+ run_ld_link_tests [subst {
+ {"GOT page 4 (one file)" "-shared $abi_ldflags(o32) -T got-page-1.ld"
+ "$abi_asflags(o32) -mips2" {got-page-4b.s}
+ {{objdump -dr got-page-4a.d}
+ {readelf -A got-page-4a.got}}
+ "got-page-4a.so"}
+ {"GOT page 4 (two files)" "-shared $abi_ldflags(o32) -T got-page-1.ld"
+ "$abi_asflags(o32) -mips2" {got-page-4a.s got-page-4b.s}
+ {{objdump -dr got-page-4b.d}
+ {readelf -A got-page-4b.got}}
+ "got-page-4b.so"}
+ }]
+ if $has_newabi {
+ run_ld_link_tests [subst {
+ {"GOT page 5" "-shared $abi_ldflags(n32) -T got-page-1.ld"
+ "$abi_asflags(n32)" {got-page-5.s}
+ {{objdump -dr got-page-5.d}
+ {readelf -A got-page-5.got}}
+ "got-page-5.so"}
+ {"GOT page 6" "-shared $abi_ldflags(n32) -T got-page-1.ld"
+ "$abi_asflags(n32)" {got-page-6.s}
+ {{objdump -dr got-page-6.d}
+ {readelf -A got-page-6.got}}
+ "got-page-6.so"}
+ {"GOT page 7 (order 1)" "-shared $abi_ldflags(n32) -T got-page-1.ld"
+ "$abi_asflags(n32)"
+ {got-page-7a.s got-page-7b.s got-page-7c.s got-page-7d.s
+ got-page-7e.s}
+ {{objdump -dr got-page-7.d}
+ {readelf -A got-page-7.got}}
+ "got-page-7a.so"}
+ {"GOT page 7 (order 2)" "-shared $abi_ldflags(n32) -T got-page-1.ld"
+ "$abi_asflags(n32)"
+ {got-page-7e.s got-page-7a.s got-page-7b.s got-page-7c.s
+ got-page-7d.s}
+ {{objdump -dr got-page-7.d}
+ {readelf -A got-page-7.got}}
+ "got-page-7b.so"}
+ }]
+ }
run_dump_test "got-dump-1"
if $has_newabi {
run_dump_test "got-dump-2"
diff --git a/ld/testsuite/ld-mips-elf/mips16-pic-2.dd b/ld/testsuite/ld-mips-elf/mips16-pic-2.dd
index 7052057..b2bdff2 100644
--- a/ld/testsuite/ld-mips-elf/mips16-pic-2.dd
+++ b/ld/testsuite/ld-mips-elf/mips16-pic-2.dd
@@ -77,7 +77,7 @@ Disassembly of section \.text:
.*: [^\t]* move t9,v0
.*: [^\t]* lw v0,16\(sp\)
.*: [^\t]* move gp,v0
-.*: [^\t]* lw v0,-32716\(v0\)
+.*: [^\t]* lw v0,-32728\(v0\)
.*: [^\t]* jalr v0
.*: [^\t]* move t9,v0
.*: [^\t]* lw v0,16\(sp\)
@@ -101,7 +101,7 @@ Disassembly of section \.text:
.*: [^\t]* move t9,v0
.*: [^\t]* lw v0,16\(sp\)
.*: [^\t]* move gp,v0
-.*: [^\t]* lw v0,-32712\(v0\)
+.*: [^\t]* lw v0,-32724\(v0\)
.*: [^\t]* jalr v0
.*: [^\t]* move t9,v0
.*: [^\t]* lw v0,16\(sp\)
diff --git a/ld/testsuite/ld-mips-elf/mips16-pic-2.gd b/ld/testsuite/ld-mips-elf/mips16-pic-2.gd
index d8d1451..c291bc8 100644
--- a/ld/testsuite/ld-mips-elf/mips16-pic-2.gd
+++ b/ld/testsuite/ld-mips-elf/mips16-pic-2.gd
@@ -13,14 +13,11 @@ Primary GOT:
0005000c -32740\(gp\) 00040409
00050010 -32736\(gp\) 0004040d
00050014 -32732\(gp\) 00000000
- 00050018 -32728\(gp\) 00000000
- 0005001c -32724\(gp\) 00000000
- 00050020 -32720\(gp\) 00000000
Global entries:
Address Access Initial Sym\.Val\. Type Ndx Name
- 00050024 -32716\(gp\) 00040574 00040574 FUNC 6 used6
- 00050028 -32712\(gp\) 00040598 00040598 FUNC 6 used7
- 0005002c -32708\(gp\) 00040550 00040550 FUNC 6 used5
- 00050030 -32704\(gp\) 0004052c 0004052c FUNC 6 used4
+ 00050018 -32728\(gp\) 00040574 00040574 FUNC 6 used6
+ 0005001c -32724\(gp\) 00040598 00040598 FUNC 6 used7
+ 00050020 -32720\(gp\) 00040550 00040550 FUNC 6 used5
+ 00050024 -32716\(gp\) 0004052c 0004052c FUNC 6 used4