diff options
-rw-r--r-- | bfd/ChangeLog | 16 | ||||
-rw-r--r-- | bfd/elfxx-mips.c | 215 |
2 files changed, 144 insertions, 87 deletions
diff --git a/bfd/ChangeLog b/bfd/ChangeLog index 949f430..457c047 100644 --- a/bfd/ChangeLog +++ b/bfd/ChangeLog @@ -1,3 +1,19 @@ +2002-12-12 Alexandre Oliva <aoliva@redhat.com> + + * elfxx-mips.c (struct mips_got_entry): New. + (struct mips_got_info): Added got_entries field. + (mips_elf_got_entry_hash, mips_elf_got_entry_eq): New functions. + (mips_elf_local_got_index, mips_elf_got_page, + mips_elf_got16_entry): Re-implement in terms of new... + (mips_elf_create_local_got_entry): Rewrite to use got_entries. + Change return type. + (mips_elf_highest): Warning clean-up. + (mips_elf_create_got_section): Initialize got_entries. + (_bfd_mips_elf_check_relocs): Use got_entries to estimate + local got size. + (_bfd_mips_elf_size_dynamic_sections): Do not account for + GOT_PAGE entries, since we now reuse GOT16 entries. + 2002-12-10 Jason Thorpe <thorpej@wasabisystems.com> * aoutx.h (set_section_contents): Allow an otherwise unrepresentable diff --git a/bfd/elfxx-mips.c b/bfd/elfxx-mips.c index 719071b..c20e444 100644 --- a/bfd/elfxx-mips.c +++ b/bfd/elfxx-mips.c @@ -40,6 +40,26 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #include "coff/ecoff.h" #include "coff/mips.h" +#include "hashtab.h" + +/* This structure is used to hold .got entries while estimating got + sizes. */ +struct mips_got_entry +{ + /* The input bfd in which the symbol is defined. */ + bfd *abfd; + /* The index of the symbol, as stored in the relocation r_info. If + it's -1, the addend is a complete address into the + executable/shared library. */ + unsigned long symndx; + /* The addend of the relocation that should be added to the symbol + value. */ + bfd_vma addend; + /* The offset from the beginning of the .got section to the entry + corresponding to this symbol+addend. */ + unsigned long gotidx; +}; + /* This structure is used to hold .got information when linking. It is stored in the tdata field of the bfd_elf_section_data structure. */ @@ -54,6 +74,8 @@ struct mips_got_info unsigned int local_gotno; /* The number of local .got entries we have used. */ unsigned int assigned_gotno; + /* A hash table holding members of the got. */ + struct htab *got_entries; }; /* This structure is passed to mips_elf_sort_hash_table_f when sorting @@ -316,7 +338,7 @@ static bfd_vma mips_elf_got16_entry PARAMS ((bfd *, struct bfd_link_info *, bfd_vma, bfd_boolean)); static bfd_vma mips_elf_got_offset_from_index PARAMS ((bfd *, bfd *, bfd_vma)); -static bfd_vma mips_elf_create_local_got_entry +static struct mips_got_entry *mips_elf_create_local_got_entry PARAMS ((bfd *, struct mips_got_info *, asection *, bfd_vma)); static bfd_boolean mips_elf_sort_hash_table PARAMS ((struct bfd_link_info *, unsigned long)); @@ -365,6 +387,8 @@ static INLINE char* elf_mips_abi_name PARAMS ((bfd *)); static void mips_elf_irix6_finish_dynamic_symbol PARAMS ((bfd *, const char *, Elf_Internal_Sym *)); static bfd_boolean _bfd_mips_elf_mach_extends_p PARAMS ((flagword, flagword)); +static hashval_t mips_elf_got_entry_hash PARAMS ((const PTR)); +static int mips_elf_got_entry_eq PARAMS ((const PTR, const PTR)); /* This will be used when we sort the dynamic relocation records. */ static bfd *reldyn_sorting_bfd; @@ -1392,6 +1416,32 @@ gptab_compare (p1, p2) return a1->gt_entry.gt_g_value - a2->gt_entry.gt_g_value; } +/* Functions to manage the got entry hash table. */ +static hashval_t +mips_elf_got_entry_hash (entry_) + const PTR entry_; +{ + const struct mips_got_entry *entry = (struct mips_got_entry *)entry_; + + return htab_hash_pointer (entry->abfd) + entry->symndx +#ifdef BFD64 + + (entry->addend >> 32) +#endif + + entry->addend; +} + +static int +mips_elf_got_entry_eq (entry1, entry2) + const PTR entry1; + const PTR entry2; +{ + const struct mips_got_entry *e1 = (struct mips_got_entry *)entry1; + const struct mips_got_entry *e2 = (struct mips_got_entry *)entry2; + + return e1->abfd == e2->abfd && e1->symndx == e2->symndx + && e1->addend == e2->addend; +} + /* Returns the GOT section for ABFD. */ static asection * @@ -1436,22 +1486,15 @@ mips_elf_local_got_index (abfd, info, value) { asection *sgot; struct mips_got_info *g; - bfd_byte *entry; + struct mips_got_entry *entry; g = mips_elf_got_info (elf_hash_table (info)->dynobj, &sgot); - /* Look to see if we already have an appropriate entry. */ - for (entry = (sgot->contents - + MIPS_ELF_GOT_SIZE (abfd) * MIPS_RESERVED_GOTNO); - entry != sgot->contents + MIPS_ELF_GOT_SIZE (abfd) * g->assigned_gotno; - entry += MIPS_ELF_GOT_SIZE (abfd)) - { - bfd_vma address = MIPS_ELF_GET_WORD (abfd, entry); - if (address == value) - return entry - sgot->contents; - } - - return mips_elf_create_local_got_entry (abfd, g, sgot, value); + entry = mips_elf_create_local_got_entry (abfd, g, sgot, value); + if (entry) + return entry->gotidx; + else + return MINUS_ONE; } /* Returns the GOT index for the global symbol indicated by H. */ @@ -1497,40 +1540,22 @@ mips_elf_got_page (abfd, info, value, offsetp) { asection *sgot; struct mips_got_info *g; - bfd_byte *entry; - bfd_byte *last_entry; - bfd_vma index = 0; - bfd_vma address; + bfd_vma index; + struct mips_got_entry *entry; g = mips_elf_got_info (elf_hash_table (info)->dynobj, &sgot); - /* Look to see if we already have an appropriate entry. */ - last_entry = sgot->contents + MIPS_ELF_GOT_SIZE (abfd) * g->assigned_gotno; - for (entry = (sgot->contents - + MIPS_ELF_GOT_SIZE (abfd) * MIPS_RESERVED_GOTNO); - entry != last_entry; - entry += MIPS_ELF_GOT_SIZE (abfd)) - { - address = MIPS_ELF_GET_WORD (abfd, entry); - - if (!mips_elf_overflow_p (value - address, 16)) - { - /* This entry will serve as the page pointer. We can add a - 16-bit number to it to get the actual address. */ - index = entry - sgot->contents; - break; - } - } + entry = mips_elf_create_local_got_entry (abfd, g, sgot, + (value + 0x8000) + & (~(bfd_vma)0xffff)); - /* If we didn't have an appropriate entry, we create one now. */ - if (entry == last_entry) - index = mips_elf_create_local_got_entry (abfd, g, sgot, value); + if (!entry) + return MINUS_ONE; + + index = entry->gotidx; if (offsetp) - { - address = MIPS_ELF_GET_WORD (abfd, entry); - *offsetp = value - address; - } + *offsetp = value - entry->addend; return index; } @@ -1547,10 +1572,7 @@ mips_elf_got16_entry (abfd, info, value, external) { asection *sgot; struct mips_got_info *g; - bfd_byte *entry; - bfd_byte *last_entry; - bfd_vma index = 0; - bfd_vma address; + struct mips_got_entry *entry; if (! external) { @@ -1563,28 +1585,11 @@ mips_elf_got16_entry (abfd, info, value, external) g = mips_elf_got_info (elf_hash_table (info)->dynobj, &sgot); - /* Look to see if we already have an appropriate entry. */ - last_entry = sgot->contents + MIPS_ELF_GOT_SIZE (abfd) * g->assigned_gotno; - for (entry = (sgot->contents - + MIPS_ELF_GOT_SIZE (abfd) * MIPS_RESERVED_GOTNO); - entry != last_entry; - entry += MIPS_ELF_GOT_SIZE (abfd)) - { - address = MIPS_ELF_GET_WORD (abfd, entry); - if (address == value) - { - /* This entry has the right high-order 16 bits, and the low-order - 16 bits are set to zero. */ - index = entry - sgot->contents; - break; - } - } - - /* If we didn't have an appropriate entry, we create one now. */ - if (entry == last_entry) - index = mips_elf_create_local_got_entry (abfd, g, sgot, value); - - return index; + entry = mips_elf_create_local_got_entry (abfd, g, sgot, value); + if (entry) + return entry->gotidx; + else + return MINUS_ONE; } /* Returns the offset for the entry at the INDEXth position @@ -1608,26 +1613,47 @@ mips_elf_got_offset_from_index (dynobj, output_bfd, index) /* Create a local GOT entry for VALUE. Return the index of the entry, or -1 if it could not be created. */ -static bfd_vma +static struct mips_got_entry * mips_elf_create_local_got_entry (abfd, g, sgot, value) bfd *abfd; struct mips_got_info *g; asection *sgot; bfd_vma value; { + struct mips_got_entry entry, **loc; + + entry.abfd = abfd; + entry.symndx = (unsigned long)-1; + entry.addend = value; + + loc = (struct mips_got_entry **) htab_find_slot (g->got_entries, &entry, + INSERT); + if (*loc) + return *loc; + + entry.gotidx = MIPS_ELF_GOT_SIZE (abfd) * g->assigned_gotno++; + + *loc = (struct mips_got_entry *)bfd_alloc (abfd, sizeof entry); + + if (! *loc) + return NULL; + + memcpy (*loc, &entry, sizeof entry); + if (g->assigned_gotno >= g->local_gotno) { + (*loc)->gotidx = (unsigned long)-1; /* We didn't allocate enough space in the GOT. */ (*_bfd_error_handler) (_("not enough GOT space for local GOT entries")); bfd_set_error (bfd_error_bad_value); - return (bfd_vma) -1; + return NULL; } MIPS_ELF_PUT_WORD (abfd, value, - (sgot->contents - + MIPS_ELF_GOT_SIZE (abfd) * g->assigned_gotno)); - return MIPS_ELF_GOT_SIZE (abfd) * g->assigned_gotno++; + (sgot->contents + entry.gotidx)); + + return *loc; } /* Sort the dynamic symbol table so that symbols that need GOT entries @@ -1873,7 +1899,7 @@ mips_elf_highest (value) bfd_vma value ATTRIBUTE_UNUSED; { #ifdef BFD64 - return ((value + (bfd_vma) 0x800080008000) >> 48) & 0xffff; + return ((value + (((bfd_vma) 0x8000 << 32) | 0x80008000)) >> 48) & 0xffff; #else abort (); return (bfd_vma) -1; @@ -1964,6 +1990,11 @@ mips_elf_create_got_section (abfd, info) g->global_gotsym = NULL; g->local_gotno = MIPS_RESERVED_GOTNO; g->assigned_gotno = MIPS_RESERVED_GOTNO; + g->got_entries = htab_try_create (1, mips_elf_got_entry_hash, + mips_elf_got_entry_eq, + (htab_del) NULL); + if (g->got_entries == NULL) + return FALSE; if (elf_section_data (s) == NULL) { amt = sizeof (struct bfd_elf_section_data); @@ -4358,20 +4389,35 @@ _bfd_mips_elf_check_relocs (abfd, info, sec, relocs) || r_type == R_MIPS_GOT_LO16 || r_type == R_MIPS_GOT_DISP)) { + struct mips_got_entry entry, **loc; + /* We may need a local GOT entry for this relocation. We don't count R_MIPS_GOT_PAGE because we can estimate the maximum number of pages needed by looking at the size of the segment. Similar comments apply to R_MIPS_GOT16 and R_MIPS_CALL16. We don't count R_MIPS_GOT_HI16, or R_MIPS_CALL_HI16 because these are always followed by an - R_MIPS_GOT_LO16 or R_MIPS_CALL_LO16. - - This estimation is very conservative since we can merge - duplicate entries in the GOT. In order to be less - conservative, we could actually build the GOT here, - rather than in relocate_section. */ - g->local_gotno++; - sgot->_raw_size += MIPS_ELF_GOT_SIZE (dynobj); + R_MIPS_GOT_LO16 or R_MIPS_CALL_LO16. */ + + entry.abfd = abfd; + entry.symndx = r_symndx; + entry.addend = rel->r_addend; + loc = (struct mips_got_entry **) + htab_find_slot (g->got_entries, &entry, INSERT); + + if (*loc == NULL) + { + entry.gotidx = g->local_gotno++; + + *loc = (struct mips_got_entry *)bfd_alloc (abfd, sizeof entry); + + if (! *loc) + return FALSE; + + memcpy (*loc, &entry, sizeof entry); + + sgot->_raw_size += MIPS_ELF_GOT_SIZE (dynobj); + } } switch (r_type) @@ -4804,11 +4850,6 @@ _bfd_mips_elf_size_dynamic_sections (output_bfd, info) /* Assume there are two loadable segments consisting of contiguous sections. Is 5 enough? */ local_gotno = (loadable_size >> 16) + 5; - if (NEWABI_P (output_bfd)) - /* It's possible we will need GOT_PAGE entries as well as - GOT16 entries. Often, these will be able to share GOT - entries, but not always. */ - local_gotno *= 2; g->local_gotno += local_gotno; s->_raw_size += local_gotno * MIPS_ELF_GOT_SIZE (dynobj); |