From 13db6b44eaf75fce5624b518185d98f81a48e603 Mon Sep 17 00:00:00 2001 From: Richard Sandiford Date: Wed, 13 Feb 2013 14:08:58 +0000 Subject: [PATCH] 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. --- bfd/ChangeLog | 26 ++ bfd/elfxx-mips.c | 416 ++++++++++++++++------- ld/testsuite/ChangeLog | 16 + ld/testsuite/ld-mips-elf/got-page-4a.d | 35 ++ ld/testsuite/ld-mips-elf/got-page-4a.got | 7 + ld/testsuite/ld-mips-elf/got-page-4a.s | 14 + ld/testsuite/ld-mips-elf/got-page-4b.d | 36 ++ ld/testsuite/ld-mips-elf/got-page-4b.got | 21 ++ ld/testsuite/ld-mips-elf/got-page-4b.s | 21 ++ ld/testsuite/ld-mips-elf/got-page-5.d | 10 + ld/testsuite/ld-mips-elf/got-page-5.got | 8 + ld/testsuite/ld-mips-elf/got-page-5.s | 31 ++ ld/testsuite/ld-mips-elf/got-page-6.d | 10 + ld/testsuite/ld-mips-elf/got-page-6.got | 6 + ld/testsuite/ld-mips-elf/got-page-6.s | 27 ++ ld/testsuite/ld-mips-elf/got-page-7.d | 17 + ld/testsuite/ld-mips-elf/got-page-7.got | 7 + ld/testsuite/ld-mips-elf/got-page-7a.s | 6 + ld/testsuite/ld-mips-elf/got-page-7b.s | 6 + ld/testsuite/ld-mips-elf/got-page-7c.s | 6 + ld/testsuite/ld-mips-elf/got-page-7d.s | 6 + ld/testsuite/ld-mips-elf/got-page-7e.s | 6 + ld/testsuite/ld-mips-elf/mips-elf.exp | 40 +++ ld/testsuite/ld-mips-elf/mips16-pic-2.dd | 4 +- ld/testsuite/ld-mips-elf/mips16-pic-2.gd | 11 +- 25 files changed, 664 insertions(+), 129 deletions(-) create mode 100644 ld/testsuite/ld-mips-elf/got-page-4a.d create mode 100644 ld/testsuite/ld-mips-elf/got-page-4a.got create mode 100644 ld/testsuite/ld-mips-elf/got-page-4a.s create mode 100644 ld/testsuite/ld-mips-elf/got-page-4b.d create mode 100644 ld/testsuite/ld-mips-elf/got-page-4b.got create mode 100644 ld/testsuite/ld-mips-elf/got-page-4b.s create mode 100644 ld/testsuite/ld-mips-elf/got-page-5.d create mode 100644 ld/testsuite/ld-mips-elf/got-page-5.got create mode 100644 ld/testsuite/ld-mips-elf/got-page-5.s create mode 100644 ld/testsuite/ld-mips-elf/got-page-6.d create mode 100644 ld/testsuite/ld-mips-elf/got-page-6.got create mode 100644 ld/testsuite/ld-mips-elf/got-page-6.s create mode 100644 ld/testsuite/ld-mips-elf/got-page-7.d create mode 100644 ld/testsuite/ld-mips-elf/got-page-7.got create mode 100644 ld/testsuite/ld-mips-elf/got-page-7a.s create mode 100644 ld/testsuite/ld-mips-elf/got-page-7b.s create mode 100644 ld/testsuite/ld-mips-elf/got-page-7c.s create mode 100644 ld/testsuite/ld-mips-elf/got-page-7d.s create mode 100644 ld/testsuite/ld-mips-elf/got-page-7e.s diff --git a/bfd/ChangeLog b/bfd/ChangeLog index 6c284813e0b..21c939611e2 100644 --- a/bfd/ChangeLog +++ b/bfd/ChangeLog @@ -1,3 +1,29 @@ +2013-02-13 Richard Sandiford + + * 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 * 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 1d4586f2c87..282a4644ccb 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. */ @@ -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); diff --git a/ld/testsuite/ChangeLog b/ld/testsuite/ChangeLog index 376b119dc58..e1a7e4a4bd6 100644 --- a/ld/testsuite/ChangeLog +++ b/ld/testsuite/ChangeLog @@ -1,3 +1,19 @@ +2013-02-13 Richard Sandiford + + * 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 * 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 00000000000..0ff341e5455 --- /dev/null +++ b/ld/testsuite/ld-mips-elf/got-page-4a.d @@ -0,0 +1,35 @@ +#... +.* : +.* 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 00000000000..9b1308eea8c --- /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 00000000000..4c8163e4987 --- /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 00000000000..2917c33bd89 --- /dev/null +++ b/ld/testsuite/ld-mips-elf/got-page-4b.d @@ -0,0 +1,36 @@ +#... +.* : +.* 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 00000000000..0e223b5d71a --- /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 00000000000..eab5277f6d9 --- /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 00000000000..5706d98683f --- /dev/null +++ b/ld/testsuite/ld-mips-elf/got-page-5.d @@ -0,0 +1,10 @@ +#... +.* : +.* 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 00000000000..0a76be807d9 --- /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 00000000000..5051263c82c --- /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 00000000000..90d66382cb1 --- /dev/null +++ b/ld/testsuite/ld-mips-elf/got-page-6.d @@ -0,0 +1,10 @@ +#... +.* : +.* 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 00000000000..e385e8c570c --- /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 00000000000..c419e00a7b2 --- /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 00000000000..12990b59baa --- /dev/null +++ b/ld/testsuite/ld-mips-elf/got-page-7.d @@ -0,0 +1,17 @@ +#... +.* : +.* lw a0,-32744\(gp\) +.* addiu a0,a0,1024 +#... +.* : +.* lw a0,-32744\(gp\) +.* addiu a0,a0,17408 +#... +.* : +.* lw a0,-32740\(gp\) +.* addiu a0,a0,-31744 +#... +.* : +.* 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 00000000000..0b5df2098f0 --- /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 00000000000..f03220bd646 --- /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 00000000000..4c9a0df103d --- /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 00000000000..b957ecffa7b --- /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 00000000000..83ddb3a5f90 --- /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 00000000000..c23382e2170 --- /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 62c6cb0593f..986048850b7 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 705205782fd..b2bdff23917 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 d8d14514dc9..c291bc89c64 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