]> git.ipfire.org Git - thirdparty/binutils-gdb.git/blobdiff - bfd/elfxx-mips.c
Correct spelling of "relocatable".
[thirdparty/binutils-gdb.git] / bfd / elfxx-mips.c
index 80a583bc60f4b8c9dc0bacde0f153a7f7f212f0a..3e85fc3b40ab727acdf3bd69f7235031d4d553f2 100644 (file)
@@ -1,6 +1,6 @@
 /* MIPS-specific support for ELF
-   Copyright 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002
-   Free Software Foundation, Inc.
+   Copyright 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002,
+   2003 Free Software Foundation, Inc.
 
    Most of the information added by Ian Lance Taylor, Cygnus Support,
    <ian@cygnus.com>.
@@ -9,27 +9,28 @@
    Traditional MIPS targets support added by Koundinya.K, Dansk Data
    Elektronik & Operations Research Group. <kk@ddeorg.soft.net>
 
-This file is part of BFD, the Binary File Descriptor library.
+   This file is part of BFD, the Binary File Descriptor library.
 
-This program is free software; you can redistribute it and/or modify
-it under the terms of the GNU General Public License as published by
-the Free Software Foundation; either version 2 of the License, or
-(at your option) any later version.
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 2 of the License, or
+   (at your option) any later version.
 
-This program is distributed in the hope that it will be useful,
-but WITHOUT ANY WARRANTY; without even the implied warranty of
-MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-GNU General Public License for more details.
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
 
-You should have received a copy of the GNU General Public License
-along with this program; if not, write to the Free Software
-Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.  */
+   You should have received a copy of the GNU General Public License
+   along with this program; if not, write to the Free Software
+   Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.  */
 
 /* This file handles functionality common to the different MIPS ABI's.  */
 
 #include "bfd.h"
 #include "sysdep.h"
 #include "libbfd.h"
+#include "libiberty.h"
 #include "elf-bfd.h"
 #include "elfxx-mips.h"
 #include "elf/mips.h"
