* addr2line.c (slurp_symtab): If canonicalization reveals that
[binutils-gdb.git] / bfd / elfxx-mips.c
index fedd667c0a0ffe4a1883f65b6c8be66ec81059dc..a5ad454a79bfec131e3ae547338e6e481b33adea 100644 (file)
 
 #include "hashtab.h"
 
+/* Types of TLS GOT entry.  */
+enum mips_got_tls_type {
+  GOT_TLS_NONE,
+  GOT_TLS_GD,
+  GOT_TLS_LDM,
+  GOT_TLS_IE
+};
+
 /* This structure is used to hold information about one GOT entry.
    There are four types of entry:
 
@@ -86,17 +94,41 @@ struct mips_got_entry
     struct mips_elf_link_hash_entry *h;
   } d;
 
-  /* The TLS type of this GOT entry: GOT_NORMAL, GOT_TLS_IE, GOT_TLS_GD
-     or GOT_TLS_LDM.  An LDM GOT entry will be a local symbol entry with
-     r_symndx == 0.  */
+  /* The TLS type of this GOT entry.  An LDM GOT entry will be a local
+     symbol entry with r_symndx == 0.  */
   unsigned char tls_type;
 
+  /* True if we have filled in the GOT contents for a TLS entry,
+     and created the associated relocations.  */
+  unsigned char tls_initialized;
+
   /* The offset from the beginning of the .got section to the entry
      corresponding to this symbol+addend.  If it's a global symbol
      whose offset is yet to be decided, it's going to be -1.  */
   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.  */
@@ -108,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.  */
@@ -144,16 +174,13 @@ 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
      of the time, it points to the previous got).  */
   struct mips_got_info *next;
-  /* This is the GOT index of the TLS LDM entry for the GOT, MINUS_ONE
-     for none, or MINUS_TWO for not yet assigned.  This is needed
-     because a single-GOT link may have multiple hash table entries
-     for the LDM.  It does not get initialized in multi-GOT mode.  */
-  bfd_vma tls_ldm_offset;
 };
 
 /* Structure passed when merging bfds' gots.  */
@@ -321,23 +348,6 @@ struct mips_elf_link_hash_entry
      being called returns a floating point value.  */
   asection *call_fp_stub;
 
-#define GOT_NORMAL     0
-#define GOT_TLS_GD     1
-#define GOT_TLS_LDM    2
-#define GOT_TLS_IE     4
-#define GOT_TLS_TYPE   7
-#define GOT_TLS_OFFSET_DONE    0x40
-#define GOT_TLS_DONE    0x80
-  unsigned char tls_ie_type;
-  unsigned char tls_gd_type;
-
-  /* These fields are only used in single-GOT mode; in multi-GOT mode there
-     is one mips_got_entry per GOT entry, so the offset is stored
-     there.  In single-GOT mode there may be many mips_got_entry
-     structures all referring to the same GOT slot.  */
-  bfd_vma tls_ie_got_offset;
-  bfd_vma tls_gd_got_offset;
-
   /* The highest GGA_* value that satisfies all references to this symbol.  */
   unsigned int global_got_area : 2;
 
@@ -455,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.  */
@@ -486,6 +499,22 @@ struct mips_elf_obj_tdata
 
   /* The GOT requirements of input bfds.  */
   struct mips_got_info *got;
+
+  /* Used by _bfd_mips_elf_find_nearest_line.  The structure could be
+     included directly in this one, but there's no point to wasting
+     the memory just for the infrequently called find_nearest_line.  */
+  struct mips_elf_find_line *find_line_info;
+
+  /* An array of stub sections indexed by symbol number.  */
+  asection **local_stubs;
+  asection **local_call_stubs;
+
+  /* The Irix 5 support uses two virtual sections, which represent
+     text/data symbols defined in dynamic objects.  */
+  asymbol *elf_data_symbol;
+  asymbol *elf_text_symbol;
+  asection *elf_data_section;
+  asection *elf_text_section;
 };
 
 /* Get MIPS ELF private object data from BFD's tdata.  */
@@ -708,6 +737,10 @@ static bfd *reldyn_sorting_bfd;
 /* Nonzero if ABFD is using NewABI conventions.  */
 #define NEWABI_P(abfd) (ABI_N32_P (abfd) || ABI_64_P (abfd))
 
+/* Nonzero if ABFD has microMIPS code.  */
+#define MICROMIPS_P(abfd) \
+  ((elf_elfheader (abfd)->e_flags & EF_MIPS_ARCH_ASE_MICROMIPS) != 0)
+
 /* The IRIX compatibility level we are striving for.  */
 #define IRIX_COMPAT(abfd) \
   (get_elf_backend_data (abfd)->elf_backend_mips_irix_compat (abfd))
