* 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.
This commit is contained in:
Richard Sandiford 2013-02-13 14:08:58 +00:00
parent 1d3ffd6bfe
commit 13db6b44ea
25 changed files with 664 additions and 129 deletions

View File

@ -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

View File

@ -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. */
@ -2770,13 +2794,39 @@ mips_elf_got_entry_eq (const void *entry1, const void *entry2)
: e2->abfd && e1->d.h == e2->d.h));
}
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);

View File

@ -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,

View File

@ -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

View File

@ -0,0 +1,7 @@
#...
Local entries:
Address Access Initial
00090008 -32744\(gp\) 00080000
0009000c -32740\(gp\) 00000000
#pass

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -0,0 +1,8 @@
#...
Local entries:
Address Access Initial
00090008 -32744\(gp\) 00080000
0009000c -32740\(gp\) 00090000
00090010 -32736\(gp\) 000a0000
#pass

View File

@ -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

View File

@ -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

View File

@ -0,0 +1,6 @@
#...
Local entries:
Address Access Initial
00090008 -32744\(gp\) 00080000
#pass

View File

@ -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

View File

@ -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

View File

@ -0,0 +1,7 @@
#...
Local entries:
Address Access Initial
00090008 -32744\(gp\) 00090000
0009000c -32740\(gp\) 000a0000
#pass

View File

@ -0,0 +1,6 @@
.globl f1
.ent f1
f1:
lw $4,%got_page(g)($gp)
addiu $4,$4,%got_ofst(g)
.end f1

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -0,0 +1,6 @@
# Make sure the loadable size of the library is large.
.section .bss
.globl g
.hidden g
g:
.space 0x800000

View File

@ -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"

View File

@ -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\)

View File

@ -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