@@ -48,20 +49,28 @@ struct mips_got_entry
 {
   /* The input bfd in which the symbol is defined.  */
   bfd *abfd;
-  /* The index of the symbol, as stored in the relocation r_info.  If
-     it's -1, the addend is a complete address into the
-     executable/shared library.  */
-  unsigned long symndx;
-  /* The addend of the relocation that should be added to the symbol
-     value.  */
-  bfd_vma addend;
+  /* The index of the symbol, as stored in the relocation r_info, if
+     we have a local symbol; -1 otherwise.  */
+  long symndx;
+  union
+  {
+    /* If abfd == NULL, an address that must be stored in the got.  */
+    bfd_vma address;
+    /* If abfd != NULL && symndx != -1, the addend of the relocation
+       that should be added to the symbol value.  */
+    bfd_vma addend;
+    /* If abfd != NULL && symndx == -1, the hash table entry
+       corresponding to a global symbol in the got (or, local, if
+       h->forced_local).  */
+    struct mips_elf_link_hash_entry *h;
+  } d;
   /* The offset from the beginning of the .got section to the entry
-     corresponding to this symbol+addend.  */
-  unsigned long gotidx;
+     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 is used to hold .got information when linking.  It
-   is stored in the tdata field of the bfd_elf_section_data structure.  */
+/* This structure is used to hold .got information when linking.  */
 
 struct mips_got_info
 {
@@ -76,8 +85,71 @@ struct mips_got_info
   unsigned int assigned_gotno;
   /* A hash table holding members of the got.  */
   struct htab *got_entries;
+  /* A hash table mapping input bfds to other mips_got_info.  NULL
+     unless multi-got was necessary.  */
+  struct htab *bfd2got;
+  /* 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;
 };
 
+/* Map an input bfd to a got in a multi-got link.  */
+
+struct mips_elf_bfd2got_hash {
+  bfd *bfd;
+  struct mips_got_info *g;
+};
+
+/* Structure passed when traversing the bfd2got hash table, used to
+   create and merge bfd's gots.  */
+
+struct mips_elf_got_per_bfd_arg
+{
+  /* A hashtable that maps bfds to gots.  */
+  htab_t bfd2got;
+  /* The output bfd.  */
+  bfd *obfd;
+  /* The link information.  */
+  struct bfd_link_info *info;
+  /* A pointer to the primary got, i.e., the one that's going to get
+     the implicit relocations from DT_MIPS_LOCAL_GOTNO and
+     DT_MIPS_GOTSYM.  */
+  struct mips_got_info *primary;
+  /* A non-primary got we're trying to merge with other input bfd's
+     gots.  */
+  struct mips_got_info *current;
+  /* The maximum number of got entries that can be addressed with a
+     16-bit offset.  */
+  unsigned int max_count;
+  /* The number of local and global entries in the primary got.  */
+  unsigned int primary_count;
+  /* The number of local and global entries in the current got.  */
+  unsigned int current_count;
+};
+
+/* Another structure used to pass arguments for got entries traversal.  */
+
+struct mips_elf_set_global_got_offset_arg
+{
+  struct mips_got_info *g;
+  int value;
+  unsigned int needed_relocs;
+  struct bfd_link_info *info;
+};
+
+struct _mips_elf_section_data
+{
+  struct bfd_elf_section_data elf;
+  union
+  {
+    struct mips_got_info *got_info;
+    bfd_byte *tdata;
+  } u;
+};
+
+#define mips_elf_section_data(sec) \
+  ((struct _mips_elf_section_data *) elf_section_data (sec))
+
 /* This structure is passed to mips_elf_sort_hash_table_f when sorting
    the dynamic symbols.  */
 
@@ -89,6 +161,10 @@ struct mips_elf_hash_sort_data
   /* The least dynamic symbol table index corresponding to a symbol
      with a GOT entry.  */
   long min_got_dynindx;
+  /* The greatest dynamic symbol table index corresponding to a symbol
+     with a GOT entry that is not referenced (e.g., a dynamic symbol
+     with dynamic relocations pointing to it from non-primary GOTs).  */
+  long max_unref_got_dynindx;
   /* The greatest dynamic symbol table index not corresponding to a
      symbol without a GOT entry.  */
   long max_non_got_dynindx;
@@ -282,17 +358,17 @@ typedef struct
    loader for use by the static exception system.  */
 
 typedef struct runtime_pdr {
-       bfd_vma adr;            /* memory address of start of procedure */
-       long    regmask;        /* save register mask */
-       long    regoffset;      /* save register offset */
-       long    fregmask;       /* save floating point register mask */
-       long    fregoffset;     /* save floating point register offset */
-       long    frameoffset;    /* frame size */
-       short   framereg;       /* frame pointer register */
-       short   pcreg;          /* offset or reg of return pc */
-       long    irpss;          /* index into the runtime string table */
+       bfd_vma adr;            /* Memory address of start of procedure.  */
+       long    regmask;        /* Save register mask.  */
+       long    regoffset;      /* Save register offset.  */
+       long    fregmask;       /* Save floating point register mask.  */
+       long    fregoffset;     /* Save floating point register offset.  */
+       long    frameoffset;    /* Frame size.  */
+       short   framereg;       /* Frame pointer register.  */
+       short   pcreg;          /* Offset or reg of return pc.  */
+       long    irpss;          /* Index into the runtime string table.  */
        long    reserved;
-       struct exception_info *exception_info;/* pointer to exception array */
+       struct exception_info *exception_info;/* Pointer to exception array.  */
 } RPDR, *pRPDR;
 #define cbRPDR sizeof (RPDR)
 #define rpdNil ((pRPDR) 0)
@@ -322,37 +398,42 @@ static void bfd_mips_elf_swap_msym_out
   PARAMS ((bfd *, const Elf32_Internal_Msym *, Elf32_External_Msym *));
 static int sort_dynamic_relocs
   PARAMS ((const void *, const void *));
+static int sort_dynamic_relocs_64
+  PARAMS ((const void *, const void *));
 static bfd_boolean mips_elf_output_extsym
   PARAMS ((struct mips_elf_link_hash_entry *, PTR));
 static int gptab_compare PARAMS ((const void *, const void *));
-static asection * mips_elf_got_section PARAMS ((bfd *));
+static asection * mips_elf_rel_dyn_section PARAMS ((bfd *, bfd_boolean));
+static asection * mips_elf_got_section PARAMS ((bfd *, bfd_boolean));
 static struct mips_got_info *mips_elf_got_info
   PARAMS ((bfd *, asection **));
+static long mips_elf_get_global_gotsym_index PARAMS ((bfd *abfd));
 static bfd_vma mips_elf_local_got_index
-  PARAMS ((bfd *, struct bfd_link_info *, bfd_vma));
+  PARAMS ((bfd *, bfd *, struct bfd_link_info *, bfd_vma));
 static bfd_vma mips_elf_global_got_index
-  PARAMS ((bfd *, struct elf_link_hash_entry *));
+  PARAMS ((bfd *, bfd *, struct elf_link_hash_entry *));
 static bfd_vma mips_elf_got_page
-  PARAMS ((bfd *, struct bfd_link_info *, bfd_vma, bfd_vma *));
+  PARAMS ((bfd *, bfd *, struct bfd_link_info *, bfd_vma, bfd_vma *));
 static bfd_vma mips_elf_got16_entry
-  PARAMS ((bfd *, struct bfd_link_info *, bfd_vma, bfd_boolean));
+  PARAMS ((bfd *, bfd *, struct bfd_link_info *, bfd_vma, bfd_boolean));
 static bfd_vma mips_elf_got_offset_from_index
-  PARAMS ((bfd *, bfd *, bfd_vma));
+  PARAMS ((bfd *, bfd *, bfd *, bfd_vma));
 static struct mips_got_entry *mips_elf_create_local_got_entry
-  PARAMS ((bfd *, struct mips_got_info *, asection *, bfd_vma));
+  PARAMS ((bfd *, bfd *, struct mips_got_info *, asection *, bfd_vma));
 static bfd_boolean mips_elf_sort_hash_table
   PARAMS ((struct bfd_link_info *, unsigned long));
 static bfd_boolean mips_elf_sort_hash_table_f
   PARAMS ((struct mips_elf_link_hash_entry *, PTR));
+static bfd_boolean mips_elf_record_local_got_symbol
+  PARAMS ((bfd *, long, bfd_vma, struct mips_got_info *));
 static bfd_boolean mips_elf_record_global_got_symbol
-  PARAMS ((struct elf_link_hash_entry *, struct bfd_link_info *,
+  PARAMS ((struct elf_link_hash_entry *, bfd *, struct bfd_link_info *,
           struct mips_got_info *));
 static const Elf_Internal_Rela *mips_elf_next_relocation
   PARAMS ((bfd *, unsigned int, const Elf_Internal_Rela *,
           const Elf_Internal_Rela *));
 static bfd_boolean mips_elf_local_relocation_p
   PARAMS ((bfd *, const Elf_Internal_Rela *, asection **, bfd_boolean));
-static bfd_vma mips_elf_sign_extend PARAMS ((bfd_vma, int));
 static bfd_boolean mips_elf_overflow_p PARAMS ((bfd_vma, int));
 static bfd_vma mips_elf_high PARAMS ((bfd_vma));
 static bfd_vma mips_elf_higher PARAMS ((bfd_vma));
@@ -360,7 +441,7 @@ static bfd_vma mips_elf_highest PARAMS ((bfd_vma));
 static bfd_boolean mips_elf_create_compact_rel_section
   PARAMS ((bfd *, struct bfd_link_info *));
 static bfd_boolean mips_elf_create_got_section
-  PARAMS ((bfd *, struct bfd_link_info *));
+  PARAMS ((bfd *, struct bfd_link_info *, bfd_boolean));
 static asection *mips_elf_create_msym_section
   PARAMS ((bfd *));
 static bfd_reloc_status_type mips_elf_calculate_relocation
@@ -382,14 +463,34 @@ static bfd_boolean mips_elf_create_dynamic_relocation
   PARAMS ((bfd *, struct bfd_link_info *, const Elf_Internal_Rela *,
           struct mips_elf_link_hash_entry *, asection *,
           bfd_vma, bfd_vma *, asection *));
-static INLINE int elf_mips_isa PARAMS ((flagword));
+static void mips_set_isa_flags PARAMS ((bfd *));
 static INLINE char* elf_mips_abi_name PARAMS ((bfd *));
 static void mips_elf_irix6_finish_dynamic_symbol
   PARAMS ((bfd *, const char *, Elf_Internal_Sym *));
-static bfd_boolean _bfd_mips_elf_mach_extends_p PARAMS ((flagword, flagword));
+static bfd_boolean mips_mach_extends_p PARAMS ((unsigned long, unsigned long));
+static bfd_boolean mips_32bit_flags_p PARAMS ((flagword));
+static INLINE hashval_t mips_elf_hash_bfd_vma PARAMS ((bfd_vma));
 static hashval_t mips_elf_got_entry_hash PARAMS ((const PTR));
 static int mips_elf_got_entry_eq PARAMS ((const PTR, const PTR));
 
+static bfd_boolean mips_elf_multi_got
+  PARAMS ((bfd *, struct bfd_link_info *, struct mips_got_info *,
+          asection *, bfd_size_type));
+static hashval_t mips_elf_multi_got_entry_hash PARAMS ((const PTR));
+static int mips_elf_multi_got_entry_eq PARAMS ((const PTR, const PTR));
+static hashval_t mips_elf_bfd2got_entry_hash PARAMS ((const PTR));
+static int mips_elf_bfd2got_entry_eq PARAMS ((const PTR, const PTR));
+static int mips_elf_make_got_per_bfd PARAMS ((void **, void *));
+static int mips_elf_merge_gots PARAMS ((void **, void *));
+static int mips_elf_set_global_got_offset PARAMS ((void**, void *));
+static int mips_elf_resolve_final_got_entry PARAMS ((void**, void *));
+static void mips_elf_resolve_final_got_entries
+  PARAMS ((struct mips_got_info *));
+static bfd_vma mips_elf_adjust_gp
+  PARAMS ((bfd *, struct mips_got_info *, bfd *));
+static struct mips_got_info *mips_elf_got_for_ibfd
+  PARAMS ((struct mips_got_info *, bfd *));
+
 /* This will be used when we sort the dynamic relocation records.  */
 static bfd *reldyn_sorting_bfd;
 
@@ -415,11 +516,11 @@ static bfd *reldyn_sorting_bfd;
 
 /* The name of the options section.  */
 #define MIPS_ELF_OPTIONS_SECTION_NAME(abfd) \
-  (ABI_64_P (abfd) ? ".MIPS.options" : ".options")
+  (NEWABI_P (abfd) ? ".MIPS.options" : ".options")
 
 /* The name of the stub section.  */
 #define MIPS_ELF_STUB_SECTION_NAME(abfd) \
-  (ABI_64_P (abfd) ? ".MIPS.stubs" : ".stub")
+  (NEWABI_P (abfd) ? ".MIPS.stubs" : ".stub")
 
 /* The size of an external REL relocation.  */
 #define MIPS_ELF_REL_SIZE(abfd) \
@@ -439,7 +540,7 @@ static bfd *reldyn_sorting_bfd;
 
 /* The default alignment for sections, as a power of two.  */
 #define MIPS_ELF_LOG_FILE_ALIGN(abfd)                          \
-  (get_elf_backend_data (abfd)->s->file_align == 8 ? 3 : 2)
+  (get_elf_backend_data (abfd)->s->log_file_align)
 
 /* Get word-sized data.  */
 #define MIPS_ELF_GET_WORD(abfd, ptr) \
@@ -491,15 +592,19 @@ static bfd *reldyn_sorting_bfd;
 /* The number of local .got entries we reserve.  */
 #define MIPS_RESERVED_GOTNO (2)
 
+/* The offset of $gp from the beginning of the .got section.  */
+#define ELF_MIPS_GP_OFFSET(abfd) (0x7ff0)
+
+/* The maximum size of the GOT for it to be addressable using 16-bit
+   offsets from $gp.  */
+#define MIPS_ELF_GOT_MAX_SIZE(abfd) (ELF_MIPS_GP_OFFSET(abfd) + 0x7fff)
+
 /* Instructions which appear in a stub.  For some reason the stub is
    slightly different on an SGI system.  */
-#define ELF_MIPS_GP_OFFSET(abfd) (SGI_COMPAT (abfd) ? 0x7ff0 : 0x8000)
 #define STUB_LW(abfd)                                          \
-  (SGI_COMPAT (abfd)                                           \
-   ? (ABI_64_P (abfd)                                                  \
-      ? 0xdf998010             /* ld t9,0x8010(gp) */          \
-      : 0x8f998010)             /* lw t9,0x8010(gp) */         \
-   : 0x8f998010)               /* lw t9,0x8000(gp) */
+  ((ABI_64_P (abfd)                                            \
+    ? 0xdf998010               /* ld t9,0x8010(gp) */          \
+    : 0x8f998010))              /* lw t9,0x8010(gp) */
 #define STUB_MOVE(abfd)                                         \
   (SGI_COMPAT (abfd) ? 0x03e07825 : 0x03e07821)         /* move t7,ra */
 #define STUB_JALR 0x0320f809                           /* jal t9 */
@@ -636,6 +741,22 @@ mips_elf_link_hash_newfunc (entry, table, string)
 
   return (struct bfd_hash_entry *) ret;
 }
+
+bfd_boolean
+_bfd_mips_elf_new_section_hook (abfd, sec)
+     bfd *abfd;
+     asection *sec;
+{
+  struct _mips_elf_section_data *sdata;
+  bfd_size_type amt = sizeof (*sdata);
+
+  sdata = (struct _mips_elf_section_data *) bfd_zalloc (abfd, amt);
+  if (sdata == NULL)
+    return FALSE;
+  sec->used_by_bfd = (PTR) sdata;
+
+  return _bfd_elf_new_section_hook (abfd, sec);
+}
 \f
 /* Read ECOFF debugging information from a .mdebug section into a
    ecoff_debug_info structure.  */
@@ -959,18 +1080,18 @@ mips_elf_check_mips16_stubs (h, data)
 \f
 bfd_reloc_status_type
 _bfd_mips_elf_gprel16_with_gp (abfd, symbol, reloc_entry, input_section,
-                              relocateable, data, gp)
+                              relocatable, data, gp)
      bfd *abfd;
      asymbol *symbol;
      arelent *reloc_entry;
      asection *input_section;
-     bfd_boolean relocateable;
+     bfd_boolean relocatable;
      PTR data;
      bfd_vma gp;
 {
   bfd_vma relocation;
-  unsigned long insn;
-  unsigned long val;
+  unsigned long insn = 0;
+  bfd_signed_vma val;
 
   if (bfd_is_com_section (symbol->section))
     relocation = 0;
@@ -983,35 +1104,36 @@ _bfd_mips_elf_gprel16_with_gp (abfd, symbol, reloc_entry, input_section,
   if (reloc_entry->address > input_section->_cooked_size)
     return bfd_reloc_outofrange;
 
-  insn = bfd_get_32 (abfd, (bfd_byte *) data + reloc_entry->address);
-
   /* Set val to the offset into the section or symbol.  */
-  if (reloc_entry->howto->src_mask == 0)
-    {
-      /* This case occurs with the 64-bit MIPS ELF ABI.  */
-      val = reloc_entry->addend;
-    }
-  else
+  val = reloc_entry->addend;
+
+  if (reloc_entry->howto->partial_inplace)
     {
-      val = ((insn & 0xffff) + reloc_entry->addend) & 0xffff;
-      if (val & 0x8000)
-       val -= 0x10000;
+      insn = bfd_get_32 (abfd, (bfd_byte *) data + reloc_entry->address);
+      val += insn & 0xffff;
     }
 
+  _bfd_mips_elf_sign_extend(val, 16);
+
   /* Adjust val for the final section location and GP value.  If we
-     are producing relocateable output, we don't want to do this for
+     are producing relocatable output, we don't want to do this for
      an external symbol.  */
-  if (! relocateable
+  if (! relocatable
       || (symbol->flags & BSF_SECTION_SYM) != 0)
     val += relocation - gp;
 
-  insn = (insn & ~0xffff) | (val & 0xffff);
-  bfd_put_32 (abfd, insn, (bfd_byte *) data + reloc_entry->address);
+  if (reloc_entry->howto->partial_inplace)
+    {
+      insn = (insn & ~0xffff) | (val & 0xffff);
+      bfd_put_32 (abfd, (bfd_vma) insn,
+                 (bfd_byte *) data + reloc_entry->address);
+    }
+  else
+    reloc_entry->addend = val;
 
-  if (relocateable)
+  if (relocatable)
     reloc_entry->address += input_section->output_offset;
-
-  else if ((long) val >= 0x8000 || (long) val < -0x8000)
+  else if (((val & ~0xffff) != ~0xffff) && ((val & ~0xffff) != 0))
     return bfd_reloc_overflow;
 
   return bfd_reloc_ok;
@@ -1209,6 +1331,26 @@ sort_dynamic_relocs (arg1, arg2)
   return ELF32_R_SYM (int_reloc1.r_info) - ELF32_R_SYM (int_reloc2.r_info);
 }
 
+/* Like sort_dynamic_relocs, but used for elf64 relocations.  */
+
+static int
+sort_dynamic_relocs_64 (arg1, arg2)
+     const PTR arg1;
+     const PTR arg2;
+{
+  Elf_Internal_Rela int_reloc1[3];
+  Elf_Internal_Rela int_reloc2[3];
+
+  (*get_elf_backend_data (reldyn_sorting_bfd)->s->swap_reloc_in)
+    (reldyn_sorting_bfd, arg1, int_reloc1);
+  (*get_elf_backend_data (reldyn_sorting_bfd)->s->swap_reloc_in)
+    (reldyn_sorting_bfd, arg2, int_reloc2);
+
+  return (ELF64_R_SYM (int_reloc1[0].r_info)
+         - ELF64_R_SYM (int_reloc2[0].r_info));
+}
+
+
 /* This routine is used to write out ECOFF debugging external symbol
    information.  It is called via mips_elf_link_hash_traverse.  The
    ECOFF external symbol information must match the ELF external
@@ -1417,17 +1559,36 @@ gptab_compare (p1, p2)
 }
 \f
 /* Functions to manage the got entry hash table.  */
+
+/* Use all 64 bits of a bfd_vma for the computation of a 32-bit
+   hash number.  */
+
+static INLINE hashval_t
+mips_elf_hash_bfd_vma (addr)
+     bfd_vma addr;
+{
+#ifdef BFD64
+  return addr + (addr >> 32);
+#else
+  return addr;
+#endif
+}
+
+/* got_entries only match if they're identical, except for gotidx, so
+   use all fields to compute the hash, and compare the appropriate
+   union members.  */
+
 static hashval_t
 mips_elf_got_entry_hash (entry_)
      const PTR entry_;
 {
   const struct mips_got_entry *entry = (struct mips_got_entry *)entry_;
 
-  return htab_hash_pointer (entry->abfd) + entry->symndx
-#ifdef BFD64
-    + (entry->addend >> 32)
-#endif
-    + entry->addend;
+  return entry->symndx
+    + (! entry->abfd ? mips_elf_hash_bfd_vma (entry->d.address)
+       : entry->abfd->id
+         + (entry->symndx >= 0 ? mips_elf_hash_bfd_vma (entry->d.addend)
+           : entry->d.h->root.root.root.hash));
 }
 
 static int
@@ -1439,16 +1600,87 @@ mips_elf_got_entry_eq (entry1, entry2)
   const struct mips_got_entry *e2 = (struct mips_got_entry *)entry2;
 
   return e1->abfd == e2->abfd && e1->symndx == e2->symndx
-    && e1->addend == e2->addend;
+    && (! e1->abfd ? e1->d.address == e2->d.address
+       : e1->symndx >= 0 ? e1->d.addend == e2->d.addend
+       : e1->d.h == e2->d.h);
+}
+
+/* multi_got_entries are still a match in the case of global objects,
+   even if the input bfd in which they're referenced differs, so the
+   hash computation and compare functions are adjusted
+   accordingly.  */
+
+static hashval_t
+mips_elf_multi_got_entry_hash (entry_)
+     const PTR entry_;
+{
+  const struct mips_got_entry *entry = (struct mips_got_entry *)entry_;
+
+  return entry->symndx
+    + (! entry->abfd
+       ? mips_elf_hash_bfd_vma (entry->d.address)
+       : entry->symndx >= 0
+       ? (entry->abfd->id
+         + mips_elf_hash_bfd_vma (entry->d.addend))
+       : entry->d.h->root.root.root.hash);
+}
+
+static int
+mips_elf_multi_got_entry_eq (entry1, entry2)
+     const PTR entry1;
+     const PTR entry2;
+{
+  const struct mips_got_entry *e1 = (struct mips_got_entry *)entry1;
+  const struct mips_got_entry *e2 = (struct mips_got_entry *)entry2;
+
+  return e1->symndx == e2->symndx
+    && (e1->symndx >= 0 ? e1->abfd == e2->abfd && e1->d.addend == e2->d.addend
+       : e1->abfd == NULL || e2->abfd == NULL
+       ? e1->abfd == e2->abfd && e1->d.address == e2->d.address
+       : e1->d.h == e2->d.h);
 }
 \f
+/* Returns the dynamic relocation section for DYNOBJ.  */
+
+static asection *
+mips_elf_rel_dyn_section (dynobj, create_p)
+     bfd *dynobj;
+     bfd_boolean create_p;
+{
+  static const char dname[] = ".rel.dyn";
+  asection *sreloc;
+
+  sreloc = bfd_get_section_by_name (dynobj, dname);
+  if (sreloc == NULL && create_p)
+    {
+      sreloc = bfd_make_section (dynobj, dname);
+      if (sreloc == NULL
+         || ! bfd_set_section_flags (dynobj, sreloc,
+                                     (SEC_ALLOC
+                                      | SEC_LOAD
+                                      | SEC_HAS_CONTENTS
+                                      | SEC_IN_MEMORY
+                                      | SEC_LINKER_CREATED
+                                      | SEC_READONLY))
+         || ! bfd_set_section_alignment (dynobj, sreloc,
+                                         MIPS_ELF_LOG_FILE_ALIGN (dynobj)))
+       return NULL;
+    }
+  return sreloc;
+}
+
 /* Returns the GOT section for ABFD.  */
 
 static asection *
-mips_elf_got_section (abfd)
+mips_elf_got_section (abfd, maybe_excluded)
      bfd *abfd;
+     bfd_boolean maybe_excluded;
 {
-  return bfd_get_section_by_name (abfd, ".got");
+  asection *sgot = bfd_get_section_by_name (abfd, ".got");
+  if (sgot == NULL
+      || (! maybe_excluded && (sgot->flags & SEC_EXCLUDE) != 0))
+    return NULL;
+  return sgot;
 }
 
 /* Returns the GOT information associated with the link indicated by
@@ -1463,24 +1695,48 @@ mips_elf_got_info (abfd, sgotp)
   asection *sgot;
   struct mips_got_info *g;
 
-  sgot = mips_elf_got_section (abfd);
+  sgot = mips_elf_got_section (abfd, TRUE);
   BFD_ASSERT (sgot != NULL);
-  BFD_ASSERT (elf_section_data (sgot) != NULL);
-  g = (struct mips_got_info *) elf_section_data (sgot)->tdata;
+  BFD_ASSERT (mips_elf_section_data (sgot) != NULL);
+  g = mips_elf_section_data (sgot)->u.got_info;
   BFD_ASSERT (g != NULL);
 
   if (sgotp)
-    *sgotp = sgot;
+    *sgotp = (sgot->flags & SEC_EXCLUDE) == 0 ? sgot : NULL;
+
   return g;
 }
 
+/* Obtain the lowest dynamic index of a symbol that was assigned a
+   global GOT entry.  */
+static long
+mips_elf_get_global_gotsym_index (abfd)
+     bfd *abfd;
+{
+  asection *sgot;
+  struct mips_got_info *g;
+
+  if (abfd == NULL)
+    return 0;
+
+  sgot = mips_elf_got_section (abfd, TRUE);
+  if (sgot == NULL || mips_elf_section_data (sgot) == NULL)
+    return 0;
+
+  g = mips_elf_section_data (sgot)->u.got_info;
+  if (g == NULL || g->global_gotsym == NULL)
+    return 0;
+
+  return g->global_gotsym->dynindx;
+}
+
 /* Returns the GOT offset at which the indicated address can be found.
    If there is not yet a GOT entry for this value, create one.  Returns
    -1 if no satisfactory GOT offset can be found.  */
 
 static bfd_vma
-mips_elf_local_got_index (abfd, info, value)
-     bfd *abfd;
+mips_elf_local_got_index (abfd, ibfd, info, value)
+     bfd *abfd, *ibfd;
      struct bfd_link_info *info;
      bfd_vma value;
 {
@@ -1490,7 +1746,7 @@ mips_elf_local_got_index (abfd, info, value)
 
   g = mips_elf_got_info (elf_hash_table (info)->dynobj, &sgot);
 
-  entry = mips_elf_create_local_got_entry (abfd, g, sgot, value);
+  entry = mips_elf_create_local_got_entry (abfd, ibfd, g, sgot, value);
   if (entry)
     return entry->gotidx;
   else
@@ -1500,18 +1756,38 @@ mips_elf_local_got_index (abfd, info, value)
 /* Returns the GOT index for the global symbol indicated by H.  */
 
 static bfd_vma
-mips_elf_global_got_index (abfd, h)
-     bfd *abfd;
+mips_elf_global_got_index (abfd, ibfd, h)
+     bfd *abfd, *ibfd;
      struct elf_link_hash_entry *h;
 {
   bfd_vma index;
   asection *sgot;
-  struct mips_got_info *g;
+  struct mips_got_info *g, *gg;
   long global_got_dynindx = 0;
 
-  g = mips_elf_got_info (abfd, &sgot);
-  if (g->global_gotsym != NULL)
-    global_got_dynindx = g->global_gotsym->dynindx;
+  gg = g = mips_elf_got_info (abfd, &sgot);
+  if (g->bfd2got && ibfd)
+    {
+      struct mips_got_entry e, *p;
+
+      BFD_ASSERT (h->dynindx >= 0);
+
+      g = mips_elf_got_for_ibfd (g, ibfd);
+      if (g->next != gg)
+       {
+         e.abfd = ibfd;
+         e.symndx = -1;
+         e.d.h = (struct mips_elf_link_hash_entry *)h;
+
+         p = (struct mips_got_entry *) htab_find (g->got_entries, &e);
+
+         BFD_ASSERT (p->gotidx > 0);
+         return p->gotidx;
+       }
+    }
+
+  if (gg->global_gotsym != NULL)
+    global_got_dynindx = gg->global_gotsym->dynindx;
 
   /* Once we determine the global GOT entry with the lowest dynamic
      symbol table index, we must put all dynamic symbols with greater
@@ -1532,8 +1808,8 @@ mips_elf_global_got_index (abfd, h)
    OFFSETP, if it is non-NULL.  */
 
 static bfd_vma
-mips_elf_got_page (abfd, info, value, offsetp)
-     bfd *abfd;
+mips_elf_got_page (abfd, ibfd, info, value, offsetp)
+     bfd *abfd, *ibfd;
      struct bfd_link_info *info;
      bfd_vma value;
      bfd_vma *offsetp;
@@ -1545,17 +1821,17 @@ mips_elf_got_page (abfd, info, value, offsetp)
 
   g = mips_elf_got_info (elf_hash_table (info)->dynobj, &sgot);
 
-  entry = mips_elf_create_local_got_entry (abfd, g, sgot,
+  entry = mips_elf_create_local_got_entry (abfd, ibfd, g, sgot,
                                           (value + 0x8000)
                                           & (~(bfd_vma)0xffff));
 
   if (!entry)
     return MINUS_ONE;
-  
+
   index = entry->gotidx;
 
   if (offsetp)
-    *offsetp = value - entry->addend;
+    *offsetp = value - entry->d.address;
 
   return index;
 }
@@ -1564,8 +1840,8 @@ mips_elf_got_page (abfd, info, value, offsetp)
    for value.  Return the index into the GOT for this entry.  */
 
 static bfd_vma
-mips_elf_got16_entry (abfd, info, value, external)
-     bfd *abfd;
+mips_elf_got16_entry (abfd, ibfd, info, value, external)
+     bfd *abfd, *ibfd;
      struct bfd_link_info *info;
      bfd_vma value;
      bfd_boolean external;
@@ -1585,7 +1861,7 @@ mips_elf_got16_entry (abfd, info, value, external)
 
   g = mips_elf_got_info (elf_hash_table (info)->dynobj, &sgot);
 
-  entry = mips_elf_create_local_got_entry (abfd, g, sgot, value);
+  entry = mips_elf_create_local_got_entry (abfd, ibfd, g, sgot, value);
   if (entry)
     return entry->gotidx;
   else
@@ -1596,53 +1872,64 @@ mips_elf_got16_entry (abfd, info, value, external)
    in the GOT.  */
 
 static bfd_vma
-mips_elf_got_offset_from_index (dynobj, output_bfd, index)
+mips_elf_got_offset_from_index (dynobj, output_bfd, input_bfd, index)
      bfd *dynobj;
      bfd *output_bfd;
+     bfd *input_bfd;
      bfd_vma index;
 {
   asection *sgot;
   bfd_vma gp;
+  struct mips_got_info *g;
+
+  g = mips_elf_got_info (dynobj, &sgot);
+  gp = _bfd_get_gp_value (output_bfd)
+    + mips_elf_adjust_gp (output_bfd, g, input_bfd);
 
-  sgot = mips_elf_got_section (dynobj);
-  gp = _bfd_get_gp_value (output_bfd);
-  return (sgot->output_section->vma + sgot->output_offset + index -
-         gp);
+  return sgot->output_section->vma + sgot->output_offset + index - gp;
 }
 
 /* Create a local GOT entry for VALUE.  Return the index of the entry,
    or -1 if it could not be created.  */
 
 static struct mips_got_entry *
-mips_elf_create_local_got_entry (abfd, g, sgot, value)
-     bfd *abfd;
-     struct mips_got_info *g;
+mips_elf_create_local_got_entry (abfd, ibfd, gg, sgot, value)
+     bfd *abfd, *ibfd;
+     struct mips_got_info *gg;
      asection *sgot;
      bfd_vma value;
 {
   struct mips_got_entry entry, **loc;
+  struct mips_got_info *g;
 
-  entry.abfd = abfd;
-  entry.symndx = (unsigned long)-1;
-  entry.addend = value;
+  entry.abfd = NULL;
+  entry.symndx = -1;
+  entry.d.address = value;
+
+  g = mips_elf_got_for_ibfd (gg, ibfd);
+  if (g == NULL)
+    {
+      g = mips_elf_got_for_ibfd (gg, abfd);
+      BFD_ASSERT (g != NULL);
+    }
 
   loc = (struct mips_got_entry **) htab_find_slot (g->got_entries, &entry,
                                                   INSERT);
   if (*loc)
     return *loc;
-      
+
   entry.gotidx = MIPS_ELF_GOT_SIZE (abfd) * g->assigned_gotno++;
 
   *loc = (struct mips_got_entry *)bfd_alloc (abfd, sizeof entry);
 
   if (! *loc)
     return NULL;
-             
+
   memcpy (*loc, &entry, sizeof entry);
 
   if (g->assigned_gotno >= g->local_gotno)
     {
-      (*loc)->gotidx = (unsigned long)-1;
+      (*loc)->gotidx = -1;
       /* We didn't allocate enough space in the GOT.  */
       (*_bfd_error_handler)
        (_("not enough GOT space for local GOT entries"));
@@ -1674,8 +1961,19 @@ mips_elf_sort_hash_table (info, max_local)
 
   dynobj = elf_hash_table (info)->dynobj;
 
+  g = mips_elf_got_info (dynobj, NULL);
+
   hsd.low = NULL;
-  hsd.min_got_dynindx = elf_hash_table (info)->dynsymcount;
+  hsd.max_unref_got_dynindx =
+  hsd.min_got_dynindx = elf_hash_table (info)->dynsymcount
+    /* In the multi-got case, assigned_gotno of the master got_info
+       indicate the number of entries that aren't referenced in the
+       primary GOT, but that must have entries because there are
+       dynamic relocations that reference it.  Since they aren't
+       referenced, we move them to the end of the GOT, so that they
+       don't prevent other entries that are referenced from getting
+       too large offsets.  */
+    - (g->next ? g->assigned_gotno : 0);
   hsd.max_non_got_dynindx = max_local;
   mips_elf_link_hash_traverse (((struct mips_elf_link_hash_table *)
                                elf_hash_table (info)),
@@ -1685,10 +1983,11 @@ mips_elf_sort_hash_table (info, max_local)
   /* There should have been enough room in the symbol table to
      accommodate both the GOT and non-GOT symbols.  */
   BFD_ASSERT (hsd.max_non_got_dynindx <= hsd.min_got_dynindx);
+  BFD_ASSERT ((unsigned long)hsd.max_unref_got_dynindx
+             <= elf_hash_table (info)->dynsymcount);
 
   /* Now we know which dynamic symbol has the lowest dynamic symbol
      table index in the GOT.  */
-  g = mips_elf_got_info (dynobj, NULL);
   g->global_gotsym = hsd.low;
 
   return TRUE;
@@ -1714,7 +2013,17 @@ mips_elf_sort_hash_table_f (h, data)
   if (h->root.dynindx == -1)
     return TRUE;
 
-  if (h->root.got.offset != 1)
+  /* Global symbols that need GOT entries that are not explicitly
+     referenced are marked with got offset 2.  Those that are
+     referenced get a 1, and those that don't need GOT entries get
+     -1.  */
+  if (h->root.got.offset == 2)
+    {
+      if (hsd->max_unref_got_dynindx == hsd->min_got_dynindx)
+       hsd->low = (struct elf_link_hash_entry *) h;
+      h->root.dynindx = hsd->max_unref_got_dynindx++;
+    }
+  else if (h->root.got.offset != 1)
     h->root.dynindx = hsd->max_non_got_dynindx++;
   else
     {
@@ -1730,11 +2039,14 @@ mips_elf_sort_hash_table_f (h, data)
    posterity.  */
 
 static bfd_boolean
-mips_elf_record_global_got_symbol (h, info, g)
+mips_elf_record_global_got_symbol (h, abfd, info, g)
      struct elf_link_hash_entry *h;
+     bfd *abfd;
      struct bfd_link_info *info;
-     struct mips_got_info *g ATTRIBUTE_UNUSED;
+     struct mips_got_info *g;
 {
+  struct mips_got_entry entry, **loc;
+
   /* A global symbol in the GOT must also be in the dynamic symbol
      table.  */
   if (h->dynindx == -1)
@@ -1750,8 +2062,26 @@ mips_elf_record_global_got_symbol (h, info, g)
        return FALSE;
     }
 
+  entry.abfd = abfd;
+  entry.symndx = -1;
+  entry.d.h = (struct mips_elf_link_hash_entry *) h;
+
+  loc = (struct mips_got_entry **) htab_find_slot (g->got_entries, &entry,
+                                                  INSERT);
+
   /* If we've already marked this entry as needing GOT space, we don't
      need to do it again.  */
+  if (*loc)
+    return TRUE;
+
+  *loc = (struct mips_got_entry *)bfd_alloc (abfd, sizeof entry);
+
+  if (! *loc)
+    return FALSE;
+
+  entry.gotidx = -1;
+  memcpy (*loc, &entry, sizeof entry);
+
   if (h->got.offset != MINUS_ONE)
     return TRUE;
 
@@ -1762,6 +2092,582 @@ mips_elf_record_global_got_symbol (h, info, g)
 
   return TRUE;
 }
+
+/* Reserve space in G for a GOT entry containing the value of symbol
+   SYMNDX in input bfd ABDF, plus ADDEND.  */
+
+static bfd_boolean
+mips_elf_record_local_got_symbol (abfd, symndx, addend, g)
+     bfd *abfd;
+     long symndx;
+     bfd_vma addend;
+     struct mips_got_info *g;
+{
+  struct mips_got_entry entry, **loc;
+
+  entry.abfd = abfd;
+  entry.symndx = symndx;
+  entry.d.addend = addend;
+  loc = (struct mips_got_entry **)
+    htab_find_slot (g->got_entries, &entry, INSERT);
+
+  if (*loc)
+    return TRUE;
+
+  entry.gotidx = g->local_gotno++;
+
+  *loc = (struct mips_got_entry *)bfd_alloc (abfd, sizeof entry);
+
+  if (! *loc)
+    return FALSE;
+
+  memcpy (*loc, &entry, sizeof entry);
+
+  return TRUE;
+}
+\f
+/* Compute the hash value of the bfd in a bfd2got hash entry.  */
+
+static hashval_t
+mips_elf_bfd2got_entry_hash (entry_)
+     const PTR entry_;
+{
+  const struct mips_elf_bfd2got_hash *entry
+    = (struct mips_elf_bfd2got_hash *)entry_;
+
+  return entry->bfd->id;
+}
+
+/* Check whether two hash entries have the same bfd.  */
+
+static int
+mips_elf_bfd2got_entry_eq (entry1, entry2)
+     const PTR entry1;
+     const PTR entry2;
+{
+  const struct mips_elf_bfd2got_hash *e1
+    = (const struct mips_elf_bfd2got_hash *)entry1;
+  const struct mips_elf_bfd2got_hash *e2
+    = (const struct mips_elf_bfd2got_hash *)entry2;
+
+  return e1->bfd == e2->bfd;
+}
+
+/* In a multi-got link, determine the GOT to be used for IBDF.  G must
+   be the master GOT data.  */
+
+static struct mips_got_info *
+mips_elf_got_for_ibfd (g, ibfd)
+     struct mips_got_info *g;
+     bfd *ibfd;
+{
+  struct mips_elf_bfd2got_hash e, *p;
+
+  if (! g->bfd2got)
+    return g;
+
+  e.bfd = ibfd;
+  p = (struct mips_elf_bfd2got_hash *) htab_find (g->bfd2got, &e);
+  return p ? p->g : NULL;
+}
+
+/* Create one separate got for each bfd that has entries in the global
+   got, such that we can tell how many local and global entries each
+   bfd requires.  */
+
+static int
+mips_elf_make_got_per_bfd (entryp, p)
+     void **entryp;
+     void *p;
+{
+  struct mips_got_entry *entry = (struct mips_got_entry *)*entryp;
+  struct mips_elf_got_per_bfd_arg *arg = (struct mips_elf_got_per_bfd_arg *)p;
+  htab_t bfd2got = arg->bfd2got;
+  struct mips_got_info *g;
+  struct mips_elf_bfd2got_hash bfdgot_entry, *bfdgot;
+  void **bfdgotp;
+
+  /* Find the got_info for this GOT entry's input bfd.  Create one if
+     none exists.  */
+  bfdgot_entry.bfd = entry->abfd;
+  bfdgotp = htab_find_slot (bfd2got, &bfdgot_entry, INSERT);
+  bfdgot = (struct mips_elf_bfd2got_hash *)*bfdgotp;
+
+  if (bfdgot != NULL)
+    g = bfdgot->g;
+  else
+    {
+      bfdgot = (struct mips_elf_bfd2got_hash *)bfd_alloc
+       (arg->obfd, sizeof (struct mips_elf_bfd2got_hash));
+
+      if (bfdgot == NULL)
+       {
+         arg->obfd = 0;
+         return 0;
+       }
+
+      *bfdgotp = bfdgot;
+
+      bfdgot->bfd = entry->abfd;
+      bfdgot->g = g = (struct mips_got_info *)
+       bfd_alloc (arg->obfd, sizeof (struct mips_got_info));
+      if (g == NULL)
+       {
+         arg->obfd = 0;
+         return 0;
+       }
+
+      g->global_gotsym = NULL;
+      g->global_gotno = 0;
+      g->local_gotno = 0;
+      g->assigned_gotno = -1;
+      g->got_entries = htab_try_create (1, mips_elf_multi_got_entry_hash,
+                                       mips_elf_multi_got_entry_eq,
+                                       (htab_del) NULL);
+      if (g->got_entries == NULL)
+       {
+         arg->obfd = 0;
+         return 0;
+       }
+
+      g->bfd2got = NULL;
+      g->next = NULL;
+    }
+
+  /* Insert the GOT entry in the bfd's got entry hash table.  */
+  entryp = htab_find_slot (g->got_entries, entry, INSERT);
+  if (*entryp != NULL)
+    return 1;
+
+  *entryp = entry;
+
+  if (entry->symndx >= 0 || entry->d.h->forced_local)
+    ++g->local_gotno;
+  else
+    ++g->global_gotno;
+
+  return 1;
+}
+
+/* Attempt to merge gots of different input bfds.  Try to use as much
+   as possible of the primary got, since it doesn't require explicit
+   dynamic relocations, but don't use bfds that would reference global
+   symbols out of the addressable range.  Failing the primary got,
+   attempt to merge with the current got, or finish the current got
+   and then make make the new got current.  */
+
+static int
+mips_elf_merge_gots (bfd2got_, p)
+     void **bfd2got_;
+     void *p;
+{
+  struct mips_elf_bfd2got_hash *bfd2got
+    = (struct mips_elf_bfd2got_hash *)*bfd2got_;
+  struct mips_elf_got_per_bfd_arg *arg = (struct mips_elf_got_per_bfd_arg *)p;
+  unsigned int lcount = bfd2got->g->local_gotno;
+  unsigned int gcount = bfd2got->g->global_gotno;
+  unsigned int maxcnt = arg->max_count;
+
+  /* If we don't have a primary GOT and this is not too big, use it as
+     a starting point for the primary GOT.  */
+  if (! arg->primary && lcount + gcount <= maxcnt)
+    {
+      arg->primary = bfd2got->g;
+      arg->primary_count = lcount + gcount;
+    }
+  /* If it looks like we can merge this bfd's entries with those of
+     the primary, merge them.  The heuristics is conservative, but we
+     don't have to squeeze it too hard.  */
+  else if (arg->primary
+          && (arg->primary_count + lcount + gcount) <= maxcnt)
+    {
+      struct mips_got_info *g = bfd2got->g;
+      int old_lcount = arg->primary->local_gotno;
+      int old_gcount = arg->primary->global_gotno;
+
+      bfd2got->g = arg->primary;
+
+      htab_traverse (g->got_entries,
+                    mips_elf_make_got_per_bfd,
+                    arg);
+      if (arg->obfd == NULL)
+       return 0;
+
+      htab_delete (g->got_entries);
+      /* We don't have to worry about releasing memory of the actual
+        got entries, since they're all in the master got_entries hash
+        table anyway.  */
+
+      BFD_ASSERT (old_lcount + lcount == arg->primary->local_gotno);
+      BFD_ASSERT (old_gcount + gcount >= arg->primary->global_gotno);
+
+      arg->primary_count = arg->primary->local_gotno
+       + arg->primary->global_gotno;
+    }
+  /* If we can merge with the last-created got, do it.  */
+  else if (arg->current
+          && arg->current_count + lcount + gcount <= maxcnt)
+    {
+      struct mips_got_info *g = bfd2got->g;
+      int old_lcount = arg->current->local_gotno;
+      int old_gcount = arg->current->global_gotno;
+
+      bfd2got->g = arg->current;
+
+      htab_traverse (g->got_entries,
+                    mips_elf_make_got_per_bfd,
+                    arg);
+      if (arg->obfd == NULL)
+       return 0;
+
+      htab_delete (g->got_entries);
+
+      BFD_ASSERT (old_lcount + lcount == arg->current->local_gotno);
+      BFD_ASSERT (old_gcount + gcount >= arg->current->global_gotno);
+
+      arg->current_count = arg->current->local_gotno
+       + arg->current->global_gotno;
+    }
+  /* Well, we couldn't merge, so create a new GOT.  Don't check if it
+     fits; if it turns out that it doesn't, we'll get relocation
+     overflows anyway.  */
+  else
+    {
+      bfd2got->g->next = arg->current;
+      arg->current = bfd2got->g;
+
+      arg->current_count = lcount + gcount;
+    }
+
+  return 1;
+}
+
+/* If passed a NULL mips_got_info in the argument, set the marker used
+   to tell whether a global symbol needs a got entry (in the primary
+   got) to the given VALUE.
+
+   If passed a pointer G to a mips_got_info in the argument (it must
+   not be the primary GOT), compute the offset from the beginning of
+   the (primary) GOT section to the entry in G corresponding to the
+   global symbol.  G's assigned_gotno must contain the index of the
+   first available global GOT entry in G.  VALUE must contain the size
+   of a GOT entry in bytes.  For each global GOT entry that requires a
+   dynamic relocation, NEEDED_RELOCS is incremented, and the symbol is
+   marked as not elligible for lazy resolution through a function
+   stub.  */
+static int
+mips_elf_set_global_got_offset (entryp, p)
+     void **entryp;
+     void *p;
+{
+  struct mips_got_entry *entry = (struct mips_got_entry *)*entryp;
+  struct mips_elf_set_global_got_offset_arg *arg
+    = (struct mips_elf_set_global_got_offset_arg *)p;
+  struct mips_got_info *g = arg->g;
+
+  if (entry->abfd != NULL && entry->symndx == -1
+      && entry->d.h->root.dynindx != -1)
+    {
+      if (g)
+       {
+         BFD_ASSERT (g->global_gotsym == NULL);
+
+         entry->gotidx = arg->value * (long) g->assigned_gotno++;
+         /* We can't do lazy update of GOT entries for
+            non-primary GOTs since the PLT entries don't use the
+            right offsets, so punt at it for now.  */
+         entry->d.h->no_fn_stub = TRUE;
+         if (arg->info->shared
+             || (elf_hash_table (arg->info)->dynamic_sections_created
+                 && ((entry->d.h->root.elf_link_hash_flags
+                      & ELF_LINK_HASH_DEF_DYNAMIC) != 0)
+                 && ((entry->d.h->root.elf_link_hash_flags
+                      & ELF_LINK_HASH_DEF_REGULAR) == 0)))
+           ++arg->needed_relocs;
+       }
+      else
+       entry->d.h->root.got.offset = arg->value;
+    }
+
+  return 1;
+}
+
+/* Follow indirect and warning hash entries so that each got entry
+   points to the final symbol definition.  P must point to a pointer
+   to the hash table we're traversing.  Since this traversal may
+   modify the hash table, we set this pointer to NULL to indicate
+   we've made a potentially-destructive change to the hash table, so
+   the traversal must be restarted.  */
+static int
+mips_elf_resolve_final_got_entry (entryp, p)
+     void **entryp;
+     void *p;
+{
+  struct mips_got_entry *entry = (struct mips_got_entry *)*entryp;
+  htab_t got_entries = *(htab_t *)p;
+
+  if (entry->abfd != NULL && entry->symndx == -1)
+    {
+      struct mips_elf_link_hash_entry *h = entry->d.h;
+
+      while (h->root.root.type == bfd_link_hash_indirect
+            || h->root.root.type == bfd_link_hash_warning)
+       h = (struct mips_elf_link_hash_entry *) h->root.root.u.i.link;
+
+      if (entry->d.h == h)
+       return 1;
+
+      entry->d.h = h;
+
+      /* If we can't find this entry with the new bfd hash, re-insert
+        it, and get the traversal restarted.  */
+      if (! htab_find (got_entries, entry))
+       {
+         htab_clear_slot (got_entries, entryp);
+         entryp = htab_find_slot (got_entries, entry, INSERT);
+         if (! *entryp)
+           *entryp = entry;
+         /* Abort the traversal, since the whole table may have
+            moved, and leave it up to the parent to restart the
+            process.  */
+         *(htab_t *)p = NULL;
+         return 0;
+       }
+      /* We might want to decrement the global_gotno count, but it's
+        either too early or too late for that at this point.  */
+    }
+
+  return 1;
+}
+
+/* Turn indirect got entries in a got_entries table into their final
+   locations.  */
+static void
+mips_elf_resolve_final_got_entries (g)
+     struct mips_got_info *g;
+{
+  htab_t got_entries;
+
+  do
+    {
+      got_entries = g->got_entries;
+
+      htab_traverse (got_entries,
+                    mips_elf_resolve_final_got_entry,
+                    &got_entries);
+    }
+  while (got_entries == NULL);
+}
+
+/* Return the offset of an input bfd IBFD's GOT from the beginning of
+   the primary GOT.  */
+static bfd_vma
+mips_elf_adjust_gp (abfd, g, ibfd)
+     bfd *abfd;
+     struct mips_got_info *g;
+     bfd *ibfd;
+{
+  if (g->bfd2got == NULL)
+    return 0;
+
+  g = mips_elf_got_for_ibfd (g, ibfd);
+  if (! g)
+    return 0;
+
+  BFD_ASSERT (g->next);
+
+  g = g->next;
+
+  return (g->local_gotno + g->global_gotno) * MIPS_ELF_GOT_SIZE (abfd);
+}
+
+/* Turn a single GOT that is too big for 16-bit addressing into
+   a sequence of GOTs, each one 16-bit addressable.  */
+
+static bfd_boolean
+mips_elf_multi_got (abfd, info, g, got, pages)
+     bfd *abfd;
+     struct bfd_link_info *info;
+     struct mips_got_info *g;
+     asection *got;
+     bfd_size_type pages;
+{
+  struct mips_elf_got_per_bfd_arg got_per_bfd_arg;
+  struct mips_elf_set_global_got_offset_arg set_got_offset_arg;
+  struct mips_got_info *gg;
+  unsigned int assign;
+
+  g->bfd2got = htab_try_create (1, mips_elf_bfd2got_entry_hash,
+                               mips_elf_bfd2got_entry_eq,
+                               (htab_del) NULL);
+  if (g->bfd2got == NULL)
+    return FALSE;
+
+  got_per_bfd_arg.bfd2got = g->bfd2got;
+  got_per_bfd_arg.obfd = abfd;
+  got_per_bfd_arg.info = info;
+
+  /* Count how many GOT entries each input bfd requires, creating a
+     map from bfd to got info while at that.  */
+  mips_elf_resolve_final_got_entries (g);
+  htab_traverse (g->got_entries, mips_elf_make_got_per_bfd, &got_per_bfd_arg);
+  if (got_per_bfd_arg.obfd == NULL)
+    return FALSE;
+
+  got_per_bfd_arg.current = NULL;
+  got_per_bfd_arg.primary = NULL;
+  /* Taking out PAGES entries is a worst-case estimate.  We could
+     compute the maximum number of pages that each separate input bfd
+     uses, but it's probably not worth it.  */
+  got_per_bfd_arg.max_count = ((MIPS_ELF_GOT_MAX_SIZE (abfd)
+                               / MIPS_ELF_GOT_SIZE (abfd))
+                              - MIPS_RESERVED_GOTNO - pages);
+
+  /* Try to merge the GOTs of input bfds together, as long as they
+     don't seem to exceed the maximum GOT size, choosing one of them
+     to be the primary GOT.  */
+  htab_traverse (g->bfd2got, mips_elf_merge_gots, &got_per_bfd_arg);
+  if (got_per_bfd_arg.obfd == NULL)
+    return FALSE;
+
+  /* If we find any suitable primary GOT, create an empty one.  */
+  if (got_per_bfd_arg.primary == NULL)
+    {
+      g->next = (struct mips_got_info *)
+       bfd_alloc (abfd, sizeof (struct mips_got_info));
+      if (g->next == NULL)
+       return FALSE;
+
+      g->next->global_gotsym = NULL;
+      g->next->global_gotno = 0;
+      g->next->local_gotno = 0;
+      g->next->assigned_gotno = 0;
+      g->next->got_entries = htab_try_create (1, mips_elf_multi_got_entry_hash,
+                                             mips_elf_multi_got_entry_eq,
+                                             (htab_del) NULL);
+      if (g->next->got_entries == NULL)
+       return FALSE;
+      g->next->bfd2got = NULL;
+    }
+  else
+    g->next = got_per_bfd_arg.primary;
+  g->next->next = got_per_bfd_arg.current;
+
+  /* GG is now the master GOT, and G is the primary GOT.  */
+  gg = g;
+  g = g->next;
+
+  /* Map the output bfd to the primary got.  That's what we're going
+     to use for bfds that use GOT16 or GOT_PAGE relocations that we
+     didn't mark in check_relocs, and we want a quick way to find it.
+     We can't just use gg->next because we're going to reverse the
+     list.  */
+  {
+    struct mips_elf_bfd2got_hash *bfdgot;
+    void **bfdgotp;
+
+    bfdgot = (struct mips_elf_bfd2got_hash *)bfd_alloc
+      (abfd, sizeof (struct mips_elf_bfd2got_hash));
+
+    if (bfdgot == NULL)
+      return FALSE;
+
+    bfdgot->bfd = abfd;
+    bfdgot->g = g;
+    bfdgotp = htab_find_slot (gg->bfd2got, bfdgot, INSERT);
+
+    BFD_ASSERT (*bfdgotp == NULL);
+    *bfdgotp = bfdgot;
+  }
+
+  /* The IRIX dynamic linker requires every symbol that is referenced
+     in a dynamic relocation to be present in the primary GOT, so
+     arrange for them to appear after those that are actually
+     referenced.
+
+     GNU/Linux could very well do without it, but it would slow down
+     the dynamic linker, since it would have to resolve every dynamic
+     symbol referenced in other GOTs more than once, without help from
+     the cache.  Also, knowing that every external symbol has a GOT
+     helps speed up the resolution of local symbols too, so GNU/Linux
+     follows IRIX's practice.
+
+     The number 2 is used by mips_elf_sort_hash_table_f to count
+     global GOT symbols that are unreferenced in the primary GOT, with
+     an initial dynamic index computed from gg->assigned_gotno, where
+     the number of unreferenced global entries in the primary GOT is
+     preserved.  */
+  if (1)
+    {
+      gg->assigned_gotno = gg->global_gotno - g->global_gotno;
+      g->global_gotno = gg->global_gotno;
+      set_got_offset_arg.value = 2;
+    }
+  else
+    {
+      /* This could be used for dynamic linkers that don't optimize
+        symbol resolution while applying relocations so as to use
+        primary GOT entries or assuming the symbol is locally-defined.
+        With this code, we assign lower dynamic indices to global
+        symbols that are not referenced in the primary GOT, so that
+        their entries can be omitted.  */
+      gg->assigned_gotno = 0;
+      set_got_offset_arg.value = -1;
+    }
+
+  /* Reorder dynamic symbols as described above (which behavior
+     depends on the setting of VALUE).  */
+  set_got_offset_arg.g = NULL;
+  htab_traverse (gg->got_entries, mips_elf_set_global_got_offset,
+                &set_got_offset_arg);
+  set_got_offset_arg.value = 1;
+  htab_traverse (g->got_entries, mips_elf_set_global_got_offset,
+                &set_got_offset_arg);
+  if (! mips_elf_sort_hash_table (info, 1))
+    return FALSE;
+
+  /* Now go through the GOTs assigning them offset ranges.
+     [assigned_gotno, local_gotno[ will be set to the range of local
+     entries in each GOT.  We can then compute the end of a GOT by
+     adding local_gotno to global_gotno.  We reverse the list and make
+     it circular since then we'll be able to quickly compute the
+     beginning of a GOT, by computing the end of its predecessor.  To
+     avoid special cases for the primary GOT, while still preserving
+     assertions that are valid for both single- and multi-got links,
+     we arrange for the main got struct to have the right number of
+     global entries, but set its local_gotno such that the initial
+     offset of the primary GOT is zero.  Remember that the primary GOT
+     will become the last item in the circular linked list, so it
+     points back to the master GOT.  */
+  gg->local_gotno = -g->global_gotno;
+  gg->global_gotno = g->global_gotno;
+  assign = 0;
+  gg->next = gg;
+
+  do
+    {
+      struct mips_got_info *gn;
+
+      assign += MIPS_RESERVED_GOTNO;
+      g->assigned_gotno = assign;
+      g->local_gotno += assign + pages;
+      assign = g->local_gotno + g->global_gotno;
+
+      /* Take g out of the direct list, and push it onto the reversed
+        list that gg points to.  */
+      gn = g->next;
+      g->next = gg->next;
+      gg->next = g;
+      g = gn;
+    }
+  while (g);
+
+  got->_raw_size = (gg->next->local_gotno
+                   + gg->next->global_gotno) * MIPS_ELF_GOT_SIZE (abfd);
+
+  return TRUE;
+}
+
 \f
 /* Returns the first relocation of type r_type found, beginning with
    RELOCATION.  RELEND is one-past-the-end of the relocation table.  */
@@ -1835,8 +2741,8 @@ mips_elf_local_relocation_p (input_bfd, relocation, local_sections,
 \f
 /* Sign-extend VALUE, which has the indicated number of BITS.  */
 
-static bfd_vma
-mips_elf_sign_extend (value, bits)
+bfd_vma
+_bfd_mips_elf_sign_extend (value, bits)
      bfd_vma value;
      int bits;
 {
@@ -1937,9 +2843,10 @@ mips_elf_create_compact_rel_section (abfd, info)
 /* Create the .got section to hold the global offset table.  */
 
 static bfd_boolean
-mips_elf_create_got_section (abfd, info)
+mips_elf_create_got_section (abfd, info, maybe_exclude)
      bfd *abfd;
      struct bfd_link_info *info;
+     bfd_boolean maybe_exclude;
 {
   flagword flags;
   register asection *s;
@@ -1949,16 +2856,24 @@ mips_elf_create_got_section (abfd, info)
   bfd_size_type amt;
 
   /* This function may be called more than once.  */
-  if (mips_elf_got_section (abfd))
-    return TRUE;
+  s = mips_elf_got_section (abfd, TRUE);
+  if (s)
+    {
+      if (! maybe_exclude)
+       s->flags &= ~SEC_EXCLUDE;
+      return TRUE;
+    }
 
   flags = (SEC_ALLOC | SEC_LOAD | SEC_HAS_CONTENTS | SEC_IN_MEMORY
           | SEC_LINKER_CREATED);
 
+  if (maybe_exclude)
+    flags |= SEC_EXCLUDE;
+
   s = bfd_make_section (abfd, ".got");
   if (s == NULL
       || ! bfd_set_section_flags (abfd, s, flags)
-      || ! bfd_set_section_alignment (abfd, s, 4))
+      || ! bfd_set_section_alignment (abfd, s, MIPS_ELF_LOG_FILE_ALIGN (abfd)))
     return FALSE;
 
   /* Define the symbol _GLOBAL_OFFSET_TABLE_.  We don't do this in the
@@ -1980,9 +2895,6 @@ mips_elf_create_got_section (abfd, info)
       && ! bfd_elf32_link_record_dynamic_symbol (info, h))
     return FALSE;
 
-  /* The first several global offset table entries are reserved.  */
-  s->_raw_size = MIPS_RESERVED_GOTNO * MIPS_ELF_GOT_SIZE (abfd);
-
   amt = sizeof (struct mips_got_info);
   g = (struct mips_got_info *) bfd_alloc (abfd, amt);
   if (g == NULL)
@@ -1990,20 +2902,15 @@ mips_elf_create_got_section (abfd, info)
   g->global_gotsym = NULL;
   g->local_gotno = MIPS_RESERVED_GOTNO;
   g->assigned_gotno = MIPS_RESERVED_GOTNO;
+  g->bfd2got = NULL;
+  g->next = NULL;
   g->got_entries = htab_try_create (1, mips_elf_got_entry_hash,
                                    mips_elf_got_entry_eq,
                                    (htab_del) NULL);
   if (g->got_entries == NULL)
     return FALSE;
-  if (elf_section_data (s) == NULL)
-    {
-      amt = sizeof (struct bfd_elf_section_data);
-      s->used_by_bfd = (PTR) bfd_zalloc (abfd, amt);
-      if (elf_section_data (s) == NULL)
-       return FALSE;
-    }
-  elf_section_data (s)->tdata = (PTR) g;
-  elf_section_data (s)->this_hdr.sh_flags
+  mips_elf_section_data (s)->u.got_info = g;
+  mips_elf_section_data (s)->elf.this_hdr.sh_flags
     |= SHF_ALLOC | SHF_WRITE | SHF_MIPS_GPREL;
 
   return TRUE;
@@ -2211,7 +3118,6 @@ mips_elf_calculate_relocation (abfd, input_bfd, input_section, info,
           addresses.  */
        symbol = 0;
       else if (info->shared
-              && (!info->symbolic || info->allow_shlib_undefined)
               && !info->no_undefined
               && ELF_ST_VISIBILITY (h->root.other) == STV_DEFAULT)
        symbol = 0;
@@ -2245,7 +3151,7 @@ mips_elf_calculate_relocation (abfd, input_bfd, input_section, info,
   /* If this is a 32- or 64-bit call to a 16-bit function with a stub, we
      need to redirect the call to the stub, unless we're already *in*
      a stub.  */
-  if (r_type != R_MIPS16_26 && !info->relocateable
+  if (r_type != R_MIPS16_26 && !info->relocatable
       && ((h != NULL && h->fn_stub != NULL)
          || (local_p && elf_tdata (input_bfd)->local_stubs != NULL
              && elf_tdata (input_bfd)->local_stubs[r_symndx] != NULL))
@@ -2266,7 +3172,7 @@ mips_elf_calculate_relocation (abfd, input_bfd, input_section, info,
     }
   /* If this is a 16-bit call to a 32- or 64-bit function with a stub, we
      need to redirect the call to the stub.  */
-  else if (r_type == R_MIPS16_26 && !info->relocateable
+  else if (r_type == R_MIPS16_26 && !info->relocatable
           && h != NULL
           && (h->call_stub != NULL || h->call_fp_stub != NULL)
           && !target_is_16_bit_code_p)
@@ -2302,7 +3208,7 @@ mips_elf_calculate_relocation (abfd, input_bfd, input_section, info,
 
   /* Calls from 16-bit code to 32-bit code and vice versa require the
      special jalx instruction.  */
-  *require_jalxp = (!info->relocateable
+  *require_jalxp = (!info->relocatable
                     && (((r_type == R_MIPS16_26) && !target_is_16_bit_code_p)
                         || ((r_type == R_MIPS_26) && target_is_16_bit_code_p)));
 
@@ -2313,6 +3219,18 @@ mips_elf_calculate_relocation (abfd, input_bfd, input_section, info,
      and we're going to need it, get it now.  */
   switch (r_type)
     {
+    case R_MIPS_GOT_PAGE:
+    case R_MIPS_GOT_OFST:
+      /* If this symbol got a global GOT entry, we have to decay
+        GOT_PAGE/GOT_OFST to GOT_DISP/addend.  */
+      local_p = local_p || ! h
+       || (h->root.dynindx
+           < mips_elf_get_global_gotsym_index (elf_hash_table (info)
+                                               ->dynobj));
+      if (local_p || r_type == R_MIPS_GOT_OFST)
+       break;
+      /* Fall through.  */
+
     case R_MIPS_CALL16:
     case R_MIPS_GOT16:
     case R_MIPS_GOT_DISP:
@@ -2323,8 +3241,13 @@ mips_elf_calculate_relocation (abfd, input_bfd, input_section, info,
       /* Find the index into the GOT where this value is located.  */
       if (!local_p)
        {
-         BFD_ASSERT (addend == 0);
+         /* GOT_PAGE may take a non-zero addend, that is ignored in a
+            GOT_PAGE relocation that decays to GOT_DISP because the
+            symbol turns out to be global.  The addend is then added
+            as GOT_OFST.  */
+         BFD_ASSERT (addend == 0 || r_type == R_MIPS_GOT_PAGE);
          g = mips_elf_global_got_index (elf_hash_table (info)->dynobj,
+                                        input_bfd,
                                         (struct elf_link_hash_entry *) h);
          if (! elf_hash_table(info)->dynamic_sections_created
              || (info->shared
@@ -2335,8 +3258,8 @@ mips_elf_calculate_relocation (abfd, input_bfd, input_section, info,
                 symbol is defined locally, or was forced to be local.
                 We must initialize this entry in the GOT.  */
              bfd *tmpbfd = elf_hash_table (info)->dynobj;
-             asection *sgot = mips_elf_got_section(tmpbfd);
-             MIPS_ELF_PUT_WORD (tmpbfd, symbol + addend, sgot->contents + g);
+             asection *sgot = mips_elf_got_section (tmpbfd, FALSE);
+             MIPS_ELF_PUT_WORD (tmpbfd, symbol, sgot->contents + g);
            }
        }
       else if (r_type == R_MIPS_GOT16 || r_type == R_MIPS_CALL16)
@@ -2345,14 +3268,15 @@ mips_elf_calculate_relocation (abfd, input_bfd, input_section, info,
        break;
       else
        {
-         g = mips_elf_local_got_index (abfd, info, symbol + addend);
+         g = mips_elf_local_got_index (abfd, input_bfd,
+                                       info, symbol + addend);
          if (g == MINUS_ONE)
            return bfd_reloc_outofrange;
        }
 
       /* Convert GOT indices to actual offsets.  */
       g = mips_elf_got_offset_from_index (elf_hash_table (info)->dynobj,
-                                         abfd, g);
+                                         abfd, input_bfd, g);
       break;
 
     case R_MIPS_HI16:
@@ -2363,6 +3287,11 @@ mips_elf_calculate_relocation (abfd, input_bfd, input_section, info,
     case R_MIPS_LITERAL:
       gp0 = _bfd_get_gp_value (input_bfd);
       gp = _bfd_get_gp_value (abfd);
+      if (elf_hash_table (info)->dynobj)
+       gp += mips_elf_adjust_gp (abfd,
+                                 mips_elf_got_info
+                                 (elf_hash_table (info)->dynobj, NULL),
+                                 input_bfd);
       break;
 
     default:
@@ -2376,7 +3305,7 @@ mips_elf_calculate_relocation (abfd, input_bfd, input_section, info,
       return bfd_reloc_continue;
 
     case R_MIPS_16:
-      value = symbol + mips_elf_sign_extend (addend, 16);
+      value = symbol + _bfd_mips_elf_sign_extend (addend, 16);
       overflowed_p = mips_elf_overflow_p (value, 16);
       break;
 
@@ -2427,7 +3356,7 @@ mips_elf_calculate_relocation (abfd, input_bfd, input_section, info,
       break;
 
     case R_MIPS_GNU_REL16_S2:
-      value = symbol + mips_elf_sign_extend (addend << 2, 18) - p;
+      value = symbol + _bfd_mips_elf_sign_extend (addend << 2, 18) - p;
       overflowed_p = mips_elf_overflow_p (value, 18);
       value = (value >> 2) & howto->dst_mask;
       break;
@@ -2452,7 +3381,7 @@ mips_elf_calculate_relocation (abfd, input_bfd, input_section, info,
       if (local_p)
        value = (((addend << 2) | ((p + 4) & 0xf0000000)) + symbol) >> 2;
       else
-       value = (mips_elf_sign_extend (addend << 2, 28) + symbol) >> 2;
+       value = (_bfd_mips_elf_sign_extend (addend << 2, 28) + symbol) >> 2;
       value &= howto->dst_mask;
       break;
 
@@ -2512,7 +3441,7 @@ mips_elf_calculate_relocation (abfd, input_bfd, input_section, info,
         instruction.  If the addend was separate, leave it alone,
         otherwise we may lose significant bits.  */
       if (howto->partial_inplace)
-       addend = mips_elf_sign_extend (addend, 16);
+       addend = _bfd_mips_elf_sign_extend (addend, 16);
       value = symbol + addend - gp;
       /* If the symbol was local, any earlier relocatable links will
         have adjusted its addend with the gp offset, so compensate
@@ -2535,12 +3464,13 @@ mips_elf_calculate_relocation (abfd, input_bfd, input_section, info,
             follows.  */
          forced = ! mips_elf_local_relocation_p (input_bfd, relocation,
                                                  local_sections, FALSE);
-         value = mips_elf_got16_entry (abfd, info, symbol + addend, forced);
+         value = mips_elf_got16_entry (abfd, input_bfd, info,
+                                       symbol + addend, forced);
          if (value == MINUS_ONE)
            return bfd_reloc_outofrange;
          value
            = mips_elf_got_offset_from_index (elf_hash_table (info)->dynobj,
-                                             abfd, value);
+                                             abfd, input_bfd, value);
          overflowed_p = mips_elf_overflow_p (value, 16);
          break;
        }
@@ -2548,6 +3478,7 @@ mips_elf_calculate_relocation (abfd, input_bfd, input_section, info,
       /* Fall through.  */
 
     case R_MIPS_GOT_DISP:
+    got_disp:
       value = g;
       overflowed_p = mips_elf_overflow_p (value, 16);
       break;
@@ -2559,7 +3490,7 @@ mips_elf_calculate_relocation (abfd, input_bfd, input_section, info,
       break;
 
     case R_MIPS_PC16:
-      value = mips_elf_sign_extend (addend, 16) + symbol - p;
+      value = _bfd_mips_elf_sign_extend (addend, 16) + symbol - p;
       overflowed_p = mips_elf_overflow_p (value, 16);
       break;
 
@@ -2579,16 +3510,24 @@ mips_elf_calculate_relocation (abfd, input_bfd, input_section, info,
       break;
 
     case R_MIPS_GOT_PAGE:
-      value = mips_elf_got_page (abfd, info, symbol + addend, NULL);
+      /* GOT_PAGE relocations that reference non-local symbols decay
+        to GOT_DISP.  The corresponding GOT_OFST relocation decays to
+        0.  */
+      if (! local_p)
+       goto got_disp;
+      value = mips_elf_got_page (abfd, input_bfd, info, symbol + addend, NULL);
       if (value == MINUS_ONE)
        return bfd_reloc_outofrange;
       value = mips_elf_got_offset_from_index (elf_hash_table (info)->dynobj,
-                                             abfd, value);
+                                             abfd, input_bfd, value);
       overflowed_p = mips_elf_overflow_p (value, 16);
       break;
 
     case R_MIPS_GOT_OFST:
-      mips_elf_got_page (abfd, info, symbol + addend, &value);
+      if (local_p)
+       mips_elf_got_page (abfd, input_bfd, info, symbol + addend, &value);
+      else
+       value = addend;
       overflowed_p = mips_elf_overflow_p (value, 16);
       break;
 
@@ -2711,7 +3650,7 @@ mips_elf_perform_relocation (info, howto, relocation, value, input_bfd,
         JALX is the 5-bit value 00011.  X is 0 for jal, 1 for jalx.
         Note that the immediate value in the first word is swapped.
 
-        When producing a relocateable object file, R_MIPS16_26 is
+        When producing a relocatable object file, R_MIPS16_26 is
         handled mostly like R_MIPS_26.  In particular, the addend is
         stored as a straight 26-bit value in a 32-bit instruction.
         (gas makes life simpler for itself by never adjusting a
@@ -2749,13 +3688,13 @@ mips_elf_perform_relocation (info, howto, relocation, value, input_bfd,
         where targ26-16 is sub1 followed by sub2 (i.e., the addend field A is
         ((sub1 << 16) | sub2)).
 
-        When producing a relocateable object file, the calculation is
+        When producing a relocatable object file, the calculation is
         (((A < 2) | ((P + 4) & 0xf0000000) + S) >> 2)
         When producing a fully linked file, the calculation is
         let R = (((A < 2) | ((P + 4) & 0xf0000000) + S) >> 2)
         ((R & 0x1f0000) << 5) | ((R & 0x3e00000) >> 5) | (R & 0xffff)  */
 
-      if (!info->relocateable)
+      if (!info->relocatable)
        /* Shuffle the bits according to the formula above.  */
        value = (((value & 0x1f0000) << 5)
                 | ((value & 0x3e00000) >> 5)
@@ -2859,7 +3798,7 @@ mips_elf_allocate_dynamic_relocations (abfd, n)
 {
   asection *s;
 
-  s = bfd_get_section_by_name (abfd, ".rel.dyn");
+  s = mips_elf_rel_dyn_section (abfd, FALSE);
   BFD_ASSERT (s != NULL);
 
   if (s->_raw_size == 0)
@@ -2896,7 +3835,7 @@ mips_elf_create_dynamic_relocation (output_bfd, info, rel, h, sec,
 
   r_type = ELF_R_TYPE (output_bfd, rel->r_info);
   dynobj = elf_hash_table (info)->dynobj;
-  sreloc = bfd_get_section_by_name (dynobj, ".rel.dyn");
+  sreloc = mips_elf_rel_dyn_section (dynobj, FALSE);
   BFD_ASSERT (sreloc != NULL);
   BFD_ASSERT (sreloc->contents != NULL);
   BFD_ASSERT (sreloc->reloc_count * MIPS_ELF_REL_SIZE (output_bfd)
@@ -2914,7 +3853,7 @@ mips_elf_create_dynamic_relocation (output_bfd, info, rel, h, sec,
   /* We begin by assuming that the offset for the dynamic relocation
      is the same as for the original relocation.  We'll adjust this
      later to reflect the correct output offsets.  */
-  if (elf_section_data (input_section)->sec_info_type != ELF_INFO_TYPE_STABS)
+  if (input_section->sec_info_type != ELF_INFO_TYPE_STABS)
     {
       outrel[1].r_offset = rel[1].r_offset;
       outrel[2].r_offset = rel[2].r_offset;
@@ -2934,11 +3873,9 @@ mips_elf_create_dynamic_relocation (output_bfd, info, rel, h, sec,
     }
 #endif
 
-  if (outrel[0].r_offset == (bfd_vma) -1)
+  if (outrel[0].r_offset == (bfd_vma) -1
+      || outrel[0].r_offset == (bfd_vma) -2)
     skip = TRUE;
-  /* FIXME: For -2 runtime relocation needs to be skipped, but
-     properly resolved statically and installed.  */
-  BFD_ASSERT (outrel[0].r_offset != (bfd_vma) -2);
 
   /* If we've decided to skip this relocation, just output an empty
      record.  Note that R_MIPS_NONE == 0, so that this call to memset
@@ -2948,7 +3885,6 @@ mips_elf_create_dynamic_relocation (output_bfd, info, rel, h, sec,
   else
     {
       long indx;
-      bfd_vma section_offset;
 
       /* We must now calculate the dynamic symbol table index to use
         in the relocation.  */
@@ -2978,15 +3914,18 @@ mips_elf_create_dynamic_relocation (output_bfd, info, rel, h, sec,
                abort ();
            }
 
-         /* Figure out how far the target of the relocation is from
-            the beginning of its section.  */
-         section_offset = symbol - sec->output_section->vma;
-         /* The relocation we're building is section-relative.
-            Therefore, the original addend must be adjusted by the
-            section offset.  */
-         *addendp += section_offset;
-         /* Now, the relocation is just against the section.  */
-         symbol = sec->output_section->vma;
+         /* Instead of generating a relocation using the section
+            symbol, we may as well make it a fully relative
+            relocation.  We want to avoid generating relocations to
+            local symbols because we used to generate them
+            incorrectly, without adding the original symbol value,
+            which is mandated by the ABI for section symbols.  In
+            order to give dynamic loaders and applications time to
+            phase out the incorrect use, we refrain from emitting
+            section-relative relocations.  It's not like they're
+            useful, after all.  This should be a bit more efficient
+            as well.  */
+         indx = 0;
        }
 
       /* If the relocation was previously an absolute relocation and
@@ -3000,6 +3939,18 @@ mips_elf_create_dynamic_relocation (output_bfd, info, rel, h, sec,
         know where the shared library will wind up at load-time.  */
       outrel[0].r_info = ELF_R_INFO (output_bfd, (unsigned long) indx,
                                     R_MIPS_REL32);
+      /* For strict adherence to the ABI specification, we should
+        generate a R_MIPS_64 relocation record by itself before the
+        _REL32/_64 record as well, such that the addend is read in as
+        a 64-bit value (REL32 is a 32-bit relocation, after all).
+        However, since none of the existing ELF64 MIPS dynamic
+        loaders seems to care, we don't waste space with these
+        artificial relocations.  If this turns out to not be true,
+        mips_elf_allocate_dynamic_relocation() should be tweaked so
+        as to make room for a pair of dynamic relocations per
+        invocation if ABI_64_P, and here we should generate an
+        additional relocation record with R_MIPS_64 by itself for a
+        NULL symbol before this relocation record.  */
       outrel[1].r_info = ELF_R_INFO (output_bfd, (unsigned long) 0,
                                     ABI_64_P (output_bfd)
                                     ? R_MIPS_64
@@ -3080,32 +4031,6 @@ mips_elf_create_dynamic_relocation (output_bfd, info, rel, h, sec,
   return TRUE;
 }
 \f
-/* Return the ISA for a MIPS e_flags value.  */
-
-static INLINE int
-elf_mips_isa (flags)
-     flagword flags;
-{
-  switch (flags & EF_MIPS_ARCH)
-    {
-    case E_MIPS_ARCH_1:
-      return 1;
-    case E_MIPS_ARCH_2:
-      return 2;
-    case E_MIPS_ARCH_3:
-      return 3;
-    case E_MIPS_ARCH_4:
-      return 4;
-    case E_MIPS_ARCH_5:
-      return 5;
-    case E_MIPS_ARCH_32:
-      return 32;
-    case E_MIPS_ARCH_64:
-      return 64;
-    }
-  return 4;
-}
-
 /* Return the MACH for a MIPS e_flags value.  */
 
 unsigned long
@@ -3172,6 +4097,10 @@ _bfd_elf_mips_mach (flags)
        case E_MIPS_ARCH_64:
          return bfd_mach_mipsisa64;
          break;
+
+       case E_MIPS_ARCH_32R2:
+         return bfd_mach_mipsisa32r2;
+         break;
        }
     }
 
@@ -3330,19 +4259,19 @@ _bfd_mips_elf_section_processing (abfd, hdr)
 
   if (hdr->sh_type == SHT_MIPS_OPTIONS
       && hdr->bfd_section != NULL
-      && elf_section_data (hdr->bfd_section) != NULL
-      && elf_section_data (hdr->bfd_section)->tdata != NULL)
+      && mips_elf_section_data (hdr->bfd_section) != NULL
+      && mips_elf_section_data (hdr->bfd_section)->u.tdata != NULL)
     {
       bfd_byte *contents, *l, *lend;
 
-      /* We stored the section contents in the elf_section_data tdata
-        field in the set_section_contents routine.  We save the
-        section contents so that we don't have to read them again.
+      /* We stored the section contents in the tdata field in the
+        set_section_contents routine.  We save the section contents
+        so that we don't have to read them again.
         At this point we know that elf_gp is set, so we can look
         through the section contents to see if there is an
         ODK_REGINFO structure.  */
 
-      contents = (bfd_byte *) elf_section_data (hdr->bfd_section)->tdata;
+      contents = mips_elf_section_data (hdr->bfd_section)->u.tdata;
       l = contents;
       lend = contents + hdr->sh_size;
       while (l + sizeof (Elf_External_Options) <= lend)
@@ -3732,8 +4661,7 @@ _bfd_mips_elf_fake_sections (abfd, hdr, sec)
       esd->rel_hdr2 = (Elf_Internal_Shdr *) bfd_zalloc (abfd, amt);
       if (!esd->rel_hdr2)
        return FALSE;
-      _bfd_elf_init_reloc_shdr (abfd, esd->rel_hdr2, sec,
-                               !elf_section_data (sec)->use_rela_p);
+      _bfd_elf_init_reloc_shdr (abfd, esd->rel_hdr2, sec, !sec->use_rela_p);
     }
 
   return TRUE;
@@ -3975,7 +4903,10 @@ _bfd_mips_elf_create_dynamic_sections (abfd, info)
     }
 
   /* We need to create .got section.  */
-  if (! mips_elf_create_got_section (abfd, info))
+  if (! mips_elf_create_got_section (abfd, info, FALSE))
+    return FALSE;
+
+  if (! mips_elf_rel_dyn_section (elf_hash_table (info)->dynobj, TRUE))
     return FALSE;
 
   /* Create the .msym section on IRIX6.  It is used by the dynamic
@@ -4043,19 +4974,19 @@ _bfd_mips_elf_create_dynamic_sections (abfd, info)
       /* Change alignments of some sections.  */
       s = bfd_get_section_by_name (abfd, ".hash");
       if (s != NULL)
-       bfd_set_section_alignment (abfd, s, 4);
+       bfd_set_section_alignment (abfd, s, MIPS_ELF_LOG_FILE_ALIGN (abfd));
       s = bfd_get_section_by_name (abfd, ".dynsym");
       if (s != NULL)
-       bfd_set_section_alignment (abfd, s, 4);
+       bfd_set_section_alignment (abfd, s, MIPS_ELF_LOG_FILE_ALIGN (abfd));
       s = bfd_get_section_by_name (abfd, ".dynstr");
       if (s != NULL)
-       bfd_set_section_alignment (abfd, s, 4);
+       bfd_set_section_alignment (abfd, s, MIPS_ELF_LOG_FILE_ALIGN (abfd));
       s = bfd_get_section_by_name (abfd, ".reginfo");
       if (s != NULL)
-       bfd_set_section_alignment (abfd, s, 4);
+       bfd_set_section_alignment (abfd, s, MIPS_ELF_LOG_FILE_ALIGN (abfd));
       s = bfd_get_section_by_name (abfd, ".dynamic");
       if (s != NULL)
-       bfd_set_section_alignment (abfd, s, 4);
+       bfd_set_section_alignment (abfd, s, MIPS_ELF_LOG_FILE_ALIGN (abfd));
     }
 
   if (!info->shared)
@@ -4130,7 +5061,7 @@ _bfd_mips_elf_check_relocs (abfd, info, sec, relocs)
   asection *sreloc;
   struct elf_backend_data *bed;
 
-  if (info->relocateable)
+  if (info->relocatable)
     return TRUE;
 
   dynobj = elf_hash_table (info)->dynobj;
@@ -4174,10 +5105,10 @@ _bfd_mips_elf_check_relocs (abfd, info, sec, relocs)
                              sizeof CALL_FP_STUB - 1) == 0)
                continue;
 
-             sec_relocs = (MNAME(abfd,_bfd_elf,link_read_relocs)
-                           (abfd, o, (PTR) NULL,
-                            (Elf_Internal_Rela *) NULL,
-                            info->keep_memory));
+             sec_relocs
+               = _bfd_elf_link_read_relocs (abfd, o, (PTR) NULL,
+                                            (Elf_Internal_Rela *) NULL,
+                                            info->keep_memory);
              if (sec_relocs == NULL)
                return FALSE;
 
@@ -4304,13 +5235,13 @@ _bfd_mips_elf_check_relocs (abfd, info, sec, relocs)
     }
   else
     {
-      sgot = mips_elf_got_section (dynobj);
+      sgot = mips_elf_got_section (dynobj, FALSE);
       if (sgot == NULL)
        g = NULL;
       else
        {
-         BFD_ASSERT (elf_section_data (sgot) != NULL);
-         g = (struct mips_got_info *) elf_section_data (sgot)->tdata;
+         BFD_ASSERT (mips_elf_section_data (sgot) != NULL);
+         g = mips_elf_section_data (sgot)->u.got_info;
          BFD_ASSERT (g != NULL);
        }
     }
@@ -4365,7 +5296,7 @@ _bfd_mips_elf_check_relocs (abfd, info, sec, relocs)
            case R_MIPS_GOT_DISP:
              if (dynobj == NULL)
                elf_hash_table (info)->dynobj = dynobj = abfd;
-             if (! mips_elf_create_got_section (dynobj, info))
+             if (! mips_elf_create_got_section (dynobj, info, FALSE))
                return FALSE;
              g = mips_elf_got_info (dynobj, &sgot);
              break;
@@ -4388,8 +5319,6 @@ _bfd_mips_elf_check_relocs (abfd, info, sec, relocs)
                 || r_type == R_MIPS_GOT_LO16
                 || r_type == R_MIPS_GOT_DISP))
        {
-         struct mips_got_entry entry, **loc;
-
          /* We may need a local GOT entry for this relocation.  We
             don't count R_MIPS_GOT_PAGE because we can estimate the
             maximum number of pages needed by looking at the size of
@@ -4397,26 +5326,9 @@ _bfd_mips_elf_check_relocs (abfd, info, sec, relocs)
             R_MIPS_CALL16.  We don't count R_MIPS_GOT_HI16, or
             R_MIPS_CALL_HI16 because these are always followed by an
             R_MIPS_GOT_LO16 or R_MIPS_CALL_LO16.  */
-
-         entry.abfd = abfd;
-         entry.symndx = r_symndx;
-         entry.addend = rel->r_addend;
-         loc = (struct mips_got_entry **)
-           htab_find_slot (g->got_entries, &entry, INSERT);
-
-         if (*loc == NULL)
-           {
-             entry.gotidx = g->local_gotno++;
-
-             *loc = (struct mips_got_entry *)bfd_alloc (abfd, sizeof entry);
-
-             if (! *loc)
-               return FALSE;
-             
-             memcpy (*loc, &entry, sizeof entry);
-
-             sgot->_raw_size += MIPS_ELF_GOT_SIZE (dynobj);
-           }
+         if (! mips_elf_record_local_got_symbol (abfd, r_symndx,
+                                                 rel->r_addend, g))
+           return FALSE;
        }
 
       switch (r_type)
@@ -4437,7 +5349,7 @@ _bfd_mips_elf_check_relocs (abfd, info, sec, relocs)
          if (h != NULL)
            {
              /* This symbol requires a global offset table entry.  */
-             if (! mips_elf_record_global_got_symbol (h, info, g))
+             if (! mips_elf_record_global_got_symbol (h, abfd, info, g))
                return FALSE;
 
              /* We need a stub, not a plt entry for the undefined
@@ -4448,12 +5360,50 @@ _bfd_mips_elf_check_relocs (abfd, info, sec, relocs)
            }
          break;
 
+       case R_MIPS_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 == NULL)
+           break;
+         else
+           {
+             struct mips_elf_link_hash_entry *hmips =
+               (struct mips_elf_link_hash_entry *) h;
+
+             while (hmips->root.root.type == bfd_link_hash_indirect
+                    || hmips->root.root.type == bfd_link_hash_warning)
+               hmips = (struct mips_elf_link_hash_entry *)
+                 hmips->root.root.u.i.link;
+
+             if ((hmips->root.root.type == bfd_link_hash_defined
+                  || hmips->root.root.type == bfd_link_hash_defweak)
+                 && hmips->root.root.u.def.section
+                 && ! (info->shared && ! info->symbolic
+                       && ! (hmips->root.elf_link_hash_flags
+                             & ELF_LINK_FORCED_LOCAL))
+                 /* If we've encountered any other relocation
+                    referencing the symbol, we'll have marked it as
+                    dynamic, and, even though we might be able to get
+                    rid of the GOT entry should we know for sure all
+                    previous relocations were GOT_PAGE ones, at this
+                    point we can't tell, so just keep using the
+                    symbol as dynamic.  This is very important in the
+                    multi-got case, since we don't decide whether to
+                    decay GOT_PAGE to GOT_DISP on a per-GOT basis: if
+                    the symbol is dynamic, we'll need a GOT entry for
+                    every GOT in which the symbol is referenced with
+                    a GOT_PAGE relocation.  */
+                 && hmips->root.dynindx == -1)
+               break;
+           }
+         /* Fall through.  */
+
        case R_MIPS_GOT16:
        case R_MIPS_GOT_HI16:
        case R_MIPS_GOT_LO16:
        case R_MIPS_GOT_DISP:
          /* This symbol requires a global offset table entry.  */
-         if (h && ! mips_elf_record_global_got_symbol (h, info, g))
+         if (h && ! mips_elf_record_global_got_symbol (h, abfd, info, g))
            return FALSE;
          break;
 
@@ -4465,24 +5415,9 @@ _bfd_mips_elf_check_relocs (abfd, info, sec, relocs)
            {
              if (sreloc == NULL)
                {
-                 const char *dname = ".rel.dyn";
-
-                 sreloc = bfd_get_section_by_name (dynobj, dname);
+                 sreloc = mips_elf_rel_dyn_section (dynobj, TRUE);
                  if (sreloc == NULL)
-                   {
-                     sreloc = bfd_make_section (dynobj, dname);
-                     if (sreloc == NULL
-                         || ! bfd_set_section_flags (dynobj, sreloc,
-                                                     (SEC_ALLOC
-                                                      | SEC_LOAD
-                                                      | SEC_HAS_CONTENTS
-                                                      | SEC_IN_MEMORY
-                                                      | SEC_LINKER_CREATED
-                                                      | SEC_READONLY))
-                         || ! bfd_set_section_alignment (dynobj, sreloc,
-                                                         4))
-                       return FALSE;
-                   }
+                   return FALSE;
                }
 #define MIPS_READONLY_SECTION (SEC_ALLOC | SEC_LOAD | SEC_READONLY)
              if (info->shared)
@@ -4517,9 +5452,16 @@ _bfd_mips_elf_check_relocs (abfd, info, sec, relocs)
                 this symbol, a symbol must have a dynamic symbol
                 table index greater that DT_MIPS_GOTSYM if there are
                 dynamic relocations against it.  */
-             if (h != NULL
-                 && ! mips_elf_record_global_got_symbol (h, info, g))
-               return FALSE;
+             if (h != NULL)
+               {
+                 if (dynobj == NULL)
+                   elf_hash_table (info)->dynobj = dynobj = abfd;
+                 if (! mips_elf_create_got_section (dynobj, info, TRUE))
+                   return FALSE;
+                 g = mips_elf_got_info (dynobj, &sgot);
+                 if (! mips_elf_record_global_got_symbol (h, abfd, info, g))
+                   return FALSE;
+               }
            }
 
          if (SGI_COMPAT (abfd))
@@ -4595,6 +5537,185 @@ _bfd_mips_elf_check_relocs (abfd, info, sec, relocs)
   return TRUE;
 }
 \f
+bfd_boolean
+_bfd_mips_relax_section (abfd, sec, link_info, again)
+     bfd *abfd;
+     asection *sec;
+     struct bfd_link_info *link_info;
+     bfd_boolean *again;
+{
+  Elf_Internal_Rela *internal_relocs;
+  Elf_Internal_Rela *irel, *irelend;
+  Elf_Internal_Shdr *symtab_hdr;
+  bfd_byte *contents = NULL;
+  bfd_byte *free_contents = NULL;
+  size_t extsymoff;
+  bfd_boolean changed_contents = FALSE;
+  bfd_vma sec_start = sec->output_section->vma + sec->output_offset;
+  Elf_Internal_Sym *isymbuf = NULL;
+
+  /* We are not currently changing any sizes, so only one pass.  */
+  *again = FALSE;
+
+  if (link_info->relocatable)
+    return TRUE;
+
+  internal_relocs = _bfd_elf_link_read_relocs (abfd, sec, (PTR) NULL,
+                                              (Elf_Internal_Rela *) NULL,
+                                              link_info->keep_memory);
+  if (internal_relocs == NULL)
+    return TRUE;
+
+  irelend = internal_relocs + sec->reloc_count
+    * get_elf_backend_data (abfd)->s->int_rels_per_ext_rel;
+  symtab_hdr = &elf_tdata (abfd)->symtab_hdr;
+  extsymoff = (elf_bad_symtab (abfd)) ? 0 : symtab_hdr->sh_info;
+
+  for (irel = internal_relocs; irel < irelend; irel++)
+    {
+      bfd_vma symval;
+      bfd_signed_vma sym_offset;
+      unsigned int r_type;
+      unsigned long r_symndx;
+      asection *sym_sec;
+      unsigned long instruction;
+
+      /* Turn jalr into bgezal, and jr into beq, if they're marked
+        with a JALR relocation, that indicate where they jump to.
+        This saves some pipeline bubbles.  */
+      r_type = ELF_R_TYPE (abfd, irel->r_info);
+      if (r_type != R_MIPS_JALR)
+       continue;
+
+      r_symndx = ELF_R_SYM (abfd, irel->r_info);
+      /* Compute the address of the jump target.  */
+      if (r_symndx >= extsymoff)
+       {
+         struct mips_elf_link_hash_entry *h
+           = ((struct mips_elf_link_hash_entry *)
+              elf_sym_hashes (abfd) [r_symndx - extsymoff]);
+
+         while (h->root.root.type == bfd_link_hash_indirect
+                || h->root.root.type == bfd_link_hash_warning)
+           h = (struct mips_elf_link_hash_entry *) h->root.root.u.i.link;
+
+         /* If a symbol is undefined, or if it may be overridden,
+            skip it.  */
+         if (! ((h->root.root.type == bfd_link_hash_defined
+                 || h->root.root.type == bfd_link_hash_defweak)
+                && h->root.root.u.def.section)
+             || (link_info->shared && ! link_info->symbolic
+                 && ! (h->root.elf_link_hash_flags & ELF_LINK_FORCED_LOCAL)))
+           continue;
+
+         sym_sec = h->root.root.u.def.section;
+         if (sym_sec->output_section)
+           symval = (h->root.root.u.def.value
+                     + sym_sec->output_section->vma
+                     + sym_sec->output_offset);
+         else
+           symval = h->root.root.u.def.value;
+       }
+      else
+       {
+         Elf_Internal_Sym *isym;
+
+         /* Read this BFD's symbols if we haven't done so already.  */
+         if (isymbuf == NULL && symtab_hdr->sh_info != 0)
+           {
+             isymbuf = (Elf_Internal_Sym *) symtab_hdr->contents;
+             if (isymbuf == NULL)
+               isymbuf = bfd_elf_get_elf_syms (abfd, symtab_hdr,
+                                               symtab_hdr->sh_info, 0,
+                                               NULL, NULL, NULL);
+             if (isymbuf == NULL)
+               goto relax_return;
+           }
+
+         isym = isymbuf + r_symndx;
+         if (isym->st_shndx == SHN_UNDEF)
+           continue;
+         else if (isym->st_shndx == SHN_ABS)
+           sym_sec = bfd_abs_section_ptr;
+         else if (isym->st_shndx == SHN_COMMON)
+           sym_sec = bfd_com_section_ptr;
+         else
+           sym_sec
+             = bfd_section_from_elf_index (abfd, isym->st_shndx);
+         symval = isym->st_value
+           + sym_sec->output_section->vma
+           + sym_sec->output_offset;
+       }
+
+      /* Compute branch offset, from delay slot of the jump to the
+        branch target.  */
+      sym_offset = (symval + irel->r_addend)
+       - (sec_start + irel->r_offset + 4);
+
+      /* Branch offset must be properly aligned.  */
+      if ((sym_offset & 3) != 0)
+       continue;
+
+      sym_offset >>= 2;
+
+      /* Check that it's in range.  */
+      if (sym_offset < -0x8000 || sym_offset >= 0x8000)
+       continue;
+
+      /* Get the section contents if we haven't done so already.  */
+      if (contents == NULL)
+       {
+         /* Get cached copy if it exists.  */
+         if (elf_section_data (sec)->this_hdr.contents != NULL)
+           contents = elf_section_data (sec)->this_hdr.contents;
+         else
+           {
+             contents = (bfd_byte *) bfd_malloc (sec->_raw_size);
+             if (contents == NULL)
+               goto relax_return;
+
+             free_contents = contents;
+             if (! bfd_get_section_contents (abfd, sec, contents,
+                                             (file_ptr) 0, sec->_raw_size))
+               goto relax_return;
+           }
+       }
+
+      instruction = bfd_get_32 (abfd, contents + irel->r_offset);
+
+      /* If it was jalr <reg>, turn it into bgezal $zero, <target>.  */
+      if ((instruction & 0xfc1fffff) == 0x0000f809)
+       instruction = 0x04110000;
+      /* If it was jr <reg>, turn it into b <target>.  */
+      else if ((instruction & 0xfc1fffff) == 0x00000008)
+       instruction = 0x10000000;
+      else
+       continue;
+
+      instruction |= (sym_offset & 0xffff);
+      bfd_put_32 (abfd, instruction, contents + irel->r_offset);
+      changed_contents = TRUE;
+    }
+
+  if (contents != NULL
+      && elf_section_data (sec)->this_hdr.contents != contents)
+    {
+      if (!changed_contents && !link_info->keep_memory)
+        free (contents);
+      else
+        {
+          /* Cache the section contents for elf_link_input_bfd.  */
+          elf_section_data (sec)->this_hdr.contents = contents;
+        }
+    }
+  return TRUE;
+
+ relax_return:
+  if (free_contents != NULL)
+    free (free_contents);
+  return FALSE;
+}
+\f
 /* Adjust a symbol defined by a dynamic object and referenced by a
    regular object.  The current definition is in some section of the
    dynamic object, but we're not including those sections.  We have to
@@ -4627,7 +5748,7 @@ _bfd_mips_elf_adjust_dynamic_symbol (info, h)
      any R_MIPS_32 or R_MIPS_REL32 relocs against it into the output
      file.  */
   hmips = (struct mips_elf_link_hash_entry *) h;
-  if (! info->relocateable
+  if (! info->relocatable
       && hmips->possibly_dynamic_relocs != 0
       && (h->root.type == bfd_link_hash_defweak
          || (h->elf_link_hash_flags
@@ -4711,19 +5832,86 @@ _bfd_mips_elf_always_size_sections (output_bfd, info)
 {
   asection *ri;
 
+  bfd *dynobj;
+  asection *s;
+  struct mips_got_info *g;
+  int i;
+  bfd_size_type loadable_size = 0;
+  bfd_size_type local_gotno;
+  bfd *sub;
+
   /* The .reginfo section has a fixed size.  */
   ri = bfd_get_section_by_name (output_bfd, ".reginfo");
   if (ri != NULL)
     bfd_set_section_size (output_bfd, ri,
                          (bfd_size_type) sizeof (Elf32_External_RegInfo));
 
-  if (info->relocateable
-      || ! mips_elf_hash_table (info)->mips16_stubs_seen)
+  if (! (info->relocatable
+        || ! mips_elf_hash_table (info)->mips16_stubs_seen))
+    mips_elf_link_hash_traverse (mips_elf_hash_table (info),
+                                mips_elf_check_mips16_stubs,
+                                (PTR) NULL);
+
+  dynobj = elf_hash_table (info)->dynobj;
+  if (dynobj == NULL)
+    /* Relocatable links don't have it.  */
+    return TRUE;
+
+  g = mips_elf_got_info (dynobj, &s);
+  if (s == NULL)
     return TRUE;
 
-  mips_elf_link_hash_traverse (mips_elf_hash_table (info),
-                              mips_elf_check_mips16_stubs,
-                              (PTR) NULL);
+  /* Calculate the total loadable size of the output.  That
+     will give us the maximum number of GOT_PAGE entries
+     required.  */
+  for (sub = info->input_bfds; sub; sub = sub->link_next)
+    {
+      asection *subsection;
+
+      for (subsection = sub->sections;
+          subsection;
+          subsection = subsection->next)
+       {
+         if ((subsection->flags & SEC_ALLOC) == 0)
+           continue;
+         loadable_size += ((subsection->_raw_size + 0xf)
+                           &~ (bfd_size_type) 0xf);
+       }
+    }
+
+  /* There has to be a global GOT entry for every symbol with
+     a dynamic symbol table index of DT_MIPS_GOTSYM or
+     higher.  Therefore, it make sense to put those symbols
+     that need GOT entries at the end of the symbol table.  We
+     do that here.  */
+  if (! mips_elf_sort_hash_table (info, 1))
+    return FALSE;
+
+  if (g->global_gotsym != NULL)
+    i = elf_hash_table (info)->dynsymcount - g->global_gotsym->dynindx;
+  else
+    /* If there are no global symbols, or none requiring
+       relocations, then GLOBAL_GOTSYM will be NULL.  */
+    i = 0;
+
+  /* In the worst case, we'll get one stub per dynamic symbol, plus
+     one to account for the dummy entry at the end required by IRIX
+     rld.  */
+  loadable_size += MIPS_FUNCTION_STUB_SIZE * (i + 1);
+
+  /* Assume there are two loadable segments consisting of
+     contiguous sections.  Is 5 enough?  */
+  local_gotno = (loadable_size >> 16) + 5;
+
+  g->local_gotno += local_gotno;
+  s->_raw_size += g->local_gotno * MIPS_ELF_GOT_SIZE (output_bfd);
+
+  g->global_gotno = i;
+  s->_raw_size += i * MIPS_ELF_GOT_SIZE (output_bfd);
+
+  if (s->_raw_size > MIPS_ELF_GOT_MAX_SIZE (output_bfd)
+      && ! mips_elf_multi_got (output_bfd, info, g, s, local_gotno))
+    return FALSE;
 
   return TRUE;
 }
@@ -4738,7 +5926,6 @@ _bfd_mips_elf_size_dynamic_sections (output_bfd, info)
   bfd *dynobj;
   asection *s;
   bfd_boolean reltext;
-  struct mips_got_info *g = NULL;
 
   dynobj = elf_hash_table (info)->dynobj;
   BFD_ASSERT (dynobj != NULL);
@@ -4814,61 +6001,64 @@ _bfd_mips_elf_size_dynamic_sections (output_bfd, info)
                 to copy relocs into the output file.  */
              if (strcmp (name, ".rel.dyn") != 0)
                s->reloc_count = 0;
+
+             /* If combreloc is enabled, elf_link_sort_relocs() will
+                sort relocations, but in a different way than we do,
+                and before we're done creating relocations.  Also, it
+                will move them around between input sections'
+                relocation's contents, so our sorting would be
+                broken, so don't let it run.  */
+             info->combreloc = 0;
            }
        }
       else if (strncmp (name, ".got", 4) == 0)
        {
-         int i;
-         bfd_size_type loadable_size = 0;
-         bfd_size_type local_gotno;
-         bfd *sub;
-
-         BFD_ASSERT (elf_section_data (s) != NULL);
-         g = (struct mips_got_info *) elf_section_data (s)->tdata;
-         BFD_ASSERT (g != NULL);
-
-         /* Calculate the total loadable size of the output.  That
-            will give us the maximum number of GOT_PAGE entries
-            required.  */
-         for (sub = info->input_bfds; sub; sub = sub->link_next)
+         /* _bfd_mips_elf_always_size_sections() has already done
+            most of the work, but some symbols may have been mapped
+            to versions that we must now resolve in the got_entries
+            hash tables.  */
+         struct mips_got_info *gg = mips_elf_got_info (dynobj, NULL);
+         struct mips_got_info *g = gg;
+         struct mips_elf_set_global_got_offset_arg set_got_offset_arg;
+         unsigned int needed_relocs = 0;
+
+         if (gg->next)
            {
-             asection *subsection;
+             set_got_offset_arg.value = MIPS_ELF_GOT_SIZE (output_bfd);
+             set_got_offset_arg.info = info;
 
-             for (subsection = sub->sections;
-                  subsection;
-                  subsection = subsection->next)
+             mips_elf_resolve_final_got_entries (gg);
+             for (g = gg->next; g && g->next != gg; g = g->next)
                {
-                 if ((subsection->flags & SEC_ALLOC) == 0)
-                   continue;
-                 loadable_size += ((subsection->_raw_size + 0xf)
-                                   &~ (bfd_size_type) 0xf);
+                 unsigned int save_assign;
+
+                 mips_elf_resolve_final_got_entries (g);
+
+                 /* Assign offsets to global GOT entries.  */
+                 save_assign = g->assigned_gotno;
+                 g->assigned_gotno = g->local_gotno;
+                 set_got_offset_arg.g = g;
+                 set_got_offset_arg.needed_relocs = 0;
+                 htab_traverse (g->got_entries,
+                                mips_elf_set_global_got_offset,
+                                &set_got_offset_arg);
+                 needed_relocs += set_got_offset_arg.needed_relocs;
+                 BFD_ASSERT (g->assigned_gotno - g->local_gotno
+                             <= g->global_gotno);
+
+                 g->assigned_gotno = save_assign;
+                 if (info->shared)
+                   {
+                     needed_relocs += g->local_gotno - g->assigned_gotno;
+                     BFD_ASSERT (g->assigned_gotno == g->next->local_gotno
+                                 + g->next->global_gotno
+                                 + MIPS_RESERVED_GOTNO);
+                   }
                }
-           }
-         loadable_size += MIPS_FUNCTION_STUB_SIZE;
 
-         /* Assume there are two loadable segments consisting of
-            contiguous sections.  Is 5 enough?  */
-         local_gotno = (loadable_size >> 16) + 5;
-
-         g->local_gotno += local_gotno;
-         s->_raw_size += local_gotno * MIPS_ELF_GOT_SIZE (dynobj);
-
-         /* There has to be a global GOT entry for every symbol with
-            a dynamic symbol table index of DT_MIPS_GOTSYM or
-            higher.  Therefore, it make sense to put those symbols
-            that need GOT entries at the end of the symbol table.  We
-            do that here.  */
-         if (! mips_elf_sort_hash_table (info, 1))
-           return FALSE;
-
-         if (g->global_gotsym != NULL)
-           i = elf_hash_table (info)->dynsymcount - g->global_gotsym->dynindx;
-         else
-           /* If there are no global symbols, or none requiring
-              relocations, then GLOBAL_GOTSYM will be NULL.  */
-           i = 0;
-         g->global_gotno = i;
-         s->_raw_size += i * MIPS_ELF_GOT_SIZE (dynobj);
+             if (needed_relocs)
+               mips_elf_allocate_dynamic_relocations (dynobj, needed_relocs);
+           }
        }
       else if (strcmp (name, MIPS_ELF_STUB_SECTION_NAME (output_bfd)) == 0)
        {
@@ -4953,7 +6143,7 @@ _bfd_mips_elf_size_dynamic_sections (output_bfd, info)
       if (! MIPS_ELF_ADD_DYNAMIC_ENTRY (info, DT_PLTGOT, 0))
        return FALSE;
 
-      if (bfd_get_section_by_name (dynobj, ".rel.dyn"))
+      if (mips_elf_rel_dyn_section (dynobj, FALSE))
        {
          if (! MIPS_ELF_ADD_DYNAMIC_ENTRY (info, DT_REL, 0))
            return FALSE;
@@ -5163,7 +6353,7 @@ _bfd_mips_elf_relocate_section (output_bfd, info, input_bfd, input_section,
                                                input_bfd, contents);
                  l &= lo16_howto->src_mask;
                  l <<= lo16_howto->rightshift;
-                 l = mips_elf_sign_extend (l, 16);
+                 l = _bfd_mips_elf_sign_extend (l, 16);
 
                  addend <<= 16;
 
@@ -5194,7 +6384,7 @@ _bfd_mips_elf_relocate_section (output_bfd, info, input_bfd, input_section,
            addend = rel->r_addend;
        }
 
-      if (info->relocateable)
+      if (info->relocatable)
        {
          Elf_Internal_Sym *sym;
          unsigned long r_symndx;
@@ -5208,7 +6398,7 @@ _bfd_mips_elf_relocate_section (output_bfd, info, input_bfd, input_section,
             they're against a section symbol, in which case we need
             to adjust by the section offset, or unless they're GP
             relative in which case we need to adjust by the amount
-            that we're adjusting GP in this relocateable object.  */
+            that we're adjusting GP in this relocatable object.  */
 
          if (! mips_elf_local_relocation_p (input_bfd, rel, local_sections,
                                             FALSE))
@@ -5496,7 +6686,7 @@ _bfd_mips_elf_finish_dynamic_symbol (output_bfd, info, h, sym)
   bfd_vma gval;
   asection *sgot;
   asection *smsym;
-  struct mips_got_info *g;
+  struct mips_got_info *g, *gg;
   const char *name;
   struct mips_elf_link_hash_entry *mh;
 
@@ -5544,10 +6734,10 @@ _bfd_mips_elf_finish_dynamic_symbol (output_bfd, info, h, sym)
   BFD_ASSERT (h->dynindx != -1
              || (h->elf_link_hash_flags & ELF_LINK_FORCED_LOCAL) != 0);
 
-  sgot = mips_elf_got_section (dynobj);
+  sgot = mips_elf_got_section (dynobj, FALSE);
   BFD_ASSERT (sgot != NULL);
-  BFD_ASSERT (elf_section_data (sgot) != NULL);
-  g = (struct mips_got_info *) elf_section_data (sgot)->tdata;
+  BFD_ASSERT (mips_elf_section_data (sgot) != NULL);
+  g = mips_elf_section_data (sgot)->u.got_info;
   BFD_ASSERT (g != NULL);
 
   /* Run through the global symbol table, creating GOT entries for all
@@ -5568,15 +6758,69 @@ _bfd_mips_elf_finish_dynamic_symbol (output_bfd, info, h, sym)
             That's because such the functions are now no longer defined
             in a shared object.)  */
 
-         if (info->shared && h->root.type == bfd_link_hash_undefined)
+         if ((info->shared && h->root.type == bfd_link_hash_undefined)
+             || h->root.type == bfd_link_hash_undefweak)
            value = 0;
          else
            value = h->root.u.def.value;
        }
-      offset = mips_elf_global_got_index (dynobj, h);
+      offset = mips_elf_global_got_index (dynobj, output_bfd, h);
       MIPS_ELF_PUT_WORD (output_bfd, value, sgot->contents + offset);
     }
 
+  if (g->next && h->dynindx != -1)
+    {
+      struct mips_got_entry e, *p;
+      bfd_vma offset;
+      bfd_vma value;
+      Elf_Internal_Rela rel[3];
+      bfd_vma addend = 0;
+
+      gg = g;
+
+      e.abfd = output_bfd;
+      e.symndx = -1;
+      e.d.h = (struct mips_elf_link_hash_entry *)h;
+
+      if (info->shared
+         || h->root.type == bfd_link_hash_undefined
+         || h->root.type == bfd_link_hash_undefweak)
+       value = 0;
+      else if (sym->st_value)
+       value = sym->st_value;
+      else
+       value = h->root.u.def.value;
+
+      memset (rel, 0, sizeof (rel));
+      rel[0].r_info = ELF_R_INFO (output_bfd, 0, R_MIPS_REL32);
+
+      for (g = g->next; g->next != gg; g = g->next)
+       {
+         if (g->got_entries
+             && (p = (struct mips_got_entry *) htab_find (g->got_entries,
+                                                          &e)))
+           {
+             offset = p->gotidx;
+             rel[0].r_offset = rel[1].r_offset = rel[2].r_offset = offset;
+
+             MIPS_ELF_PUT_WORD (output_bfd, value, sgot->contents + offset);
+
+             if ((info->shared
+                  || (elf_hash_table (info)->dynamic_sections_created
+                      && p->d.h != NULL
+                      && ((p->d.h->root.elf_link_hash_flags
+                           & ELF_LINK_HASH_DEF_DYNAMIC) != 0)
+                      && ((p->d.h->root.elf_link_hash_flags
+                           & ELF_LINK_HASH_DEF_REGULAR) == 0)))
+                 && ! (mips_elf_create_dynamic_relocation
+                       (output_bfd, info, rel,
+                        e.d.h, NULL, value, &addend, sgot)))
+               return FALSE;
+             BFD_ASSERT (addend == 0);
+           }
+       }
+    }
+
   /* Create a .msym entry, if appropriate.  */
   smsym = bfd_get_section_by_name (dynobj, ".msym");
   if (smsym)
@@ -5683,19 +6927,21 @@ _bfd_mips_elf_finish_dynamic_sections (output_bfd, info)
   bfd *dynobj;
   asection *sdyn;
   asection *sgot;
-  struct mips_got_info *g;
+  struct mips_got_info *gg, *g;
 
   dynobj = elf_hash_table (info)->dynobj;
 
   sdyn = bfd_get_section_by_name (dynobj, ".dynamic");
 
-  sgot = bfd_get_section_by_name (dynobj, ".got");
+  sgot = mips_elf_got_section (dynobj, FALSE);
   if (sgot == NULL)
-    g = NULL;
+    gg = g = NULL;
   else
     {
-      BFD_ASSERT (elf_section_data (sgot) != NULL);
-      g = (struct mips_got_info *) elf_section_data (sgot)->tdata;
+      BFD_ASSERT (mips_elf_section_data (sgot) != NULL);
+      gg = mips_elf_section_data (sgot)->u.got_info;
+      BFD_ASSERT (gg != NULL);
+      g = mips_elf_got_for_ibfd (gg, output_bfd);
       BFD_ASSERT (g != NULL);
     }
 
@@ -5725,7 +6971,7 @@ _bfd_mips_elf_finish_dynamic_sections (output_bfd, info)
          switch (dyn.d_tag)
            {
            case DT_RELENT:
-             s = (bfd_get_section_by_name (dynobj, ".rel.dyn"));
+             s = mips_elf_rel_dyn_section (dynobj, FALSE);
              BFD_ASSERT (s != NULL);
              dyn.d_un.d_val = MIPS_ELF_REL_SIZE (dynobj);
              break;
@@ -5811,9 +7057,9 @@ _bfd_mips_elf_finish_dynamic_sections (output_bfd, info)
              break;
 
            case DT_MIPS_GOTSYM:
-             if (g->global_gotsym)
+             if (gg->global_gotsym)
                {
-                 dyn.d_un.d_val = g->global_gotsym->dynindx;
+                 dyn.d_un.d_val = gg->global_gotsym->dynindx;
                  break;
                }
              /* In case if we don't have global got symbols we default
@@ -5876,6 +7122,41 @@ _bfd_mips_elf_finish_dynamic_sections (output_bfd, info)
     elf_section_data (sgot->output_section)->this_hdr.sh_entsize
       = MIPS_ELF_GOT_SIZE (output_bfd);
 
+  /* Generate dynamic relocations for the non-primary gots.  */
+  if (gg != NULL && gg->next)
+    {
+      Elf_Internal_Rela rel[3];
+      bfd_vma addend = 0;
+
+      memset (rel, 0, sizeof (rel));
+      rel[0].r_info = ELF_R_INFO (output_bfd, 0, R_MIPS_REL32);
+
+      for (g = gg->next; g->next != gg; g = g->next)
+       {
+         bfd_vma index = g->next->local_gotno + g->next->global_gotno;
+
+         MIPS_ELF_PUT_WORD (output_bfd, (bfd_vma) 0, sgot->contents
+                            + index++ * MIPS_ELF_GOT_SIZE (output_bfd));
+         MIPS_ELF_PUT_WORD (output_bfd, (bfd_vma) 0x80000000, sgot->contents
+                            + index++ * MIPS_ELF_GOT_SIZE (output_bfd));
+
+         if (! info->shared)
+           continue;
+
+         while (index < g->assigned_gotno)
+           {
+             rel[0].r_offset = rel[1].r_offset = rel[2].r_offset
+               = index++ * MIPS_ELF_GOT_SIZE (output_bfd);
+             if (!(mips_elf_create_dynamic_relocation
+                   (output_bfd, info, rel, NULL,
+                    bfd_abs_section_ptr,
+                    0, &addend, sgot)))
+               return FALSE;
+             BFD_ASSERT (addend == 0);
+           }
+       }
+    }
+
   {
     asection *smsym;
     asection *s;
@@ -5938,43 +7219,35 @@ _bfd_mips_elf_finish_dynamic_sections (output_bfd, info)
 
     /* We need to sort the entries of the dynamic relocation section.  */
 
-    if (!ABI_64_P (output_bfd))
+    s = mips_elf_rel_dyn_section (dynobj, FALSE);
+
+    if (s != NULL
+       && s->_raw_size > (bfd_vma)2 * MIPS_ELF_REL_SIZE (output_bfd))
       {
-       asection *reldyn;
+       reldyn_sorting_bfd = output_bfd;
 
-       reldyn = bfd_get_section_by_name (dynobj, ".rel.dyn");
-       if (reldyn != NULL && reldyn->reloc_count > 2)
-         {
-           reldyn_sorting_bfd = output_bfd;
-           qsort ((Elf32_External_Rel *) reldyn->contents + 1,
-                  (size_t) reldyn->reloc_count - 1,
-                  sizeof (Elf32_External_Rel), sort_dynamic_relocs);
-         }
+       if (ABI_64_P (output_bfd))
+         qsort ((Elf64_External_Rel *) s->contents + 1,
+                (size_t) s->reloc_count - 1,
+                sizeof (Elf64_Mips_External_Rel), sort_dynamic_relocs_64);
+       else
+         qsort ((Elf32_External_Rel *) s->contents + 1,
+                (size_t) s->reloc_count - 1,
+                sizeof (Elf32_External_Rel), sort_dynamic_relocs);
       }
-
-    /* Clean up a first relocation in .rel.dyn.  */
-    s = bfd_get_section_by_name (dynobj, ".rel.dyn");
-    if (s != NULL && s->_raw_size > 0)
-      memset (s->contents, 0, MIPS_ELF_REL_SIZE (dynobj));
   }
 
   return TRUE;
 }
 
-/* The final processing done just before writing out a MIPS ELF object
-   file.  This gets the MIPS architecture right based on the machine
-   number.  This is used by both the 32-bit and the 64-bit ABI.  */
 
-void
-_bfd_mips_elf_final_write_processing (abfd, linker)
+/* Set ABFD's EF_MIPS_ARCH and EF_MIPS_MACH flags.  */
+
+static void
+mips_set_isa_flags (abfd)
      bfd *abfd;
-     bfd_boolean linker ATTRIBUTE_UNUSED;
 {
-  unsigned long val;
-  unsigned int i;
-  Elf_Internal_Shdr **hdrpp;
-  const char *name;
-  asection *sec;
+  flagword val;
 
   switch (bfd_get_mach (abfd))
     {
@@ -6047,11 +7320,38 @@ _bfd_mips_elf_final_write_processing (abfd, linker)
 
     case bfd_mach_mipsisa64:
       val = E_MIPS_ARCH_64;
-    }
+      break;
 
+    case bfd_mach_mipsisa32r2:
+      val = E_MIPS_ARCH_32R2;
+      break;
+    }
   elf_elfheader (abfd)->e_flags &= ~(EF_MIPS_ARCH | EF_MIPS_MACH);
   elf_elfheader (abfd)->e_flags |= val;
 
+}
+
+
+/* The final processing done just before writing out a MIPS ELF object
+   file.  This gets the MIPS architecture right based on the machine
+   number.  This is used by both the 32-bit and the 64-bit ABI.  */
+
+void
+_bfd_mips_elf_final_write_processing (abfd, linker)
+     bfd *abfd;
+     bfd_boolean linker ATTRIBUTE_UNUSED;
+{
+  unsigned int i;
+  Elf_Internal_Shdr **hdrpp;
+  const char *name;
+  asection *sec;
+
+  /* Keep the existing EF_MIPS_MACH and EF_MIPS_ARCH flags if the former
+     is nonzero.  This is for compatibility with old objects, which used
+     a combination of a 32-bit EF_MIPS_ARCH and a 64-bit EF_MIPS_MACH.  */
+  if ((elf_elfheader (abfd)->e_flags & EF_MIPS_MACH) == 0)
+    mips_set_isa_flags (abfd);
+
   /* Set the sh_info field for .gptab sections and other appropriate
      info for each special section.  */
   for (i = 1, hdrpp = elf_elfsections (abfd) + 1;
@@ -6499,17 +7799,63 @@ _bfd_mips_elf_hide_symbol (info, entry, force_local)
   h = (struct mips_elf_link_hash_entry *) entry;
   if (h->forced_local)
     return;
-  h->forced_local = TRUE;
+  h->forced_local = force_local;
 
   dynobj = elf_hash_table (info)->dynobj;
-  got = bfd_get_section_by_name (dynobj, ".got");
-  g = (struct mips_got_info *) elf_section_data (got)->tdata;
+  if (dynobj != NULL && force_local)
+    {
+      got = mips_elf_got_section (dynobj, FALSE);
+      g = mips_elf_section_data (got)->u.got_info;
 
-  _bfd_elf_link_hash_hide_symbol (info, &h->root, force_local);
+      if (g->next)
+       {
+         struct mips_got_entry e;
+         struct mips_got_info *gg = g;
+
+         /* Since we're turning what used to be a global symbol into a
+            local one, bump up the number of local entries of each GOT
+            that had an entry for it.  This will automatically decrease
+            the number of global entries, since global_gotno is actually
+            the upper limit of global entries.  */
+         e.abfd = dynobj;
+         e.symndx = -1;
+         e.d.h = h;
+
+         for (g = g->next; g != gg; g = g->next)
+           if (htab_find (g->got_entries, &e))
+             {
+               BFD_ASSERT (g->global_gotno > 0);
+               g->local_gotno++;
+               g->global_gotno--;
+             }
+
+         /* If this was a global symbol forced into the primary GOT, we
+            no longer need an entry for it.  We can't release the entry
+            at this point, but we must at least stop counting it as one
+            of the symbols that required a forced got entry.  */
+         if (h->root.got.offset == 2)
+           {
+             BFD_ASSERT (gg->assigned_gotno > 0);
+             gg->assigned_gotno--;
+           }
+       }
+      else if (g->global_gotno == 0 && g->global_gotsym == NULL)
+       /* If we haven't got through GOT allocation yet, just bump up the
+          number of local entries, as this symbol won't be counted as
+          global.  */
+       g->local_gotno++;
+      else if (h->root.got.offset == 1)
+       {
+         /* If we're past non-multi-GOT allocation and this symbol had
+            been marked for a global got entry, give it a local entry
+            instead.  */
+         BFD_ASSERT (g->global_gotno > 0);
+         g->local_gotno++;
+         g->global_gotno--;
+       }
+    }
 
-  /* FIXME: Do we allocate too much GOT space here?  */
-  g->local_gotno++;
-  got->_raw_size += MIPS_ELF_GOT_SIZE (dynobj);
+  _bfd_elf_link_hash_hide_symbol (info, &h->root, force_local);
 }
 \f
 #define PDR_SIZE 32
@@ -6540,10 +7886,9 @@ _bfd_mips_elf_discard_info (abfd, cookie, info)
   if (! tdata)
     return FALSE;
 
-  cookie->rels = (MNAME(abfd,_bfd_elf,link_read_relocs)
-                 (abfd, o, (PTR) NULL,
-                  (Elf_Internal_Rela *) NULL,
-                  info->keep_memory));
+  cookie->rels = _bfd_elf_link_read_relocs (abfd, o, (PTR) NULL,
+                                           (Elf_Internal_Rela *) NULL,
+                                           info->keep_memory);
   if (!cookie->rels)
     {
       free (tdata);
@@ -6553,7 +7898,7 @@ _bfd_mips_elf_discard_info (abfd, cookie, info)
   cookie->rel = cookie->rels;
   cookie->relend = cookie->rels + o->reloc_count;
 
-  for (i = 0, skip = 0; i < o->_raw_size; i ++)
+  for (i = 0, skip = 0; i < o->_raw_size / PDR_SIZE; i ++)
     {
       if (MNAME(abfd,_bfd_elf,reloc_symbol_deleted_p) (i * PDR_SIZE, cookie))
        {
@@ -6564,7 +7909,7 @@ _bfd_mips_elf_discard_info (abfd, cookie, info)
 
   if (skip != 0)
     {
-      elf_section_data (o)->tdata = tdata;
+      mips_elf_section_data (o)->u.tdata = tdata;
       o->_cooked_size = o->_raw_size - skip * PDR_SIZE;
       ret = TRUE;
     }
@@ -6598,7 +7943,7 @@ _bfd_mips_elf_write_section (output_bfd, sec, contents)
   if (strcmp (sec->name, ".pdr") != 0)
     return FALSE;
 
-  if (elf_section_data (sec)->tdata == NULL)
+  if (mips_elf_section_data (sec)->u.tdata == NULL)
     return FALSE;
 
   to = contents;
@@ -6607,7 +7952,7 @@ _bfd_mips_elf_write_section (output_bfd, sec, contents)
        from < end;
        from += PDR_SIZE, i++)
     {
-      if (((unsigned char *) elf_section_data (sec)->tdata)[i] == 1)
+      if ((mips_elf_section_data (sec)->u.tdata)[i] == 1)
        continue;
       if (to != from)
        memcpy (to, from, PDR_SIZE);
@@ -6757,7 +8102,7 @@ _bfd_mips_elf_set_section_contents (abfd, section, location, offset, count)
          if (elf_section_data (section) == NULL)
            return FALSE;
        }
-      c = (bfd_byte *) elf_section_data (section)->tdata;
+      c = mips_elf_section_data (section)->u.tdata;
       if (c == NULL)
        {
          bfd_size_type size;
@@ -6769,7 +8114,7 @@ _bfd_mips_elf_set_section_contents (abfd, section, location, offset, count)
          c = (bfd_byte *) bfd_zalloc (abfd, size);
          if (c == NULL)
            return FALSE;
-         elf_section_data (section)->tdata = (PTR) c;
+         mips_elf_section_data (section)->u.tdata = c;
        }
 
       memcpy (c + offset, location, (size_t) count);
@@ -6784,12 +8129,12 @@ _bfd_mips_elf_set_section_contents (abfd, section, location, offset, count)
 
 bfd_byte *
 _bfd_elf_mips_get_relocated_section_contents (abfd, link_info, link_order,
-                                             data, relocateable, symbols)
+                                             data, relocatable, symbols)
      bfd *abfd;
      struct bfd_link_info *link_info;
      struct bfd_link_order *link_order;
      bfd_byte *data;
-     bfd_boolean relocateable;
+     bfd_boolean relocatable;
      asymbol **symbols;
 {
   /* Get enough memory to hold the stuff */
@@ -6897,7 +8242,7 @@ _bfd_elf_mips_get_relocated_section_contents (abfd, link_info, link_order,
            {
              /* bypass special_function call */
              r = _bfd_mips_elf_gprel16_with_gp (input_bfd, sym, *parent,
-                                                input_section, relocateable,
+                                                input_section, relocatable,
                                                 (PTR) data, gp);
              goto skip_bfd_perform_relocation;
            }
@@ -6907,11 +8252,11 @@ _bfd_elf_mips_get_relocated_section_contents (abfd, link_info, link_order,
                                      *parent,
                                      (PTR) data,
                                      input_section,
-                                     relocateable ? abfd : (bfd *) NULL,
+                                     relocatable ? abfd : (bfd *) NULL,
                                      &error_message);
        skip_bfd_perform_relocation:
 
-         if (relocateable)
+         if (relocatable)
            {
              asection *os = input_section->output_section;
 
@@ -7034,17 +8379,6 @@ _bfd_mips_elf_final_link (abfd, info)
     scRData, scSData, scSBss, scBss
   };
 
-  /* If all the things we linked together were PIC, but we're
-     producing an executable (rather than a shared object), then the
-     resulting file is CPIC (i.e., it calls PIC code.)  */
-  if (!info->shared
-      && !info->relocateable
-      && elf_elfheader (abfd)->e_flags & EF_MIPS_PIC)
-    {
-      elf_elfheader (abfd)->e_flags &= ~EF_MIPS_PIC;
-      elf_elfheader (abfd)->e_flags |= EF_MIPS_CPIC;
-    }
-
   /* We'd carefully arranged the dynamic symbol indices, and then the
      generic size_dynamic_sections renumbered them out from under us.
      Rather than trying somehow to prevent the renumbering, just do
@@ -7068,8 +8402,8 @@ _bfd_mips_elf_final_link (abfd, info)
 
       /* Make sure we didn't grow the global .got region.  */
       dynobj = elf_hash_table (info)->dynobj;
-      got = bfd_get_section_by_name (dynobj, ".got");
-      g = (struct mips_got_info *) elf_section_data (got)->tdata;
+      got = mips_elf_got_section (dynobj, FALSE);
+      g = mips_elf_section_data (got)->u.got_info;
 
       if (g->global_gotsym != NULL)
        BFD_ASSERT ((elf_hash_table (info)->dynsymcount
@@ -7129,7 +8463,7 @@ _bfd_mips_elf_final_link (abfd, info)
        elf_gp (abfd) = (h->u.def.value
                         + h->u.def.section->output_section->vma
                         + h->u.def.section->output_offset);
-      else if (info->relocateable)
+      else if (info->relocatable)
        {
          bfd_vma lo = MINUS_ONE;
 
@@ -7450,7 +8784,7 @@ _bfd_mips_elf_final_link (abfd, info)
             information describing how the small data area would
             change depending upon the -G switch.  These sections
             not used in executables files.  */
-         if (! info->relocateable)
+         if (! info->relocatable)
            {
              for (p = o->link_order_head;
                   p != (struct bfd_link_order *) NULL;
@@ -7720,26 +9054,97 @@ _bfd_mips_elf_final_link (abfd, info)
   return TRUE;
 }
 \f
-/* Return TRUE if machine EXTENSION is an extension of machine BASE,
-   meaning that it should be safe to link code for the two machines
-   and set the output machine to EXTENSION.  EXTENSION and BASE are
-   both submasks of EF_MIPS_MACH.  */
+/* Structure for saying that BFD machine EXTENSION extends BASE.  */
+
+struct mips_mach_extension {
+  unsigned long extension, base;
+};
+
+
+/* An array describing how BFD machines relate to one another.  The entries
+   are ordered topologically with MIPS I extensions listed last.  */
+
+static const struct mips_mach_extension mips_mach_extensions[] = {
+  /* MIPS64 extensions.  */
+  { bfd_mach_mips_sb1, bfd_mach_mipsisa64 },
+
+  /* MIPS V extensions.  */
+  { bfd_mach_mipsisa64, bfd_mach_mips5 },
+
+  /* R10000 extensions.  */
+  { bfd_mach_mips12000, bfd_mach_mips10000 },
+
+  /* R5000 extensions.  Note: the vr5500 ISA is an extension of the core
+     vr5400 ISA, but doesn't include the multimedia stuff.  It seems
+     better to allow vr5400 and vr5500 code to be merged anyway, since
+     many libraries will just use the core ISA.  Perhaps we could add
+     some sort of ASE flag if this ever proves a problem.  */
+  { bfd_mach_mips5500, bfd_mach_mips5400 },
+  { bfd_mach_mips5400, bfd_mach_mips5000 },
+
+  /* MIPS IV extensions.  */
+  { bfd_mach_mips5, bfd_mach_mips8000 },
+  { bfd_mach_mips10000, bfd_mach_mips8000 },
+  { bfd_mach_mips5000, bfd_mach_mips8000 },
+
+  /* VR4100 extensions.  */
+  { bfd_mach_mips4120, bfd_mach_mips4100 },
+  { bfd_mach_mips4111, bfd_mach_mips4100 },
+
+  /* MIPS III extensions.  */
+  { bfd_mach_mips8000, bfd_mach_mips4000 },
+  { bfd_mach_mips4650, bfd_mach_mips4000 },
+  { bfd_mach_mips4600, bfd_mach_mips4000 },
+  { bfd_mach_mips4400, bfd_mach_mips4000 },
+  { bfd_mach_mips4300, bfd_mach_mips4000 },
+  { bfd_mach_mips4100, bfd_mach_mips4000 },
+  { bfd_mach_mips4010, bfd_mach_mips4000 },
+
+  /* MIPS32 extensions.  */
+  { bfd_mach_mipsisa32r2, bfd_mach_mipsisa32 },
+
+  /* MIPS II extensions.  */
+  { bfd_mach_mips4000, bfd_mach_mips6000 },
+  { bfd_mach_mipsisa32, bfd_mach_mips6000 },
+
+  /* MIPS I extensions.  */
+  { bfd_mach_mips6000, bfd_mach_mips3000 },
+  { bfd_mach_mips3900, bfd_mach_mips3000 }
+};
+
+
+/* Return true if bfd machine EXTENSION is an extension of machine BASE.  */
+
+static bfd_boolean
+mips_mach_extends_p (base, extension)
+     unsigned long base, extension;
+{
+  size_t i;
+
+  for (i = 0; extension != base && i < ARRAY_SIZE (mips_mach_extensions); i++)
+    if (extension == mips_mach_extensions[i].extension)
+      extension = mips_mach_extensions[i].base;
+
+  return extension == base;
+}
+
+
+/* Return true if the given ELF header flags describe a 32-bit binary.  */
 
 static bfd_boolean
-_bfd_mips_elf_mach_extends_p (base, extension)
-     flagword base, extension;
+mips_32bit_flags_p (flags)
+     flagword flags;
 {
-  /* The vr5500 ISA is an extension of the core vr5400 ISA, but doesn't
-     include the multimedia stuff.  It seems better to allow vr5400
-     and vr5500 code to be merged anyway, since many libraries will
-     just use the core ISA.  Perhaps we could add some sort of ASE
-     flag if this ever proves a problem.  */
-  return (base == 0
-         || (base == E_MIPS_MACH_5400 && extension == E_MIPS_MACH_5500)
-         || (base == E_MIPS_MACH_4100 && extension == E_MIPS_MACH_4111)
-         || (base == E_MIPS_MACH_4100 && extension == E_MIPS_MACH_4120));
+  return ((flags & EF_MIPS_32BITMODE) != 0
+         || (flags & EF_MIPS_ABI) == E_MIPS_ABI_O32
+         || (flags & EF_MIPS_ABI) == E_MIPS_ABI_EABI32
+         || (flags & EF_MIPS_ARCH) == E_MIPS_ARCH_1
+         || (flags & EF_MIPS_ARCH) == E_MIPS_ARCH_2
+         || (flags & EF_MIPS_ARCH) == E_MIPS_ARCH_32
+         || (flags & EF_MIPS_ARCH) == E_MIPS_ARCH_32R2);
 }
 
+
 /* Merge backend specific data from an object file to the output
    object file when linking.  */
 
@@ -7756,12 +9161,25 @@ _bfd_mips_elf_merge_private_bfd_data (ibfd, obfd)
 
   /* Check if we have the same endianess */
   if (! _bfd_generic_verify_endian_match (ibfd, obfd))
-    return FALSE;
+    {
+      (*_bfd_error_handler)
+       (_("%s: endianness incompatible with that of the selected emulation"),
+        bfd_archive_filename (ibfd));
+      return FALSE;
+    }
 
   if (bfd_get_flavour (ibfd) != bfd_target_elf_flavour
       || bfd_get_flavour (obfd) != bfd_target_elf_flavour)
     return TRUE;
 
+  if (strcmp (bfd_get_target (ibfd), bfd_get_target (obfd)) != 0)
+    {
+      (*_bfd_error_handler)
+       (_("%s: ABI is incompatible with that of the selected emulation"),
+        bfd_archive_filename (ibfd));
+      return FALSE;
+    }
+
   new_flags = elf_elfheader (ibfd)->e_flags;
   elf_elfheader (obfd)->e_flags |= new_flags & EF_MIPS_NOREORDER;
   old_flags = elf_elfheader (obfd)->e_flags;
@@ -7789,6 +9207,11 @@ _bfd_mips_elf_merge_private_bfd_data (ibfd, obfd)
   new_flags &= ~EF_MIPS_NOREORDER;
   old_flags &= ~EF_MIPS_NOREORDER;
 
+  /* Some IRIX 6 BSD-compatibility objects have this bit set.  It
+     doesn't seem to matter.  */
+  new_flags &= ~EF_MIPS_XGOT;
+  old_flags &= ~EF_MIPS_XGOT;
+
   if (new_flags == old_flags)
     return TRUE;
 
@@ -7815,86 +9238,67 @@ _bfd_mips_elf_merge_private_bfd_data (ibfd, obfd)
 
   ok = TRUE;
 
-  if ((new_flags & EF_MIPS_PIC) != (old_flags & EF_MIPS_PIC))
+  if (((new_flags & (EF_MIPS_PIC | EF_MIPS_CPIC)) != 0)
+      != ((old_flags & (EF_MIPS_PIC | EF_MIPS_CPIC)) != 0))
     {
-      new_flags &= ~EF_MIPS_PIC;
-      old_flags &= ~EF_MIPS_PIC;
       (*_bfd_error_handler)
-       (_("%s: linking PIC files with non-PIC files"),
+       (_("%s: warning: linking PIC files with non-PIC files"),
         bfd_archive_filename (ibfd));
-      ok = FALSE;
+      ok = TRUE;
     }
 
-  if ((new_flags & EF_MIPS_CPIC) != (old_flags & EF_MIPS_CPIC))
+  if (new_flags & (EF_MIPS_PIC | EF_MIPS_CPIC))
+    elf_elfheader (obfd)->e_flags |= EF_MIPS_CPIC;
+  if (! (new_flags & EF_MIPS_PIC))
+    elf_elfheader (obfd)->e_flags &= ~EF_MIPS_PIC;
+
+  new_flags &= ~ (EF_MIPS_PIC | EF_MIPS_CPIC);
+  old_flags &= ~ (EF_MIPS_PIC | EF_MIPS_CPIC);
+
+  /* Compare the ISAs.  */
+  if (mips_32bit_flags_p (old_flags) != mips_32bit_flags_p (new_flags))
     {
-      new_flags &= ~EF_MIPS_CPIC;
-      old_flags &= ~EF_MIPS_CPIC;
       (*_bfd_error_handler)
-       (_("%s: linking abicalls files with non-abicalls files"),
+       (_("%s: linking 32-bit code with 64-bit code"),
         bfd_archive_filename (ibfd));
       ok = FALSE;
     }
-
-  /* Compare the ISA's.  */
-  if ((new_flags & (EF_MIPS_ARCH | EF_MIPS_MACH))
-      != (old_flags & (EF_MIPS_ARCH | EF_MIPS_MACH)))
+  else if (!mips_mach_extends_p (bfd_get_mach (ibfd), bfd_get_mach (obfd)))
     {
-      int new_mach = new_flags & EF_MIPS_MACH;
-      int old_mach = old_flags & EF_MIPS_MACH;
-      int new_isa = elf_mips_isa (new_flags);
-      int old_isa = elf_mips_isa (old_flags);
-
-      /* If either has no machine specified, just compare the general isa's.
-        Some combinations of machines are ok, if the isa's match.  */
-      if (new_mach == old_mach
-         || _bfd_mips_elf_mach_extends_p (new_mach, old_mach)
-         || _bfd_mips_elf_mach_extends_p (old_mach, new_mach))
+      /* OBFD's ISA isn't the same as, or an extension of, IBFD's.  */
+      if (mips_mach_extends_p (bfd_get_mach (obfd), bfd_get_mach (ibfd)))
        {
-         /* Don't warn about mixing code using 32-bit ISAs, or mixing code
-            using 64-bit ISAs.  They will normally use the same data sizes
-            and calling conventions.  */
-
-         if ((  (new_isa == 1 || new_isa == 2 || new_isa == 32)
-              ^ (old_isa == 1 || old_isa == 2 || old_isa == 32)) != 0)
-           {
-             (*_bfd_error_handler)
-              (_("%s: ISA mismatch (-mips%d) with previous modules (-mips%d)"),
-               bfd_archive_filename (ibfd), new_isa, old_isa);
-             ok = FALSE;
-           }
-         else
-           {
-             /* Do we need to update the mach field?  */
-             if (_bfd_mips_elf_mach_extends_p (old_mach, new_mach))
-               {
-                 elf_elfheader (obfd)->e_flags &= ~EF_MIPS_MACH;
-                 elf_elfheader (obfd)->e_flags |= new_mach;
-               }
-
-             /* Do we need to update the ISA field?  */
-             if (new_isa > old_isa)
-               {
-                 elf_elfheader (obfd)->e_flags &= ~EF_MIPS_ARCH;
-                 elf_elfheader (obfd)->e_flags
-                   |= new_flags & EF_MIPS_ARCH;
-               }
-           }
+         /* Copy the architecture info from IBFD to OBFD.  Also copy
+            the 32-bit flag (if set) so that we continue to recognise
+            OBFD as a 32-bit binary.  */
+         bfd_set_arch_info (obfd, bfd_get_arch_info (ibfd));
+         elf_elfheader (obfd)->e_flags &= ~(EF_MIPS_ARCH | EF_MIPS_MACH);
+         elf_elfheader (obfd)->e_flags
+           |= new_flags & (EF_MIPS_ARCH | EF_MIPS_MACH | EF_MIPS_32BITMODE);
+
+         /* Copy across the ABI flags if OBFD doesn't use them
+            and if that was what caused us to treat IBFD as 32-bit.  */
+         if ((old_flags & EF_MIPS_ABI) == 0
+             && mips_32bit_flags_p (new_flags)
+             && !mips_32bit_flags_p (new_flags & ~EF_MIPS_ABI))
+           elf_elfheader (obfd)->e_flags |= new_flags & EF_MIPS_ABI;
        }
       else
        {
+         /* The ISAs aren't compatible.  */
          (*_bfd_error_handler)
-           (_("%s: ISA mismatch (%d) with previous modules (%d)"),
+           (_("%s: linking %s module with previous %s modules"),
             bfd_archive_filename (ibfd),
-            _bfd_elf_mips_mach (new_flags),
-            _bfd_elf_mips_mach (old_flags));
+            bfd_printable_name (ibfd),
+            bfd_printable_name (obfd));
          ok = FALSE;
        }
-
-      new_flags &= ~(EF_MIPS_ARCH | EF_MIPS_MACH);
-      old_flags &= ~(EF_MIPS_ARCH | EF_MIPS_MACH);
     }
 
-  /* Compare ABI's.  The 64-bit ABI does not use EF_MIPS_ABI.  But, it
+  new_flags &= ~(EF_MIPS_ARCH | EF_MIPS_MACH | EF_MIPS_32BITMODE);
+  old_flags &= ~(EF_MIPS_ARCH | EF_MIPS_MACH | EF_MIPS_32BITMODE);
+
+  /* Compare ABIs.  The 64-bit ABI does not use EF_MIPS_ABI.  But, it
      does set EI_CLASS differently from any 32-bit ABI.  */
   if ((new_flags & EF_MIPS_ABI) != (old_flags & EF_MIPS_ABI)
       || (elf_elfheader (ibfd)->e_ident[EI_CLASS]
@@ -8005,6 +9409,8 @@ _bfd_mips_elf_print_private_bfd_data (abfd, ptr)
     fprintf (file, _(" [mips32]"));
   else if ((elf_elfheader (abfd)->e_flags & EF_MIPS_ARCH) == E_MIPS_ARCH_64)
     fprintf (file, _(" [mips64]"));
+  else if ((elf_elfheader (abfd)->e_flags & EF_MIPS_ARCH) == E_MIPS_ARCH_32R2)
+    fprintf (file, _(" [mips32r2]"));
   else
     fprintf (file, _(" [unknown ISA]"));