@@ -1075,8 +1108,6 @@ mips_elf_link_hash_newfunc (struct bfd_hash_entry *entry,
       ret->fn_stub = NULL;
       ret->call_stub = NULL;
       ret->call_fp_stub = NULL;
-      ret->tls_ie_type = GOT_NORMAL;
-      ret->tls_gd_type = GOT_NORMAL;
       ret->global_got_area = GGA_NONE;
       ret->got_only_for_calls = TRUE;
       ret->readonly_reloc = FALSE;
@@ -2760,8 +2791,8 @@ mips_elf_got_entry_hash (const void *entry_)
   const struct mips_got_entry *entry = (struct mips_got_entry *)entry_;
 
   return (entry->symndx
-         + (((entry->tls_type & GOT_TLS_TYPE) == GOT_TLS_LDM) << 18)
-         + ((entry->tls_type & GOT_TLS_TYPE) == GOT_TLS_LDM ? 0
+         + ((entry->tls_type == GOT_TLS_LDM) << 18)
+         + (entry->tls_type == GOT_TLS_LDM ? 0
             : !entry->abfd ? mips_elf_hash_bfd_vma (entry->d.address)
             : entry->symndx >= 0 ? (entry->abfd->id
                                     + mips_elf_hash_bfd_vma (entry->d.addend))
@@ -2775,21 +2806,47 @@ mips_elf_got_entry_eq (const void *entry1, const void *entry2)
   const struct mips_got_entry *e2 = (struct mips_got_entry *)entry2;
 
   return (e1->symndx == e2->symndx
-         && (e1->tls_type & GOT_TLS_TYPE) == (e2->tls_type & GOT_TLS_TYPE)
-         && ((e1->tls_type & GOT_TLS_TYPE) == GOT_TLS_LDM ? TRUE
+         && e1->tls_type == e2->tls_type
+         && (e1->tls_type == GOT_TLS_LDM ? TRUE
              : !e1->abfd ? !e2->abfd && e1->d.address == e2->d.address
              : e1->symndx >= 0 ? (e1->abfd == e2->abfd
                                   && e1->d.addend == e2->d.addend)
              : 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
@@ -2799,7 +2856,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;
 }
 \f
 /* Create and return a new mips_got_info structure.  */
@@ -2813,15 +2870,14 @@ mips_elf_create_got_info (bfd *abfd)
   if (g == NULL)
     return NULL;
 
-  g->tls_ldm_offset = MINUS_ONE;
   g->got_entries = htab_try_create (1, mips_elf_got_entry_hash,
                                    mips_elf_got_entry_eq, NULL);
   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;
@@ -2858,7 +2914,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;
 }
@@ -2908,7 +2966,7 @@ mips_elf_reloc_tls_type (unsigned int r_type)
   if (tls_gottprel_reloc_p (r_type))
     return GOT_TLS_IE;
 
-  return GOT_NORMAL;
+  return GOT_TLS_NONE;
 }
 
 /* Return the number of GOT slots needed for GOT TLS type TYPE.  */
@@ -2925,7 +2983,7 @@ mips_tls_got_entries (unsigned int type)
     case GOT_TLS_IE:
       return 1;
 
-    case GOT_NORMAL:
+    case GOT_TLS_NONE:
       return 0;
     }
   abort ();
@@ -2956,7 +3014,7 @@ mips_tls_got_relocs (struct bfd_link_info *info, unsigned char tls_type,
   if (!need_relocs)
     return 0;
 
-  switch (tls_type & GOT_TLS_TYPE)
+  switch (tls_type)
     {
     case GOT_TLS_GD:
       return indx != 0 ? 2 : 1;
@@ -2980,13 +3038,10 @@ mips_elf_count_got_entry (struct bfd_link_info *info,
                          struct mips_got_info *g,
                          struct mips_got_entry *entry)
 {
-  unsigned char tls_type;
-
-  tls_type = entry->tls_type & GOT_TLS_TYPE;
-  if (tls_type)
+  if (entry->tls_type)
     {
-      g->tls_gotno += mips_tls_got_entries (tls_type);
-      g->relocs += mips_tls_got_relocs (info, tls_type,
+      g->tls_gotno += mips_tls_got_entries (entry->tls_type);
+      g->relocs += mips_tls_got_relocs (info, entry->tls_type,
                                        entry->symndx < 0
                                        ? &entry->d.h->root : NULL);
     }
@@ -2996,80 +3051,6 @@ mips_elf_count_got_entry (struct bfd_link_info *info,
     g->global_gotno += 1;
 }
 
-/* A htab_traverse callback.  Count the number of GOT entries and
-   TLS relocations required for the GOT entry in *ENTRYP.  DATA points
-   to a mips_elf_traverse_got_arg structure.  */
-
-static int
-mips_elf_count_got_entries (void **entryp, void *data)
-{
-  struct mips_got_entry *entry;
-  struct mips_elf_traverse_got_arg *arg;
-
-  entry = (struct mips_got_entry *) *entryp;
-  arg = (struct mips_elf_traverse_got_arg *) data;
-  mips_elf_count_got_entry (arg->info, arg->g, entry);
-
-  return 1;
-}
-
-/* A htab_traverse callback.  If *SLOT describes a GOT entry for a local
-   symbol, count the number of GOT entries and TLS relocations that it
-   requires.  DATA points to a mips_elf_traverse_got_arg structure.  */
-
-static int
-mips_elf_count_local_got_entries (void **entryp, void *data)
-{
-  struct mips_got_entry *entry;
-  struct mips_elf_traverse_got_arg *arg;
-
-  entry = (struct mips_got_entry *) *entryp;
-  arg = (struct mips_elf_traverse_got_arg *) data;
-  if (entry->abfd != NULL && entry->symndx != -1)
-    {
-      if ((entry->tls_type & GOT_TLS_TYPE) == GOT_TLS_LDM)
-       {
-         if (arg->g->tls_ldm_offset == MINUS_TWO)
-           return 1;
-         arg->g->tls_ldm_offset = MINUS_TWO;
-       }
-      mips_elf_count_got_entry (arg->info, arg->g, entry);
-    }
-
-  return 1;
-}
-
-/* Count the number of TLS GOT entries and relocationss required for the
-   global (or forced-local) symbol in ARG1.  */
-
-static int
-mips_elf_count_global_tls_entries (void *entry, void *data)
-{
-  struct mips_elf_link_hash_entry *hm;
-  struct mips_elf_traverse_got_arg *arg;
-
-  hm = (struct mips_elf_link_hash_entry *) entry;
-  if (hm->root.root.type == bfd_link_hash_indirect
-      || hm->root.root.type == bfd_link_hash_warning)
-    return 1;
-
-  arg = (struct mips_elf_traverse_got_arg *) data;
-  if (hm->tls_gd_type)
-    {
-      arg->g->tls_gotno += 2;
-      arg->g->relocs += mips_tls_got_relocs (arg->info, hm->tls_gd_type,
-                                            &hm->root);
-    }
-  if (hm->tls_ie_type)
-    {
-      arg->g->tls_gotno += 1;
-      arg->g->relocs += mips_tls_got_relocs (arg->info, hm->tls_ie_type,
-                                            &hm->root);
-    }
-
-  return 1;
-}
-
 /* Output a simple dynamic relocation into SRELOC.  */
 
 static void
@@ -3104,16 +3085,15 @@ mips_elf_output_dynamic_relocation (bfd *output_bfd,
 /* Initialize a set of TLS GOT entries for one symbol.  */
 
 static void
-mips_elf_initialize_tls_slots (bfd *abfd, bfd_vma got_offset,
-                              unsigned char *tls_type_p,
-                              struct bfd_link_info *info,
+mips_elf_initialize_tls_slots (bfd *abfd, struct bfd_link_info *info,
+                              struct mips_got_entry *entry,
                               struct mips_elf_link_hash_entry *h,
                               bfd_vma value)
 {
   struct mips_elf_link_hash_table *htab;
   int indx;
   asection *sreloc, *sgot;
-  bfd_vma got_offset2;
+  bfd_vma got_offset, got_offset2;
   bfd_boolean need_relocs = FALSE;
 
   htab = mips_elf_hash_table (info);
@@ -3132,7 +3112,7 @@ mips_elf_initialize_tls_slots (bfd *abfd, bfd_vma got_offset,
        indx = h->root.dynindx;
     }
 
-  if (*tls_type_p & GOT_TLS_DONE)
+  if (entry->tls_initialized)
     return;
 
   if ((info->shared || indx != 0)
@@ -3149,8 +3129,9 @@ mips_elf_initialize_tls_slots (bfd *abfd, bfd_vma got_offset,
 
   /* Emit necessary relocations.  */
   sreloc = mips_elf_rel_dyn_section (info, FALSE);
+  got_offset = entry->gotidx;
 
-  switch (*tls_type_p & GOT_TLS_TYPE)
+  switch (entry->tls_type)
     {
     case GOT_TLS_GD:
       /* General Dynamic.  */
@@ -3223,37 +3204,7 @@ mips_elf_initialize_tls_slots (bfd *abfd, bfd_vma got_offset,
       abort ();
     }
 
-  *tls_type_p |= GOT_TLS_DONE;
-}
-
-/* Return the GOT index to use for a relocation against H using the
-   TLS model in *TLS_TYPE.  The GOT entries for this symbol/model
-   combination start at GOT_INDEX into ABFD's GOT.  This function
-   initializes the GOT entries and corresponding relocations.  */
-
-static bfd_vma
-mips_tls_got_index (bfd *abfd, bfd_vma got_index, unsigned char *tls_type,
-                   struct bfd_link_info *info,
-                   struct mips_elf_link_hash_entry *h, bfd_vma symbol)
-{
-  mips_elf_initialize_tls_slots (abfd, got_index, tls_type, info, h, symbol);
-  return got_index;
-}
-
-/* Return the GOT index to use for a relocation of type R_TYPE against H
-   in ABFD.  */
-
-static bfd_vma
-mips_tls_single_got_index (bfd *abfd, int r_type, struct bfd_link_info *info,
-                          struct mips_elf_link_hash_entry *h, bfd_vma symbol)
-{
-  if (tls_gottprel_reloc_p (r_type))
-    return mips_tls_got_index (abfd, h->tls_ie_got_offset, &h->tls_ie_type,
-                              info, h, symbol);
-  if (tls_gd_reloc_p (r_type))
-    return mips_tls_got_index (abfd, h->tls_gd_got_offset, &h->tls_gd_type,
-                              info, h, symbol);
-  abort ();
+  entry->tls_initialized = TRUE;
 }
 
 /* Return the offset from _GLOBAL_OFFSET_TABLE_ of the .got.plt entry
@@ -3314,17 +3265,8 @@ mips_elf_local_got_index (bfd *abfd, bfd *ibfd, struct bfd_link_info *info,
     return MINUS_ONE;
 
   if (entry->tls_type)
-    {
-      if (entry->symndx == -1 && htab->got_info->next == NULL)
-       /* A type (3) entry in the single-GOT case.  We use the symbol's
-          hash table entry to track the index.  */
-       return mips_tls_single_got_index (abfd, r_type, info, h, value);
-      else
-       return mips_tls_got_index (abfd, entry->gotidx, &entry->tls_type,
-                                  info, h, value);
-    }
-  else
-    return entry->gotidx;
+    mips_elf_initialize_tls_slots (abfd, info, entry, h, value);
+  return entry->gotidx;
 }
 
 /* Return the GOT index of global symbol H in the primary GOT.  */
@@ -3366,54 +3308,31 @@ mips_elf_global_got_index (bfd *obfd, struct bfd_link_info *info, bfd *ibfd,
                           struct elf_link_hash_entry *h, int r_type)
 {
   struct mips_elf_link_hash_table *htab;
-  bfd_vma got_index;
-  struct mips_got_info *g, *gg;
+  struct mips_got_info *g;
+  struct mips_got_entry lookup, *entry;
+  bfd_vma gotidx;
 
   htab = mips_elf_hash_table (info);
   BFD_ASSERT (htab != NULL);
 
-  gg = g = htab->got_info;
-  if (g->next && ibfd)
-    {
-      struct mips_got_entry e, *p;
-
-      BFD_ASSERT (h->dynindx >= 0);
+  g = mips_elf_bfd_got (ibfd, FALSE);
+  BFD_ASSERT (g);
 
-      g = mips_elf_bfd_got (ibfd, FALSE);
-      BFD_ASSERT (g);
-      if (g->next != gg || TLS_RELOC_P (r_type))
-       {
-         e.abfd = ibfd;
-         e.symndx = -1;
-         e.d.h = (struct mips_elf_link_hash_entry *)h;
-         e.tls_type = mips_elf_reloc_tls_type (r_type);
+  lookup.tls_type = mips_elf_reloc_tls_type (r_type);
+  if (!lookup.tls_type && g == mips_elf_bfd_got (obfd, FALSE))
+    return mips_elf_primary_global_got_index (obfd, info, h);
 
-         p = htab_find (g->got_entries, &e);
+  lookup.abfd = ibfd;
+  lookup.symndx = -1;
+  lookup.d.h = (struct mips_elf_link_hash_entry *) h;
+  entry = htab_find (g->got_entries, &lookup);
+  BFD_ASSERT (entry);
 
-         BFD_ASSERT (p && p->gotidx > 0);
+  gotidx = entry->gotidx;
+  BFD_ASSERT (gotidx > 0 && gotidx < htab->sgot->size);
 
-         if (p->tls_type)
-           {
-             bfd_vma value = MINUS_ONE;
-             if ((h->root.type == bfd_link_hash_defined
-                  || h->root.type == bfd_link_hash_defweak)
-                 && h->root.u.def.section->output_section)
-               value = (h->root.u.def.value
-                        + h->root.u.def.section->output_offset
-                        + h->root.u.def.section->output_section->vma);
-
-             return mips_tls_got_index (obfd, p->gotidx, &p->tls_type,
-                                        info, e.d.h, value);
-           }
-         else
-           return p->gotidx;
-       }
-    }
-
-  if (TLS_RELOC_P (r_type))
+  if (lookup.tls_type)
     {
-      struct mips_elf_link_hash_entry *hm
-       = (struct mips_elf_link_hash_entry *) h;
       bfd_vma value = MINUS_ONE;
 
       if ((h->root.type == bfd_link_hash_defined
@@ -3423,13 +3342,9 @@ mips_elf_global_got_index (bfd *obfd, struct bfd_link_info *info, bfd *ibfd,
                 + h->root.u.def.section->output_offset
                 + h->root.u.def.section->output_section->vma);
 
-      got_index = mips_tls_single_got_index (obfd, r_type, info, hm, value);
+      mips_elf_initialize_tls_slots (obfd, info, entry, lookup.d.h, value);
     }
-  else
-    got_index = mips_elf_primary_global_got_index (obfd, info, h);
-  BFD_ASSERT (got_index < htab->sgot->size);
-
-  return got_index;
+  return gotidx;
 }
 
 /* Find a GOT page entry that points to within 32KB of VALUE.  These
@@ -3521,18 +3436,15 @@ mips_elf_create_local_got_entry (bfd *abfd, struct bfd_link_info *info,
                                 struct mips_elf_link_hash_entry *h,
                                 int r_type)
 {
-  struct mips_got_entry entry, **loc;
+  struct mips_got_entry lookup, *entry;
+  void **loc;
   struct mips_got_info *g;
   struct mips_elf_link_hash_table *htab;
+  bfd_vma gotidx;
 
   htab = mips_elf_hash_table (info);
   BFD_ASSERT (htab != NULL);
 
-  entry.abfd = NULL;
-  entry.symndx = -1;
-  entry.d.address = value;
-  entry.tls_type = mips_elf_reloc_tls_type (r_type);
-
   g = mips_elf_bfd_got (ibfd, FALSE);
   if (g == NULL)
     {
@@ -3543,48 +3455,49 @@ mips_elf_create_local_got_entry (bfd *abfd, struct bfd_link_info *info,
   /* This function shouldn't be called for symbols that live in the global
      area of the GOT.  */
   BFD_ASSERT (h == NULL || h->global_got_area == GGA_NONE);
-  if (entry.tls_type)
-    {
-      struct mips_got_entry *p;
 
-      entry.abfd = ibfd;
+  lookup.tls_type = mips_elf_reloc_tls_type (r_type);
+  if (lookup.tls_type)
+    {
+      lookup.abfd = ibfd;
       if (tls_ldm_reloc_p (r_type))
        {
-         entry.symndx = 0;
-         entry.d.addend = 0;
+         lookup.symndx = 0;
+         lookup.d.addend = 0;
        }
       else if (h == NULL)
        {
-         entry.symndx = r_symndx;
-         entry.d.addend = 0;
+         lookup.symndx = r_symndx;
+         lookup.d.addend = 0;
        }
       else
-       entry.d.h = h;
-
-      p = (struct mips_got_entry *)
-       htab_find (g->got_entries, &entry);
-
-      BFD_ASSERT (p);
-      return p;
-    }
+       {
+         lookup.symndx = -1;
+         lookup.d.h = h;
+       }
 
-  loc = (struct mips_got_entry **) htab_find_slot (g->got_entries, &entry,
-                                                  INSERT);
-  if (*loc)
-    return *loc;
+      entry = (struct mips_got_entry *) htab_find (g->got_entries, &lookup);
+      BFD_ASSERT (entry);
 
-  entry.gotidx = MIPS_ELF_GOT_SIZE (abfd) * g->assigned_gotno++;
+      gotidx = entry->gotidx;
+      BFD_ASSERT (gotidx > 0 && gotidx < htab->sgot->size);
 
-  *loc = (struct mips_got_entry *)bfd_alloc (abfd, sizeof entry);
+      return entry;
+    }
 
-  if (! *loc)
+  lookup.abfd = NULL;
+  lookup.symndx = -1;
+  lookup.d.address = value;
+  loc = htab_find_slot (g->got_entries, &lookup, INSERT);
+  if (!loc)
     return NULL;
 
-  memcpy (*loc, &entry, sizeof entry);
+  entry = (struct mips_got_entry *) *loc;
+  if (entry)
+    return entry;
 
-  if (g->assigned_gotno > g->local_gotno)
+  if (g->assigned_gotno >= g->local_gotno)
     {
-      (*loc)->gotidx = -1;
       /* We didn't allocate enough space in the GOT.  */
       (*_bfd_error_handler)
        (_("not enough GOT space for local GOT entries"));
@@ -3592,8 +3505,15 @@ mips_elf_create_local_got_entry (bfd *abfd, struct bfd_link_info *info,
       return NULL;
     }
 
-  MIPS_ELF_PUT_WORD (abfd, value,
-                    (htab->sgot->contents + entry.gotidx));
+  entry = (struct mips_got_entry *) bfd_alloc (abfd, sizeof (*entry));
+  if (!entry)
+    return NULL;
+
+  lookup.gotidx = MIPS_ELF_GOT_SIZE (abfd) * g->assigned_gotno++;
+  *entry = lookup;
+  *loc = entry;
+
+  MIPS_ELF_PUT_WORD (abfd, value, htab->sgot->contents + entry->gotidx);
 
   /* These GOT entries need a dynamic relocation on VxWorks.  */
   if (htab->is_vxworks)
@@ -3606,7 +3526,7 @@ mips_elf_create_local_got_entry (bfd *abfd, struct bfd_link_info *info,
       s = mips_elf_rel_dyn_section (info, FALSE);
       got_address = (htab->sgot->output_section->vma
                     + htab->sgot->output_offset
-                    + entry.gotidx);
+                    + entry->gotidx);
 
       rloc = s->contents + (s->reloc_count++ * sizeof (Elf32_External_Rela));
       outrel.r_offset = got_address;
@@ -3615,7 +3535,7 @@ mips_elf_create_local_got_entry (bfd *abfd, struct bfd_link_info *info,
       bfd_elf32_swap_reloca_out (abfd, &outrel, rloc);
     }
 
-  return *loc;
+  return entry;
 }
 
 /* Return the number of dynamic section symbols required by OUTPUT_BFD.
@@ -3752,6 +3672,7 @@ mips_elf_record_got_entry (struct bfd_link_info *info, bfd *abfd,
       if (!entry)
        return FALSE;
 
+      lookup->tls_initialized = FALSE;
       lookup->gotidx = -1;
       *entry = *lookup;
       *loc = entry;
@@ -3808,12 +3729,8 @@ mips_elf_record_global_got_symbol (struct elf_link_hash_entry *h,
     }
 
   tls_type = mips_elf_reloc_tls_type (r_type);
-  if (tls_type == GOT_NORMAL && hmips->global_got_area > GGA_NORMAL)
+  if (tls_type == GOT_TLS_NONE && hmips->global_got_area > GGA_NORMAL)
     hmips->global_got_area = GGA_NORMAL;
-  else if (tls_type == GOT_TLS_IE && hmips->tls_ie_type == 0)
-    hmips->tls_ie_type = tls_type;
-  else if (tls_type == GOT_TLS_GD && hmips->tls_gd_type == 0)
-    hmips->tls_gd_type = tls_type;
 
   entry.abfd = abfd;
   entry.symndx = -1;
@@ -3846,30 +3763,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);
@@ -3878,26 +3783,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;
     }
 
@@ -3906,67 +3814,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;
 }
 
@@ -3999,17 +3853,19 @@ mips_elf_allocate_dynamic_relocations (bfd *abfd, struct bfd_link_info *info,
     }
 }
 \f
-/* A htab_traverse callback for GOT entries.  Set boolean *DATA to true
-   if the GOT entry is for an indirect or warning symbol.  */
+/* A htab_traverse callback for GOT entries, with DATA pointing to a
+   mips_elf_traverse_got_arg structure.  Count the number of GOT
+   entries and TLS relocs.  Set DATA->value to true if we need
+   to resolve indirect or warning symbols and then recreate the GOT.  */
 
 static int
 mips_elf_check_recreate_got (void **entryp, void *data)
 {
   struct mips_got_entry *entry;
-  bfd_boolean *must_recreate;
+  struct mips_elf_traverse_got_arg *arg;
 
   entry = (struct mips_got_entry *) *entryp;
-  must_recreate = (bfd_boolean *) data;
+  arg = (struct mips_elf_traverse_got_arg *) data;
   if (entry->abfd != NULL && entry->symndx == -1)
     {
       struct mips_elf_link_hash_entry *h;
@@ -4018,27 +3874,28 @@ mips_elf_check_recreate_got (void **entryp, void *data)
       if (h->root.root.type == bfd_link_hash_indirect
          || h->root.root.type == bfd_link_hash_warning)
        {
-         *must_recreate = TRUE;
+         arg->value = TRUE;
          return 0;
        }
     }
+  mips_elf_count_got_entry (arg->info, arg->g, entry);
   return 1;
 }
 
-/* A htab_traverse callback for GOT entries.  Add all entries to
-   hash table *DATA, converting entries for indirect and warning
-   symbols into entries for the target symbol.  Set *DATA to null
-   on error.  */
+/* A htab_traverse callback for GOT entries, with DATA pointing to a
+   mips_elf_traverse_got_arg structure.  Add all entries to DATA->g,
+   converting entries for indirect and warning symbols into entries
+   for the target symbol.  Set DATA->g to null on error.  */
 
 static int
 mips_elf_recreate_got (void **entryp, void *data)
 {
-  htab_t *new_got;
   struct mips_got_entry new_entry, *entry;
+  struct mips_elf_traverse_got_arg *arg;
   void **slot;
 
-  new_got = (htab_t *) data;
   entry = (struct mips_got_entry *) *entryp;
+  arg = (struct mips_elf_traverse_got_arg *) data;
   if (entry->abfd != NULL
       && entry->symndx == -1
       && (entry->d.h->root.root.type == bfd_link_hash_indirect
@@ -4058,10 +3915,10 @@ mips_elf_recreate_got (void **entryp, void *data)
             || h->root.root.type == bfd_link_hash_warning);
       entry->d.h = h;
     }
-  slot = htab_find_slot (*new_got, entry, INSERT);
+  slot = htab_find_slot (arg->g->got_entries, entry, INSERT);
   if (slot == NULL)
     {
-      *new_got = NULL;
+      arg->g = NULL;
       return 0;
     }
   if (*slot == NULL)
@@ -4071,45 +3928,246 @@ mips_elf_recreate_got (void **entryp, void *data)
          entry = bfd_alloc (entry->abfd, sizeof (*entry));
          if (!entry)
            {
-             *new_got = NULL;
+             arg->g = NULL;
              return 0;
            }
          *entry = new_entry;
        }
       *slot = entry;
+      mips_elf_count_got_entry (arg->info, arg->g, entry);
+    }
+  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 mips_got_info *g)
+mips_elf_resolve_final_got_entries (struct bfd_link_info *info,
+                                   struct mips_got_info *g)
 {
-  bfd_boolean must_recreate;
-  htab_t new_got;
+  struct mips_elf_traverse_got_arg tga;
+  struct mips_got_info oldg;
 
-  must_recreate = FALSE;
-  htab_traverse (g->got_entries, mips_elf_check_recreate_got, &must_recreate);
-  if (must_recreate)
+  oldg = *g;
+
+  tga.info = info;
+  tga.g = g;
+  tga.value = FALSE;
+  htab_traverse (g->got_entries, mips_elf_check_recreate_got, &tga);
+  if (tga.value)
     {
-      new_got = htab_create (htab_size (g->got_entries),
-                            mips_elf_got_entry_hash,
-                            mips_elf_got_entry_eq, NULL);
-      htab_traverse (g->got_entries, mips_elf_recreate_got, &new_got);
-      if (new_got == NULL)
+      *g = oldg;
+      g->got_entries = htab_create (htab_size (oldg.got_entries),
+                                   mips_elf_got_entry_hash,
+                                   mips_elf_got_entry_eq, NULL);
+      if (!g->got_entries)
+       return FALSE;
+
+      htab_traverse (oldg.got_entries, mips_elf_recreate_got, &tga);
+      if (!tga.g)
        return FALSE;
 
-      htab_delete (g->got_entries);
-      g->got_entries = new_got;
+      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;
 }
 
-/* A mips_elf_link_hash_traverse callback for which DATA points
-   to the link_info structure.  Count the number of type (3) entries
-   in the master GOT.  */
+/* A mips_elf_link_hash_traverse callback for which DATA points to the
+   link_info structure.  Decide whether the hash entry needs an entry in
+   the global part of the primary GOT, setting global_got_area accordingly.
+   Count the number of global symbols that are in the primary GOT only
+   because they have relocations against them (reloc_only_gotno).  */
 
 static int
 mips_elf_count_got_symbols (struct mips_elf_link_hash_entry *h, void *data)
@@ -4136,14 +4194,10 @@ mips_elf_count_got_symbols (struct mips_elf_link_hash_entry *h, void *data)
          || (h->got_only_for_calls
              ? SYMBOL_CALLS_LOCAL (info, &h->root)
              : SYMBOL_REFERENCES_LOCAL (info, &h->root)))
-       {
-         /* The symbol belongs in the local GOT.  We no longer need this
-            entry if it was only used for relocations; those relocations
-            will be against the null or section symbol instead of H.  */
-         if (h->global_got_area != GGA_RELOC_ONLY)
-           g->local_gotno++;
-         h->global_got_area = GGA_NONE;
-       }
+       /* The symbol belongs in the local GOT.  We no longer need this
+          entry if it was only used for relocations; those relocations
+          will be against the null or section symbol instead of H.  */
+       h->global_got_area = GGA_NONE;
       else if (htab->is_vxworks
               && h->got_only_for_calls
               && h->root.plt.offset != MINUS_ONE)
@@ -4151,11 +4205,10 @@ mips_elf_count_got_symbols (struct mips_elf_link_hash_entry *h, void *data)
           they don't need entries in the regular GOT.  .got.plt entries
           will be allocated by _bfd_mips_elf_adjust_dynamic_symbol.  */
        h->global_got_area = GGA_NONE;
-      else
+      else if (h->global_got_area == GGA_RELOC_ONLY)
        {
+         g->reloc_only_gotno++;
          g->global_gotno++;
-         if (h->global_got_area == GGA_RELOC_ONLY)
-           g->reloc_only_gotno++;
        }
     }
   return 1;
@@ -4275,17 +4328,12 @@ static bfd_boolean
 mips_elf_merge_got (bfd *abfd, struct mips_got_info *g,
                    struct mips_elf_got_per_bfd_arg *arg)
 {
-  struct mips_elf_traverse_got_arg tga;
   unsigned int estimate;
   int result;
 
-  if (!mips_elf_resolve_final_got_entries (g))
+  if (!mips_elf_resolve_final_got_entries (arg->info, g))
     return FALSE;
 
-  tga.info = arg->info;
-  tga.g = g;
-  htab_traverse (g->got_entries, mips_elf_count_got_entries, &tga);
-
   /* Work out the number of page, local and TLS entries.  */
   estimate = arg->max_pages;
   if (estimate > g->page_gotno)
@@ -4366,63 +4414,21 @@ mips_elf_initialize_tls_index (void **entryp, void *data)
 {
   struct mips_got_entry *entry;
   struct mips_elf_traverse_got_arg *arg;
-  struct mips_got_info *g;
-  bfd_vma next_index;
-  unsigned char tls_type;
 
   /* We're only interested in TLS symbols.  */
   entry = (struct mips_got_entry *) *entryp;
-  tls_type = (entry->tls_type & GOT_TLS_TYPE);
-  if (tls_type == 0)
+  if (entry->tls_type == GOT_TLS_NONE)
     return 1;
 
   arg = (struct mips_elf_traverse_got_arg *) data;
-  g = arg->g;
-  next_index = arg->value * g->tls_assigned_gotno;
-
-  if (entry->symndx == -1 && g->next == NULL)
+  if (!mips_elf_set_gotidx (entryp, arg->value * arg->g->tls_assigned_gotno))
     {
-      /* A type (3) got entry in the single-GOT case.  We use the symbol's
-        hash table entry to track its index.  */
-      if (tls_type == GOT_TLS_IE)
-       {
-         if (entry->d.h->tls_ie_type & GOT_TLS_OFFSET_DONE)
-           return 1;
-         entry->d.h->tls_ie_type |= GOT_TLS_OFFSET_DONE;
-         entry->d.h->tls_ie_got_offset = next_index;
-       }
-      else
-       {
-         BFD_ASSERT (tls_type == GOT_TLS_GD);
-         if (entry->d.h->tls_gd_type & GOT_TLS_OFFSET_DONE)
-           return 1;
-         entry->d.h->tls_gd_type |= GOT_TLS_OFFSET_DONE;
-         entry->d.h->tls_gd_got_offset = next_index;
-       }
-    }
-  else
-    {
-      if (tls_type == GOT_TLS_LDM)
-       {
-         /* There are separate mips_got_entry objects for each input bfd
-            that requires an LDM entry.  Make sure that all LDM entries in
-            a GOT resolve to the same index.  */
-         if (g->tls_ldm_offset != MINUS_TWO && g->tls_ldm_offset != MINUS_ONE)
-           {
-             entry->gotidx = g->tls_ldm_offset;
-             return 1;
-           }
-         g->tls_ldm_offset = next_index;
-       }
-      if (!mips_elf_set_gotidx (entryp, next_index))
-       {
-         arg->g = NULL;
-         return 0;
-       }
+      arg->g = NULL;
+      return 0;
     }
 
   /* Account for the entries we've just allocated.  */
-  g->tls_assigned_gotno += mips_tls_got_entries (tls_type);
+  arg->g->tls_assigned_gotno += mips_tls_got_entries (entry->tls_type);
   return 1;
 }
 
@@ -5194,8 +5200,8 @@ mips_elf_calculate_relocation (bfd *abfd, bfd *input_bfd,
           && h->fn_stub != NULL
           && (r_type != R_MIPS16_CALL16 || h->need_fn_stub))
          || (local_p
-             && elf_tdata (input_bfd)->local_stubs != NULL
-             && elf_tdata (input_bfd)->local_stubs[r_symndx] != NULL))
+             && mips_elf_tdata (input_bfd)->local_stubs != NULL
+             && mips_elf_tdata (input_bfd)->local_stubs[r_symndx] != NULL))
       && !section_allows_mips16_refs_p (input_section))
     {
       /* This is a 32- or 64-bit call to a 16-bit function.  We should
@@ -5203,7 +5209,7 @@ mips_elf_calculate_relocation (bfd *abfd, bfd *input_bfd,
         stub.  */
       if (local_p)
        {
-         sec = elf_tdata (input_bfd)->local_stubs[r_symndx];
+         sec = mips_elf_tdata (input_bfd)->local_stubs[r_symndx];
          value = 0;
        }
       else
@@ -5234,12 +5240,12 @@ mips_elf_calculate_relocation (bfd *abfd, bfd *input_bfd,
   else if (r_type == R_MIPS16_26 && !info->relocatable
           && ((h != NULL && (h->call_stub != NULL || h->call_fp_stub != NULL))
               || (local_p
-                  && elf_tdata (input_bfd)->local_call_stubs != NULL
-                  && elf_tdata (input_bfd)->local_call_stubs[r_symndx] != NULL))
+                  && mips_elf_tdata (input_bfd)->local_call_stubs != NULL
+                  && mips_elf_tdata (input_bfd)->local_call_stubs[r_symndx] != NULL))
           && !target_is_16_bit_code_p)
     {
       if (local_p)
-       sec = elf_tdata (input_bfd)->local_call_stubs[r_symndx];
+       sec = mips_elf_tdata (input_bfd)->local_call_stubs[r_symndx];
       else
        {
          /* If both call_stub and call_fp_stub are defined, we can figure
@@ -6421,7 +6427,7 @@ _bfd_mips_elf_symbol_processing (bfd *abfd, asymbol *asym)
       && (asym->value & 1) != 0)
     {
       asym->value--;
-      if (elf_elfheader (abfd)->e_flags & EF_MIPS_ARCH_ASE_MICROMIPS)
+      if (MICROMIPS_P (abfd))
        elfsym->internal_elf_sym.st_other
          = ELF_ST_SET_MICROMIPS (elfsym->internal_elf_sym.st_other);
       else
@@ -7023,7 +7029,7 @@ _bfd_mips_elf_add_symbol_hook (bfd *abfd, struct bfd_link_info *info,
 
     case SHN_MIPS_TEXT:
       /* This section is used in a shared object.  */
-      if (elf_tdata (abfd)->elf_text_section == NULL)
+      if (mips_elf_tdata (abfd)->elf_text_section == NULL)
        {
          asymbol *elf_text_symbol;
          asection *elf_text_section;
@@ -7040,11 +7046,11 @@ _bfd_mips_elf_add_symbol_hook (bfd *abfd, struct bfd_link_info *info,
 
          /* Initialize the section.  */
 
-         elf_tdata (abfd)->elf_text_section = elf_text_section;
-         elf_tdata (abfd)->elf_text_symbol = elf_text_symbol;
+         mips_elf_tdata (abfd)->elf_text_section = elf_text_section;
+         mips_elf_tdata (abfd)->elf_text_symbol = elf_text_symbol;
 
          elf_text_section->symbol = elf_text_symbol;
-         elf_text_section->symbol_ptr_ptr = &elf_tdata (abfd)->elf_text_symbol;
+         elf_text_section->symbol_ptr_ptr = &mips_elf_tdata (abfd)->elf_text_symbol;
 
          elf_text_section->name = ".text";
          elf_text_section->flags = SEC_NO_FLAGS;
@@ -7057,14 +7063,14 @@ _bfd_mips_elf_add_symbol_hook (bfd *abfd, struct bfd_link_info *info,
       /* This code used to do *secp = bfd_und_section_ptr if
          info->shared.  I don't know why, and that doesn't make sense,
          so I took it out.  */
-      *secp = elf_tdata (abfd)->elf_text_section;
+      *secp = mips_elf_tdata (abfd)->elf_text_section;
       break;
 
     case SHN_MIPS_ACOMMON:
       /* Fall through. XXX Can we treat this as allocated data?  */
     case SHN_MIPS_DATA:
       /* This section is used in a shared object.  */
-      if (elf_tdata (abfd)->elf_data_section == NULL)
+      if (mips_elf_tdata (abfd)->elf_data_section == NULL)
        {
          asymbol *elf_data_symbol;
          asection *elf_data_section;
@@ -7081,11 +7087,11 @@ _bfd_mips_elf_add_symbol_hook (bfd *abfd, struct bfd_link_info *info,
 
          /* Initialize the section.  */
 
-         elf_tdata (abfd)->elf_data_section = elf_data_section;
-         elf_tdata (abfd)->elf_data_symbol = elf_data_symbol;
+         mips_elf_tdata (abfd)->elf_data_section = elf_data_section;
+         mips_elf_tdata (abfd)->elf_data_symbol = elf_data_symbol;
 
          elf_data_section->symbol = elf_data_symbol;
-         elf_data_section->symbol_ptr_ptr = &elf_tdata (abfd)->elf_data_symbol;
+         elf_data_section->symbol_ptr_ptr = &mips_elf_tdata (abfd)->elf_data_symbol;
 
          elf_data_section->name = ".data";
          elf_data_section->flags = SEC_NO_FLAGS;
@@ -7098,7 +7104,7 @@ _bfd_mips_elf_add_symbol_hook (bfd *abfd, struct bfd_link_info *info,
       /* This code used to do *secp = bfd_und_section_ptr if
          info->shared.  I don't know why, and that doesn't make sense,
          so I took it out.  */
-      *secp = elf_tdata (abfd)->elf_data_section;
+      *secp = mips_elf_tdata (abfd)->elf_data_section;
       break;
 
     case SHN_MIPS_SUNDEFINED:
@@ -7322,7 +7328,7 @@ _bfd_mips_elf_create_dynamic_sections (bfd *abfd, struct bfd_link_info *info)
     }
 
   /* Create the .plt, .rel(a).plt, .dynbss and .rel(a).bss sections.
-     Also create the _PROCEDURE_LINKAGE_TABLE symbol.  */
+     Also, on VxWorks, create the _PROCEDURE_LINKAGE_TABLE_ symbol.  */
   if (!_bfd_elf_create_dynamic_sections (abfd, info))
     return FALSE;
 
@@ -7604,7 +7610,7 @@ _bfd_mips_elf_check_relocs (bfd *abfd, struct bfd_link_info *info,
 
          /* Record this stub in an array of local symbol stubs for
              this BFD.  */
-         if (elf_tdata (abfd)->local_stubs == NULL)
+         if (mips_elf_tdata (abfd)->local_stubs == NULL)
            {
              unsigned long symcount;
              asection **n;
@@ -7618,11 +7624,11 @@ _bfd_mips_elf_check_relocs (bfd *abfd, struct bfd_link_info *info,
              n = bfd_zalloc (abfd, amt);
              if (n == NULL)
                return FALSE;
-             elf_tdata (abfd)->local_stubs = n;
+             mips_elf_tdata (abfd)->local_stubs = n;
            }
 
          sec->flags |= SEC_KEEP;
-         elf_tdata (abfd)->local_stubs[r_symndx] = sec;
+         mips_elf_tdata (abfd)->local_stubs[r_symndx] = sec;
 
          /* We don't need to set mips16_stubs_seen in this case.
              That flag is used to see whether we need to look through
@@ -7729,7 +7735,7 @@ _bfd_mips_elf_check_relocs (bfd *abfd, struct bfd_link_info *info,
 
          /* Record this stub in an array of local symbol call_stubs for
              this BFD.  */
-         if (elf_tdata (abfd)->local_call_stubs == NULL)
+         if (mips_elf_tdata (abfd)->local_call_stubs == NULL)
            {
              unsigned long symcount;
              asection **n;
@@ -7743,11 +7749,11 @@ _bfd_mips_elf_check_relocs (bfd *abfd, struct bfd_link_info *info,
              n = bfd_zalloc (abfd, amt);
              if (n == NULL)
                return FALSE;
-             elf_tdata (abfd)->local_call_stubs = n;
+             mips_elf_tdata (abfd)->local_call_stubs = n;
            }
 
          sec->flags |= SEC_KEEP;
-         elf_tdata (abfd)->local_call_stubs[r_symndx] = sec;
+         mips_elf_tdata (abfd)->local_call_stubs[r_symndx] = sec;
 
          /* We don't need to set mips16_stubs_seen in this case.
              That flag is used to see whether we need to look through
@@ -8016,21 +8022,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:
@@ -8059,10 +8050,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:
@@ -8791,14 +8796,13 @@ mips_elf_lay_out_got (bfd *output_bfd, struct bfd_link_info *info)
   g->local_gotno += htab->reserved_gotno;
   g->assigned_gotno = htab->reserved_gotno;
 
-  /* Replace entries for indirect and warning symbols with entries for
-     the target symbol.  */
-  if (!mips_elf_resolve_final_got_entries (g))
-    return FALSE;
-
-  /* Count the number of GOT symbols.  */
+  /* Decide which symbols need to go in the global part of the GOT and
+     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.  */
@@ -8827,25 +8831,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;
 
-  /* Count the number of local GOT entries and TLS relocs.  */
-  tga.info = info;
-  tga.g = g;
-  htab_traverse (g->got_entries, mips_elf_count_local_got_entries, &tga);
-
-  /* We need to calculate tls_gotno for global symbols at this point
-     instead of building it up earlier, to avoid doublecounting
-     entries for one global symbol from multiple input files.  */
-  elf_link_hash_traverse (elf_hash_table (info),
-                         mips_elf_count_global_tls_entries,
-                         &tga);
-
   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);
@@ -8853,20 +8845,7 @@ mips_elf_lay_out_got (bfd *output_bfd, struct bfd_link_info *info)
   /* VxWorks does not support multiple GOTs.  It initializes $gp to
      __GOTT_BASE__[__GOTT_INDEX__], the value of which is set by the
      dynamic loader.  */
-  if (htab->is_vxworks)
-    {
-      /* VxWorks executables do not need a GOT.  */
-      if (info->shared)
-       {
-         /* Each VxWorks GOT entry needs an explicit relocation.  */
-         unsigned int count;
-
-         count = g->global_gotno + g->local_gotno - htab->reserved_gotno;
-         if (count)
-           mips_elf_allocate_dynamic_relocations (dynobj, info, count);
-       }
-    }
-  else if (s->size > MIPS_ELF_GOT_MAX_SIZE (info))
+  if (!htab->is_vxworks && s->size > MIPS_ELF_GOT_MAX_SIZE (info))
     {
       if (!mips_elf_multi_got (output_bfd, info, s, page_gotno))
        return FALSE;
@@ -8891,6 +8870,10 @@ mips_elf_lay_out_got (bfd *output_bfd, struct bfd_link_info *info)
       BFD_ASSERT (g->tls_assigned_gotno
                  == g->global_gotno + g->local_gotno + g->tls_gotno);
 
+      /* Each VxWorks GOT entry needs an explicit relocation.  */
+      if (htab->is_vxworks && info->shared)
+       g->relocs += g->global_gotno + g->local_gotno - htab->reserved_gotno;
+
       /* Allocate room for the TLS relocations.  */
       if (g->relocs)
        mips_elf_allocate_dynamic_relocations (dynobj, info, g->relocs);
@@ -8937,7 +8920,7 @@ mips_elf_estimate_stub_size (bfd *output_bfd, struct bfd_link_info *info)
    allocate an entry in the stubs section.  */
 
 static bfd_boolean
-mips_elf_allocate_lazy_stub (struct mips_elf_link_hash_entry *h, void **data)
+mips_elf_allocate_lazy_stub (struct mips_elf_link_hash_entry *h, void *data)
 {
   struct mips_elf_link_hash_table *htab;
 
@@ -10027,7 +10010,7 @@ _bfd_mips_elf_finish_dynamic_symbol (bfd *output_bfd,
       e.abfd = output_bfd;
       e.symndx = -1;
       e.d.h = hmips;
-      e.tls_type = 0;
+      e.tls_type = GOT_TLS_NONE;
 
       for (g = g->next; g->next != gg; g = g->next)
        {
@@ -10036,6 +10019,7 @@ _bfd_mips_elf_finish_dynamic_symbol (bfd *output_bfd,
                                                           &e)))
            {
              offset = p->gotidx;
+             BFD_ASSERT (offset > 0 && offset < htab->sgot->size);
              if (info->shared
                  || (elf_hash_table (info)->dynamic_sections_created
                      && p->d.h != NULL
@@ -10134,13 +10118,18 @@ _bfd_mips_elf_finish_dynamic_symbol (bfd *output_bfd,
   if (IRIX_COMPAT (output_bfd) == ict_irix6)
     mips_elf_irix6_finish_dynamic_symbol (output_bfd, name, sym);
 
-  /* Keep dynamic MIPS16 symbols odd.  This allows the dynamic linker to
-     treat MIPS16 symbols like any other.  */
+  /* Keep dynamic compressed symbols odd.  This allows the dynamic linker
+     to treat compressed symbols like any other.  */
   if (ELF_ST_IS_MIPS16 (sym->st_other))
     {
       BFD_ASSERT (sym->st_value & 1);
       sym->st_other -= STO_MIPS16;
     }
+  else if (ELF_ST_IS_MICROMIPS (sym->st_other))
+    {
+      BFD_ASSERT (sym->st_value & 1);
+      sym->st_other -= STO_MICROMIPS;
+    }
 
   return TRUE;
 }
@@ -11152,7 +11141,7 @@ _bfd_mips_elf_modify_segment_map (bfd *abfd,
   s = bfd_get_section_by_name (abfd, ".reginfo");
   if (s != NULL && (s->flags & SEC_LOAD) != 0)
     {
-      for (m = elf_tdata (abfd)->segment_map; m != NULL; m = m->next)
+      for (m = elf_seg_map (abfd); m != NULL; m = m->next)
        if (m->p_type == PT_MIPS_REGINFO)
          break;
       if (m == NULL)
@@ -11167,7 +11156,7 @@ _bfd_mips_elf_modify_segment_map (bfd *abfd,
          m->sections[0] = s;
 
          /* We want to put it after the PHDR and INTERP segments.  */
-         pm = &elf_tdata (abfd)->segment_map;
+         pm = &elf_seg_map (abfd);
          while (*pm != NULL
                 && ((*pm)->p_type == PT_PHDR
                     || (*pm)->p_type == PT_INTERP))
@@ -11197,7 +11186,7 @@ _bfd_mips_elf_modify_segment_map (bfd *abfd,
        {
          struct elf_segment_map *options_segment;
 
-         pm = &elf_tdata (abfd)->segment_map;
+         pm = &elf_seg_map (abfd);
          while (*pm != NULL
                 && ((*pm)->p_type == PT_PHDR
                     || (*pm)->p_type == PT_INTERP))
@@ -11227,7 +11216,7 @@ _bfd_mips_elf_modify_segment_map (bfd *abfd,
              && bfd_get_section_by_name (abfd, ".dynamic") != NULL
              && bfd_get_section_by_name (abfd, ".mdebug") != NULL)
            {
-             for (m = elf_tdata (abfd)->segment_map; m != NULL; m = m->next)
+             for (m = elf_seg_map (abfd); m != NULL; m = m->next)
                if (m->p_type == PT_MIPS_RTPROC)
                  break;
              if (m == NULL)
@@ -11253,7 +11242,7 @@ _bfd_mips_elf_modify_segment_map (bfd *abfd,
                    }
 
                  /* We want to put it after the DYNAMIC segment.  */
-                 pm = &elf_tdata (abfd)->segment_map;
+                 pm = &elf_seg_map (abfd);
                  while (*pm != NULL && (*pm)->p_type != PT_DYNAMIC)
                    pm = &(*pm)->next;
                  if (*pm != NULL)
@@ -11267,7 +11256,7 @@ _bfd_mips_elf_modify_segment_map (bfd *abfd,
       /* On IRIX5, the PT_DYNAMIC segment includes the .dynamic,
         .dynstr, .dynsym, and .hash sections, and everything in
         between.  */
-      for (pm = &elf_tdata (abfd)->segment_map; *pm != NULL;
+      for (pm = &elf_seg_map (abfd); *pm != NULL;
           pm = &(*pm)->next)
        if ((*pm)->p_type == PT_DYNAMIC)
          break;
@@ -11374,7 +11363,7 @@ _bfd_mips_elf_modify_segment_map (bfd *abfd,
       && !SGI_COMPAT (abfd)
       && bfd_get_section_by_name (abfd, ".dynamic"))
     {
-      for (pm = &elf_tdata (abfd)->segment_map; *pm != NULL; pm = &(*pm)->next)
+      for (pm = &elf_seg_map (abfd); *pm != NULL; pm = &(*pm)->next)
        if ((*pm)->p_type == PT_NULL)
          break;
       if (*pm == NULL)
@@ -11529,11 +11518,6 @@ _bfd_mips_elf_copy_indirect_symbol (struct bfd_link_info *info,
     indmips->global_got_area = GGA_NONE;
   if (indmips->has_nonpic_branches)
     dirmips->has_nonpic_branches = TRUE;
-
-  if (dirmips->tls_ie_type == 0)
-    dirmips->tls_ie_type = indmips->tls_ie_type;
-  if (dirmips->tls_gd_type == 0)
-    dirmips->tls_gd_type = indmips->tls_gd_type;
 }
 \f
 #define PDR_SIZE 32
@@ -11690,7 +11674,7 @@ _bfd_mips_elf_find_nearest_line (bfd *abfd, asection *section,
       if (elf_section_data (msec)->this_hdr.sh_type != SHT_NOBITS)
        msec->flags |= SEC_HAS_CONTENTS;
 
-      fi = elf_tdata (abfd)->find_line_info;
+      fi = mips_elf_tdata (abfd)->find_line_info;
       if (fi == NULL)
        {
          bfd_size_type external_fdr_size;
@@ -11728,7 +11712,7 @@ _bfd_mips_elf_find_nearest_line (bfd *abfd, asection *section,
          for (; fraw_src < fraw_end; fraw_src += external_fdr_size, fdr_ptr++)
            (*swap->swap_fdr_in) (abfd, fraw_src, fdr_ptr);
 
-         elf_tdata (abfd)->find_line_info = fi;
+         mips_elf_tdata (abfd)->find_line_info = fi;
 
          /* Note that we don't bother to ever free this information.
              find_nearest_line is either called all the time, as in