#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. */
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
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));
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;
return a1->gt_entry.gt_g_value - a2->gt_entry.gt_g_value;
}
\f
+/* 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;
+}
+\f
/* Returns the GOT section for ABFD. */
static asection *
{
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. */
{
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;
}
{
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)
{
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
/* 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
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;
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);
|| 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)
/* 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);