* elflink.c (_bfd_elf_merge_symbol): Use local var holding value
[binutils-gdb.git] / bfd / elfxx-mips.c
index 102e57fa427f33088b41ada346845a5424c2ace1..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,23 +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.  */
-#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_DONE    0x80
+  /* 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.  */
@@ -114,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.  */
@@ -150,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
@@ -439,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.  */
@@ -470,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.  */
@@ -692,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))
@@ -2742,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))
@@ -2757,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
@@ -2781,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.  */
@@ -2800,9 +2875,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;
@@ -2839,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;
 }
@@ -2889,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.  */
@@ -2906,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 ();
@@ -2937,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;
@@ -2961,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);
     }
@@ -2977,23 +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;
-}
-
 /* Output a simple dynamic relocation into SRELOC.  */
 
 static void
@@ -3028,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);
@@ -3056,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)
@@ -3073,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.  */
@@ -3147,21 +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;
+  entry->tls_initialized = TRUE;
 }
 
 /* Return the offset from _GLOBAL_OFFSET_TABLE_ of the .got.plt entry
@@ -3222,10 +3265,8 @@ mips_elf_local_got_index (bfd *abfd, bfd *ibfd, struct bfd_link_info *info,
     return MINUS_ONE;
 
   if (entry->tls_type)
-    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.  */
@@ -3301,8 +3342,7 @@ 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);
 
-      return mips_tls_got_index (obfd, gotidx, &entry->tls_type,
-                                info, lookup.d.h, value);
+      mips_elf_initialize_tls_slots (obfd, info, entry, lookup.d.h, value);
     }
   return gotidx;
 }
@@ -3632,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;
@@ -3688,7 +3729,7 @@ 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;
 
   entry.abfd = abfd;
@@ -3722,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);
@@ -3754,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;
     }
 
@@ -3782,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;
 }
 
@@ -3875,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;
@@ -3894,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
@@ -3934,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)
@@ -3947,39 +3928,238 @@ 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;
+
+  oldg = *g;
 
-  must_recreate = FALSE;
-  htab_traverse (g->got_entries, mips_elf_check_recreate_got, &must_recreate);
-  if (must_recreate)
+  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_delete (g->got_entries);
-      g->got_entries = new_got;
+      htab_traverse (oldg.got_entries, mips_elf_recreate_got, &tga);
+      if (!tga.g)
+       return FALSE;
+
+      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;
 }
 
@@ -4148,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)
@@ -4239,12 +4414,10 @@ mips_elf_initialize_tls_index (void **entryp, void *data)
 {
   struct mips_got_entry *entry;
   struct mips_elf_traverse_got_arg *arg;
-  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;
@@ -4255,7 +4428,7 @@ mips_elf_initialize_tls_index (void **entryp, void *data)
     }
 
   /* Account for the entries we've just allocated.  */
-  arg->g->tls_assigned_gotno += mips_tls_got_entries (tls_type);
+  arg->g->tls_assigned_gotno += mips_tls_got_entries (entry->tls_type);
   return 1;
 }
 
@@ -5027,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
@@ -5036,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
@@ -5067,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
@@ -6254,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
@@ -6856,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;
@@ -6873,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;
@@ -6890,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;
@@ -6914,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;
@@ -6931,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:
@@ -7155,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;
 
@@ -7437,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;
@@ -7451,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
@@ -7562,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;
@@ -7576,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
@@ -7849,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:
@@ -7892,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:
@@ -8624,15 +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;
-
   /* 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.  */
@@ -8661,18 +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 GOT entries and TLS relocs.  */
-  tga.info = info;
-  tga.g = g;
-  htab_traverse (g->got_entries, mips_elf_count_got_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);
@@ -8680,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;
@@ -8718,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);
@@ -8764,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;
 
@@ -9854,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)
        {
@@ -9962,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;
 }
@@ -10980,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)
@@ -10995,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))
@@ -11025,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))
@@ -11055,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)
@@ -11081,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)
@@ -11095,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;
@@ -11202,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)
@@ -11513,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;
@@ -11551,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