Fix GOT overflow on MIPS with page references to mergeable sections
Richard Sandiford
rdsandiford@googlemail.com
Wed Feb 13 14:09:00 GMT 2013
It took longer than it should have done, but here's a patch to fix the
bug that Robert found: the counting of GOT page entries didn't work in
cases where a bfd has page references to multiple pieces of mergeable data,
some of which might end up resolving to input sections in other bfds
that are far away from the original.
The idea is to collect references during check_relocs, and only convert
them to page entries during size_dynamic_sections. This also has the
benefit of handling hidden global symbols.
The patch applies on top of the recent GOT rewrite patches, so it's only
suitable for mainline. Robert: could you check whether mainline CVS
now works with your original testcase?
Tested in the same way as the GOT rewrite patches. Applied.
Richard
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.
Index: bfd/elfxx-mips.c
===================================================================
--- bfd/elfxx-mips.c 2013-02-13 13:43:51.961189241 +0000
+++ bfd/elfxx-mips.c 2013-02-13 13:43:56.072215253 +0000
@@ -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 *entry
}
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 *entr
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, str
/* 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 *a
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 b
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 b
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, vo
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 (stru
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, s
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, s
}
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, s
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, s
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);
Index: ld/testsuite/ld-mips-elf/mips16-pic-2.dd
===================================================================
--- ld/testsuite/ld-mips-elf/mips16-pic-2.dd 2013-02-13 13:43:51.960189235 +0000
+++ ld/testsuite/ld-mips-elf/mips16-pic-2.dd 2013-02-13 13:43:56.073215259 +0000
@@ -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\)
Index: ld/testsuite/ld-mips-elf/mips16-pic-2.gd
===================================================================
--- ld/testsuite/ld-mips-elf/mips16-pic-2.gd 2013-02-13 13:43:51.864188625 +0000
+++ ld/testsuite/ld-mips-elf/mips16-pic-2.gd 2013-02-13 13:43:56.074215266 +0000
@@ -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
Index: ld/testsuite/ld-mips-elf/got-page-4a.s
===================================================================
--- /dev/null 2013-02-10 23:11:23.371797561 +0000
+++ ld/testsuite/ld-mips-elf/got-page-4a.s 2013-02-13 13:43:56.075215273 +0000
@@ -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
Index: ld/testsuite/ld-mips-elf/got-page-4b.s
===================================================================
--- /dev/null 2013-02-10 23:11:23.371797561 +0000
+++ ld/testsuite/ld-mips-elf/got-page-4b.s 2013-02-13 14:04:36.805756786 +0000
@@ -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
Index: ld/testsuite/ld-mips-elf/got-page-4a.d
===================================================================
--- /dev/null 2013-02-10 23:11:23.371797561 +0000
+++ ld/testsuite/ld-mips-elf/got-page-4a.d 2013-02-13 13:43:56.075215273 +0000
@@ -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
Index: ld/testsuite/ld-mips-elf/got-page-4a.got
===================================================================
--- /dev/null 2013-02-10 23:11:23.371797561 +0000
+++ ld/testsuite/ld-mips-elf/got-page-4a.got 2013-02-13 13:43:56.075215273 +0000
@@ -0,0 +1,7 @@
+#...
+ Local entries:
+ Address Access Initial
+ 00090008 -32744\(gp\) 00080000
+ 0009000c -32740\(gp\) 00000000
+
+#pass
Index: ld/testsuite/ld-mips-elf/got-page-4b.d
===================================================================
--- /dev/null 2013-02-10 23:11:23.371797561 +0000
+++ ld/testsuite/ld-mips-elf/got-page-4b.d 2013-02-13 13:43:56.076215279 +0000
@@ -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
Index: ld/testsuite/ld-mips-elf/got-page-4b.got
===================================================================
--- /dev/null 2013-02-10 23:11:23.371797561 +0000
+++ ld/testsuite/ld-mips-elf/got-page-4b.got 2013-02-13 13:43:56.076215279 +0000
@@ -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
Index: ld/testsuite/ld-mips-elf/got-page-5.s
===================================================================
--- /dev/null 2013-02-10 23:11:23.371797561 +0000
+++ ld/testsuite/ld-mips-elf/got-page-5.s 2013-02-13 13:43:56.078215292 +0000
@@ -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
Index: ld/testsuite/ld-mips-elf/got-page-5.d
===================================================================
--- /dev/null 2013-02-10 23:11:23.371797561 +0000
+++ ld/testsuite/ld-mips-elf/got-page-5.d 2013-02-13 13:43:56.077215285 +0000
@@ -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
Index: ld/testsuite/ld-mips-elf/got-page-5.got
===================================================================
--- /dev/null 2013-02-10 23:11:23.371797561 +0000
+++ ld/testsuite/ld-mips-elf/got-page-5.got 2013-02-13 13:43:56.078215292 +0000
@@ -0,0 +1,8 @@
+#...
+ Local entries:
+ Address Access Initial
+ 00090008 -32744\(gp\) 00080000
+ 0009000c -32740\(gp\) 00090000
+ 00090010 -32736\(gp\) 000a0000
+
+#pass
Index: ld/testsuite/ld-mips-elf/got-page-6.s
===================================================================
--- /dev/null 2013-02-10 23:11:23.371797561 +0000
+++ ld/testsuite/ld-mips-elf/got-page-6.s 2013-02-13 13:43:56.079215299 +0000
@@ -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
Index: ld/testsuite/ld-mips-elf/got-page-6.d
===================================================================
--- /dev/null 2013-02-10 23:11:23.371797561 +0000
+++ ld/testsuite/ld-mips-elf/got-page-6.d 2013-02-13 13:43:56.078215292 +0000
@@ -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
Index: ld/testsuite/ld-mips-elf/got-page-6.got
===================================================================
--- /dev/null 2013-02-10 23:11:23.371797561 +0000
+++ ld/testsuite/ld-mips-elf/got-page-6.got 2013-02-13 13:43:56.079215299 +0000
@@ -0,0 +1,6 @@
+#...
+ Local entries:
+ Address Access Initial
+ 00090008 -32744\(gp\) 00080000
+
+#pass
Index: ld/testsuite/ld-mips-elf/got-page-7a.s
===================================================================
--- /dev/null 2013-02-10 23:11:23.371797561 +0000
+++ ld/testsuite/ld-mips-elf/got-page-7a.s 2013-02-13 13:43:56.080215306 +0000
@@ -0,0 +1,6 @@
+ .globl f1
+ .ent f1
+f1:
+ lw $4,%got_page(g)($gp)
+ addiu $4,$4,%got_ofst(g)
+ .end f1
Index: ld/testsuite/ld-mips-elf/got-page-7b.s
===================================================================
--- /dev/null 2013-02-10 23:11:23.371797561 +0000
+++ ld/testsuite/ld-mips-elf/got-page-7b.s 2013-02-13 13:43:56.080215306 +0000
@@ -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
Index: ld/testsuite/ld-mips-elf/got-page-7c.s
===================================================================
--- /dev/null 2013-02-10 23:11:23.371797561 +0000
+++ ld/testsuite/ld-mips-elf/got-page-7c.s 2013-02-13 13:43:56.080215306 +0000
@@ -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
Index: ld/testsuite/ld-mips-elf/got-page-7d.s
===================================================================
--- /dev/null 2013-02-10 23:11:23.371797561 +0000
+++ ld/testsuite/ld-mips-elf/got-page-7d.s 2013-02-13 13:43:56.081215313 +0000
@@ -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
Index: ld/testsuite/ld-mips-elf/got-page-7e.s
===================================================================
--- /dev/null 2013-02-10 23:11:23.371797561 +0000
+++ ld/testsuite/ld-mips-elf/got-page-7e.s 2013-02-13 13:43:56.081215313 +0000
@@ -0,0 +1,6 @@
+ # Make sure the loadable size of the library is large.
+ .section .bss
+ .globl g
+ .hidden g
+g:
+ .space 0x800000
Index: ld/testsuite/ld-mips-elf/got-page-7.d
===================================================================
--- /dev/null 2013-02-10 23:11:23.371797561 +0000
+++ ld/testsuite/ld-mips-elf/got-page-7.d 2013-02-13 13:43:56.079215299 +0000
@@ -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
Index: ld/testsuite/ld-mips-elf/got-page-7.got
===================================================================
--- /dev/null 2013-02-10 23:11:23.371797561 +0000
+++ ld/testsuite/ld-mips-elf/got-page-7.got 2013-02-13 13:43:56.080215306 +0000
@@ -0,0 +1,7 @@
+#...
+ Local entries:
+ Address Access Initial
+ 00090008 -32744\(gp\) 00090000
+ 0009000c -32740\(gp\) 000a0000
+
+#pass
Index: ld/testsuite/ld-mips-elf/mips-elf.exp
===================================================================
--- ld/testsuite/ld-mips-elf/mips-elf.exp 2013-02-13 13:43:51.864188625 +0000
+++ ld/testsuite/ld-mips-elf/mips-elf.exp 2013-02-13 13:48:32.777929917 +0000
@@ -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"
More information about the Binutils
mailing list